diff --git a/presets/c64/common.h b/presets/c64/common.h index a0a63e17..663ebfe8 100644 --- a/presets/c64/common.h +++ b/presets/c64/common.h @@ -24,6 +24,37 @@ typedef enum { false, true } bool; // boolean ///// MACROS ///// +// VIC Control Register 1 Flags +#define VIC_CTRL1_RST8 0x80 // Bit 8 of RASTER (read) or raster line interrupt set (write) +#define VIC_CTRL1_ECM 0x40 // Extended Color Mode +#define VIC_CTRL1_BMM 0x20 // Bitmap Mode +#define VIC_CTRL1_DEN 0x10 // Display Enable +#define VIC_CTRL1_RSEL 0x08 // Row Select (25 or 24 rows) +#define VIC_CTRL1_YSCROLL_MASK 0x07 // Vertical Fine Scrolling + +// VIC Control Register 2 Flags +#define VIC_CTRL2_RES 0x20 // Chip reset +#define VIC_CTRL2_MCM 0x10 // Multicolor Mode Enable +#define VIC_CTRL2_CSEL 0x08 // Column Select (40 or 38 columns) +#define VIC_CTRL2_XSCROLL_MASK 0x07 // Horizontal Fine Scrolling + +// VIC Memory Control Register Flags +#define VIC_ADDR_VM_MASK 0xf0 // Video Matrix Base Address Mask (character data) +#define VIC_ADDR_CB_MASK 0x0e // Character Bank Base Address Mask (screen memory) + +// VIC Interrupt Register Flags +#define VIC_IRR_IRQ 0x80 // Interrupt Request +#define VIC_IRR_ILP 0x08 // Light Pen Interrupt +#define VIC_IRR_IMMC 0x04 // Sprite-Sprite Collision Interrupt +#define VIC_IRR_IMBC 0x02 // Sprite-Background Collision Interrupt +#define VIC_IRR_IRST 0x01 // Raster Line Interrupt + +// VIC Interrupt Mask Register Flags +#define VIC_IMR_ELP 0x08 // Enable Light Pen Interrupt +#define VIC_IMR_EMMC 0x04 // Enable Sprite-Sprite Collision Interrupt +#define VIC_IMR_EMBC 0x02 // Enable Sprite-Background Collision Interrupt +#define VIC_IMR_ERST 0x01 // Enable Raster Interrupt + // lookup screen address macro #define SCRNADR(base,col,row) ((base)+(col)+(row)*40) @@ -77,6 +108,16 @@ char* get_vic_bank_start(); // get current screen memory address char* get_screen_memory(); +// read joystick fast +#define READ_STICK(index) ~PEEK(0xdc01-(index)) + +#define STICK_UP(joy) ((joy & 0x1) != 0) +#define STICK_DOWN(joy) ((joy & 0x2) != 0) +#define STICK_LEFT(joy) ((joy & 0x4) != 0) +#define STICK_RIGHT(joy) ((joy & 0x8) != 0) +#define STICK_BUTTON(joy) ((joy & 0x10) != 0) +#define STICK_MOVED(joy) ((joy & 0x1f) != 0) + #ifdef __CC65__ // return key in buffer, or 0 if none (BIOS call) char __fastcall__ poll_keyboard(); diff --git a/presets/c64/plasma.c b/presets/c64/plasma.c new file mode 100644 index 00000000..f48d6dc7 --- /dev/null +++ b/presets/c64/plasma.c @@ -0,0 +1,300 @@ +/*****************************************************************************\ +** plasma test program for cc65. ** +** ** +** (w)2001 by groepaz ** +** ** +** Cleanup and porting by Ullrich von Bassewitz. ** +** ** +\*****************************************************************************/ + + + +#include +#include +#include +#include + + + +#if defined(__C64__) || defined(__C128__) +# define SCREEN1 0xE000 +# define SCREEN2 0xE400 +# define CHARSET 0xE800 +# define outb(addr,val) (*(addr)) = (val) +# define inb(addr) (*(addr)) +#elif defined(__CBM510__) +# define SCREEN1 0xF000 +# define SCREEN2 0xF400 +# define CHARSET 0xE000 +# define outb(addr,val) pokebsys ((unsigned)(addr), val) +# define inb(addr) peekbsys ((unsigned)(addr)) +#elif defined(__PLUS4__) +# define SCREEN1 0x6400 +# define SCREEN2 0x6C00 +# define CHARSET 0x7000 +# define outb(addr,val) (*(addr)) = (val) +# define inb(addr) (*(addr)) +#endif + + + +/* Values for the VIC address register to switch between the two pages */ +#if defined(__PLUS4__) +#define PAGE1 ((SCREEN1 >> 8) & 0xF8) +#define PAGE2 ((SCREEN2 >> 8) & 0xF8) +#define CHARADR ((CHARSET >> 8) & 0xFC) +#else +#define PAGE1 ((SCREEN1 >> 6) & 0xF0) | ((CHARSET >> 10) & 0x0E) +#define PAGE2 ((SCREEN2 >> 6) & 0xF0) | ((CHARSET >> 10) & 0x0E) +#endif + + + +/* Use static local variables for speed */ +#pragma static-locals (1); + + +static const unsigned char sinustable[0x100] = { + 0x80, 0x7d, 0x7a, 0x77, 0x74, 0x70, 0x6d, 0x6a, + 0x67, 0x64, 0x61, 0x5e, 0x5b, 0x58, 0x55, 0x52, + 0x4f, 0x4d, 0x4a, 0x47, 0x44, 0x41, 0x3f, 0x3c, + 0x39, 0x37, 0x34, 0x32, 0x2f, 0x2d, 0x2b, 0x28, + 0x26, 0x24, 0x22, 0x20, 0x1e, 0x1c, 0x1a, 0x18, + 0x16, 0x15, 0x13, 0x11, 0x10, 0x0f, 0x0d, 0x0c, + 0x0b, 0x0a, 0x08, 0x07, 0x06, 0x06, 0x05, 0x04, + 0x03, 0x03, 0x02, 0x02, 0x02, 0x01, 0x01, 0x01, + 0x01, 0x01, 0x01, 0x01, 0x02, 0x02, 0x02, 0x03, + 0x03, 0x04, 0x05, 0x06, 0x06, 0x07, 0x08, 0x0a, + 0x0b, 0x0c, 0x0d, 0x0f, 0x10, 0x11, 0x13, 0x15, + 0x16, 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, + 0x26, 0x28, 0x2b, 0x2d, 0x2f, 0x32, 0x34, 0x37, + 0x39, 0x3c, 0x3f, 0x41, 0x44, 0x47, 0x4a, 0x4d, + 0x4f, 0x52, 0x55, 0x58, 0x5b, 0x5e, 0x61, 0x64, + 0x67, 0x6a, 0x6d, 0x70, 0x74, 0x77, 0x7a, 0x7d, + 0x80, 0x83, 0x86, 0x89, 0x8c, 0x90, 0x93, 0x96, + 0x99, 0x9c, 0x9f, 0xa2, 0xa5, 0xa8, 0xab, 0xae, + 0xb1, 0xb3, 0xb6, 0xb9, 0xbc, 0xbf, 0xc1, 0xc4, + 0xc7, 0xc9, 0xcc, 0xce, 0xd1, 0xd3, 0xd5, 0xd8, + 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, + 0xea, 0xeb, 0xed, 0xef, 0xf0, 0xf1, 0xf3, 0xf4, + 0xf5, 0xf6, 0xf8, 0xf9, 0xfa, 0xfa, 0xfb, 0xfc, + 0xfd, 0xfd, 0xfe, 0xfe, 0xfe, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xfe, 0xfe, 0xfe, 0xfd, + 0xfd, 0xfc, 0xfb, 0xfa, 0xfa, 0xf9, 0xf8, 0xf6, + 0xf5, 0xf4, 0xf3, 0xf1, 0xf0, 0xef, 0xed, 0xeb, + 0xea, 0xe8, 0xe6, 0xe4, 0xe2, 0xe0, 0xde, 0xdc, + 0xda, 0xd8, 0xd5, 0xd3, 0xd1, 0xce, 0xcc, 0xc9, + 0xc7, 0xc4, 0xc1, 0xbf, 0xbc, 0xb9, 0xb6, 0xb3, + 0xb1, 0xae, 0xab, 0xa8, 0xa5, 0xa2, 0x9f, 0x9c, + 0x99, 0x96, 0x93, 0x90, 0x8c, 0x89, 0x86, 0x83 +}; + + + +static void doplasma (register unsigned char* scrn) +{ + unsigned char xbuf[40]; + unsigned char ybuf[25]; + unsigned char c1a,c1b; + unsigned char c2a,c2b; + unsigned char c1A,c1B; + unsigned char c2A,c2B; + register unsigned char i, ii; + + c1a = c1A; + c1b = c1B; + for (ii = 0; ii < 25; ++ii) { + ybuf[ii] = (sinustable[c1a] + sinustable[c1b]); + c1a += 4; + c1b += 9; + } + c1A += 3; + c1B -= 5; + c2a = c2A; + c2b = c2B; + for (i = 0; i < 40; ++i) { + xbuf[i] = (sinustable[c2a] + sinustable[c2b]); + c2a += 3; + c2b += 7; + } + c2A += 2; + c2B -= 3; + for (ii = 0; ii < 25; ++ii) { + /* Unrolling the following loop will give a speed increase of + ** nearly 100% (~24fps), but it will also increase the code + ** size a lot. + */ + for (i = 0; i < 40; ++i, ++scrn) { + *scrn = (xbuf[i] + ybuf[ii]); + } + } +} + +static void makechar (void) +{ + static const unsigned char bittab[8] = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 + }; + unsigned char i, ii, b, s; + unsigned c; + + gotoxy (0, 1); + for (c = 0; c < 0x100; ++c) { + s = sinustable[c]; + for (i = 0; i < 8; ++i){ + b = 0; + for (ii = 0; ii < 8; ++ii) { + if ((rand() & 0xFFu) > s) { + b |= bittab[ii]; + } + } + ((unsigned char*)CHARSET) [(c*8) + i] = b; + } + if ((c & 0x07) == 0) { + cputc ('.'); + } + } +} + + + +int main (void) +{ + unsigned char border; + unsigned char background; + unsigned char text; + unsigned char v; + clock_t t; + unsigned long f = 0; + unsigned long sec; + unsigned sec10; + unsigned long fps; + unsigned fps10; + + +#if defined(__C64__) + unsigned char block; +#endif +#if defined(__C128__) + unsigned char block; + unsigned char initflag; + unsigned char graphflag; +#endif +#if defined(__PLUS4__) + unsigned int i; + unsigned char v2; +#endif + + clrscr (); + cprintf ("Making charset, mompls"); + makechar(); + + /* Set the border and background colors */ + border = bordercolor (COLOR_BLUE); + background = bgcolor (COLOR_BLUE); + text = textcolor (COLOR_BLACK); + clrscr (); + +#if defined(__C64__) || defined(__C128__) + /* Move the VIC 16K block */ + block = inb (&CIA2.pra); + outb (&CIA2.pra, (block & 0xFC) | ((SCREEN1 >> 14) ^ 0x03)); +#endif +#if defined(__C128__) + /* Save and change some flags, so that kernal/basic interrupt handler will + ** not interfere with our routine. + */ + initflag = *(unsigned char*) 0xA04; + *(unsigned char*) 0xA04 &= 0xFE; + graphflag = *(unsigned char*) 0xD8; + *(unsigned char*) 0xD8 = 0xFF; +#endif + + /* Remember the VIC address register */ +#if defined(__PLUS4__) + v = inb (&TED.char_addr); + v2 = inb (&TED.video_addr); +#else + v = inb (&VIC.addr); +#endif + +#if defined(__PLUS4__) + for (i=0;i<1000;i++) { + ((unsigned char *) (SCREEN1-0x0400))[i] = 0; + ((unsigned char *) (SCREEN2-0x0400))[i] = 0; + } + outb (&TED.char_addr, CHARADR); +#endif + + /* Run the demo until a key was hit */ + t = clock (); + while (!kbhit()) { + /* Build page 1, then make it visible */ + doplasma ((unsigned char*)SCREEN1); +#if defined(__PLUS4__) + outb (&TED.video_addr, PAGE1); +#else + outb (&VIC.addr, PAGE1); +#endif + + /* Build page 2, then make it visible */ + doplasma ((unsigned char*)SCREEN2); +#if defined(__PLUS4__) + outb (&TED.video_addr, PAGE2); +#else + outb (&VIC.addr, PAGE2); +#endif + + /* Count frames */ + f += 2; + } + t = clock() - t; + + /* Switch back the VIC screen */ +#if defined(__PLUS4__) + outb (&TED.video_addr, v2); + outb (&TED.char_addr, v); +#else + outb (&VIC.addr, v); +#endif + +#if defined(__C64__) || defined(__C128__) + /* Move back the VIC 16K block */ + outb (&CIA2.pra, block); +#endif +#if defined(__C128__) + /* Restore the flags */ + *(unsigned char*) 0xA04 = initflag; + *(unsigned char*) 0xD8 = graphflag; +#endif + + /* Fetch the character from the keyboard buffer and discard it */ + (void) cgetc(); + + /* Reset screen colors */ + bordercolor (border); + bgcolor (background); + textcolor (text); + clrscr (); + + /* Calculate stats */ + sec = (t * 10) / CLK_TCK; + sec10 = sec % 10; + sec /= 10; + fps = (f * (CLK_TCK * 10)) / t; + fps10 = fps % 10; + fps /= 10; + + /* Output stats */ + gotoxy (0, 0); cprintf ("time : %lu.%us", sec, sec10); + gotoxy (0, 1); cprintf ("frames: %lu", f); + gotoxy (0, 2); cprintf ("fps : %lu.%u", fps, fps10); + + if (doesclrscrafterexit ()) { + cputsxy (0, 4, "Press any key when done..."); + (void) cgetc (); + } + + /* Done */ + return EXIT_SUCCESS; +} diff --git a/presets/c64/rasterirq.ca65 b/presets/c64/rasterirq.ca65 index 55519b5b..4029d1db 100644 --- a/presets/c64/rasterirq.ca65 +++ b/presets/c64/rasterirq.ca65 @@ -1,4 +1,5 @@ +; use CC65's interrupter (slower) USE_INTERRUPTOR = 0 .segment "DATA" @@ -9,39 +10,41 @@ NextDlist: .word NullDlist-1 .segment "CODE" .global ___dlist_setup +.global ___dlist_done .global DLIST_IRQ_NEXT .global DLIST_IRQ_RESTART + .if USE_INTERRUPTOR .interruptor DLIST_IRQ .endif ___dlist_setup: - SEI ; set interrupt bit, make the CPU ignore interrupt requests + sei ; set interrupt bit, make the CPU ignore interrupt requests sta StartDlist+0 ; save XA as pointer to start of dlist stx StartDlist+1 - LDA #%01111111 ; switch off interrupt signals from CIA-1 - STA $DC0D + lda #%01111111 ; switch off interrupt signals from CIA-1 + sta $DC0D - AND $D011 ; clear most significant bit of VIC's raster register - STA $D011 + and $D011 ; clear most significant bit of VIC's raster register + sta $D011 - LDA $DC0D ; acknowledge pending interrupts from CIA-1 - LDA $DD0D ; acknowledge pending interrupts from CIA-2 + lda $DC0D ; acknowledge pending interrupts from CIA-1 + lda $DD0D ; acknowledge pending interrupts from CIA-2 - LDA #252 ; set rasterline where interrupt shall occur - STA $D012 + lda #252 ; set rasterline where interrupt shall occur + sta $D012 .if !USE_INTERRUPTOR - LDA #DLIST_IRQ - STA $0315 + lda #DLIST_IRQ + sta $0315 .endif - LDA #%00000001 ; enable raster interrupt signals from VIC - STA $D01A + lda #%00000001 ; enable raster interrupt signals from VIC + sta $D01A cli rts @@ -54,26 +57,21 @@ DLIST_CALL: rts DLIST_IRQ_RESTART: - sta $d012 + sta $D012 ; set IRQ raster line lda StartDlist+0 sta NextDlist+0 lda StartDlist+1 sta NextDlist+1 bne DLIST_ACK -DLIST_IRQ_STOP: - lda #0 ; disable raster interrupt signals from VIC - sta $D01A - bne DLIST_ACK - DLIST_IRQ_NEXT: - sta $d012 + sta $D012 pla sta NextDlist+0 pla sta NextDlist+1 DLIST_ACK: - ASL $D019 ; acknowledge the interrupt by clearing the VIC's interrupt flag + asl $D019 ; acknowledge the interrupt by clearing the VIC's interrupt flag .if USE_INTERRUPTOR clc rts @@ -84,9 +82,30 @@ DLIST_ACK: tax pla rti ; return from interrupt -; JMP $EA31 ; jump into KERNAL's standard interrupt service routine to handle keyboard scan, cursor display etc. .endif +___dlist_done: + php + sei ; disable interrupts + lda #$0 ; disable raster interrupt signals from VIC + sta $D01A + lda #$ff + sta $DC0D +.if !USE_INTERRUPTOR + lda #$31 ; set interrupt vectors back to KERNAL + sta $0314 + lda #$ea + sta $0315 +.else + lda #<(NullDlist-1) + sta StartDlist + lda #>(NullDlist-1) + sta StartDlist+1 +.endif + plp + rts + + NullDlist: lda #252 jmp DLIST_IRQ_RESTART diff --git a/presets/c64/rasterirq.h b/presets/c64/rasterirq.h index 073873ce..ee6762fd 100644 --- a/presets/c64/rasterirq.h +++ b/presets/c64/rasterirq.h @@ -4,6 +4,7 @@ // internal function, use macro instead void __dlist_setup(void* ptr); +void __dlist_done(); // initialize display list with function 'func' #define DLIST_SETUP(func) \ @@ -19,5 +20,7 @@ void __dlist_setup(void* ptr); __A__ = line; \ asm ("jmp DLIST_IRQ_RESTART"); +// stop display list +#define DLIST_DONE() __dlist_done(); #endif diff --git a/presets/c64/scrollingmap1.c b/presets/c64/scrollingmap1.c new file mode 100644 index 00000000..c9417409 --- /dev/null +++ b/presets/c64/scrollingmap1.c @@ -0,0 +1,179 @@ + +#include +#include +#include +#include +#include +#include +#include +#include + +//#resource "c64-sid.cfg" +#define CFGFILE c64-sid.cfg + +#include "common.h" +//#link "common.c" + +#include "scrolling.h" +//#link "scrolling.c" + +#include "sprites.h" +//#link "sprites.c" + +//#link "level1.ca65" + +extern const byte charset_data[]; +extern const byte charset_attrib_data[]; +extern const byte chartileset_data[]; +extern const byte chartileset_tag_data[]; +extern const byte* map_row_pointers[]; + +#define MAP_COLS 28 +#define MAP_ROWS 11 + +static void draw_cell(word ofs, byte x, byte y) { + sbyte xx = x + origin_x; + sbyte yy = y + origin_y; + sbyte col = xx >> 2; + sbyte row = yy >> 2; + byte xofs = xx & 3; + byte yofs = yy & 3; + char ch; + char color; + if (col < 0 || col >= MAP_COLS || row < 0 || row >= MAP_ROWS) { + ch = 0; + color = 0; + } else { + byte tileindex = map_row_pointers[row][col]; + ch = chartileset_data[xofs + yofs*4 + tileindex*16]; + color = charset_attrib_data[ch]; + } + hidbuf[ofs] = ch; + colorbuf[ofs] = color; +} + +void scroll_draw_column(byte col) { + byte y; + word ofs = col; + for (y=0; y>= 4; + dy >>= 4; + if (dx) { + if (dx > 8) dx = 8; + else if (dx < -8) dx = -8; + camerax -= dx; + scroll_horiz(dx); + } + if (dy) { + if (dy > 8) dy = 8; + else if (dy < -8) dy = -8; + cameray -= dy; + scroll_vert(dy); + } +} + +void refresh_world(void) { + byte i; + for (i=0; i<25; i++) { + scroll_draw_row(i); + } +} + +void main(void) { + + clrscr(); + + // setup scrolling library + scroll_setup(); + + // multicolor character mode + VIC.ctrl2 |= 0x10; + VIC.bgcolor0 = 6; + VIC.bgcolor1 = 0; + VIC.bgcolor2 = 1; + + // select character set @ 0x8800 + VIC.addr = 0x12; + memcpy((char*)0x8800, charset_data, 520); + + // setup sprite library and copy sprite to VIC bank + sprite_clear(); + sprite_set_shapes(SPRITE1, 255, 1); + sprshad.spr_color[0] = 13; + + // install the joystick driver + joy_install (joy_static_stddrv); + + // repaint screen memory w/ the map + refresh_world(); + + // infinite loop + while (1) { + static char speed; + static char joy; + static bool slowframe = false; + // get joystick bits + joy = joy_read(0); + // speed up scrolling while button pressed + speed = JOY_BTN_1(joy) ? 3 : 1; + // if we copied screen memory last frame, + // double speed of player for this frame + if (slowframe) speed *= 2; + // move sprite based on arrow keys + if (JOY_LEFT(joy)) playerx -= speed; + if (JOY_RIGHT(joy)) playerx += speed; + if (JOY_UP(joy)) playery -= speed; + if (JOY_DOWN(joy)) playery += speed; + // move the camera? + camera_follow(joy); + slowframe = swap_needed; + // animate sprite in shadow sprite ram + update_player(); + // wait for vblank + wait_vblank(); + // then update sprite registers + sprite_update(visbuf); + // update scroll registers + // and swap screens if we must + scroll_update(); + } +} diff --git a/presets/c64/side_scroller.c b/presets/c64/side_scroller.c index a4e6ba4d..c9661655 100644 --- a/presets/c64/side_scroller.c +++ b/presets/c64/side_scroller.c @@ -124,6 +124,7 @@ void update_scoreboard() { void add_score(int delta) { score = bcd_add(score, delta); + update_scoreboard(); } // clear scoreboard and draw initial strings @@ -242,13 +243,13 @@ void scroll_one_pixel_left() { } } -void detect_player_collision(byte bgcoll, byte sprcoll) { +void detect_player_collision(byte bg_coll, byte spr_coll) { // did we hit a powerup? (#0 and #1) - bool hit_powerup = (sprcoll & 0b011) == 0b011; + bool hit_powerup = (spr_coll & 0b011) == 0b011; // did player and obstacle sprite (#0 and #2) collide? - bool hit_obstacle = (sprcoll & 0b101) == 0b101; + bool hit_obstacle = (spr_coll & 0b101) == 0b101; // did player (#0) collide with background? - hit_obstacle |= (bgcoll & 0b001) != 0; + hit_obstacle |= (bg_coll & 0b001) != 0; // did we hit anything bad? if (hit_obstacle) { // make player fall downward and backward @@ -257,7 +258,6 @@ void detect_player_collision(byte bgcoll, byte sprcoll) { sprshad.spr_color[PLAYER_INDEX] = COLOR_LIGHTRED; SID_PLAY_TONE(500); if (score != 0) { add_score(0x9999); } // BCD -1 - update_scoreboard(); } else { sprshad.spr_color[PLAYER_INDEX] = COLOR_GREEN; } @@ -266,7 +266,6 @@ void detect_player_collision(byte bgcoll, byte sprcoll) { sprshad.spr_color[POWERUP_INDEX] += 1; // cycle colors SID_PLAY_TONE(8000); add_score(1); - update_scoreboard(); } } @@ -312,15 +311,15 @@ void main() { // game loop, repeat forever while (1) { // saved collision flags - byte sprcoll, bgcoll; + byte spr_coll, bg_coll; // wait for end of frame waitvsync(); //--- START TIME CRITICAL SECTION // grab and reset collision flags - sprcoll = VIC.spr_coll; - bgcoll = VIC.spr_bg_coll; + spr_coll = VIC.spr_coll; + bg_coll = VIC.spr_bg_coll; // update sprite registers from sprite shadow buffer sprite_update(DEFAULT_SCREEN); @@ -330,7 +329,7 @@ void main() { //--- END TIME CRITICAL SECTION // use collision flags to see if player collided - detect_player_collision(bgcoll, sprcoll); + detect_player_collision(bg_coll, spr_coll); // get joystick bits and move player move_player(joy_read(0)); diff --git a/presets/c64/sprite_stretch.c b/presets/c64/sprite_stretch.c new file mode 100644 index 00000000..c0989452 --- /dev/null +++ b/presets/c64/sprite_stretch.c @@ -0,0 +1,76 @@ + +//#link "common.c" +#include "common.h" + +//#link "rasterirq.ca65" +#include "rasterirq.h" + +//#link "sprites.c" +#include "sprites.h" + +#include +#include + +/*{w:24,h:21,bpp:1,brev:1}*/ +const char spriteshape[3*21] = { + 0x00,0x7F,0x00,0x01,0xFF,0xC0,0x03,0xFF,0xE0, + 0x03,0xE7,0xE0,0x07,0xD9,0xF0,0x07,0xDF,0xF0, + 0x07,0xD9,0xF0,0x03,0xE7,0xE0,0x03,0xFF,0xE0, + 0x03,0xFF,0xE0,0x02,0xFF,0xA0,0x01,0x7F,0x40, + 0x01,0x3E,0x40,0x00,0x9C,0x80,0x00,0x9C,0x80, + 0x00,0x49,0x00,0x00,0x49,0x00,0x00,0x3E,0x00, + 0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00 +}; + +void sprite_stretch() { + // get current raster line + asm("lda $d012"); + // sprite Y expand bits = 255 + asm("ldx #$ff"); + asm("stx $d017"); + // wait for next raster line + asm("@loop:"); + asm("cmp $d012"); + asm("beq @loop"); + // sprite Y expand bits = 0 + asm("inx"); + asm("stx $d017"); +} + +void dlist_example(void) { + + // stretch for the next 40 lines + while (VIC.rasterline != 160) { + sprite_stretch(); + } + + VIC.spr0_y+=3; + VIC.spr7_y-=2; + + DLIST_RESTART(8*15); +} + +void main(void) { + byte i; + + clrscr(); + VIC.bordercolor = 0; + + sprite_clear(); + sprite_set_shapes(spriteshape, 192, 1); + + sprshad.spr_exp_x = 0xff; + for (i=0; i<8; i++) { + sprshad.spr_color[i] = i|8; + sprite_draw(i, i*38+24, 120-i, 192); + } + sprite_update(DEFAULT_SCREEN); + + DLIST_SETUP(dlist_example); + + while (1) { + if (STICK_MOVED(READ_STICK(0))) break; + } + + DLIST_DONE(); +} diff --git a/presets/c64/test_border_sprites.c b/presets/c64/test_border_sprites.c new file mode 100644 index 00000000..59148771 --- /dev/null +++ b/presets/c64/test_border_sprites.c @@ -0,0 +1,92 @@ + +//#link "common.c" +#include "common.h" + +//#link "rasterirq.ca65" +#include "rasterirq.h" + +//#link "sprites.c" +#include "sprites.h" + +#include +#include + +/*{w:24,h:21,bpp:1,brev:1}*/ +const char spriteshape[3*21] = { + 0x00,0x7F,0x00,0x01,0xFF,0xC0,0x03,0xFF,0xE0, + 0x03,0xE7,0xE0,0x07,0xD9,0xF0,0x07,0xDF,0xF0, + 0x07,0xD9,0xF0,0x03,0xE7,0xE0,0x03,0xFF,0xE0, + 0x03,0xFF,0xE0,0x02,0xFF,0xA0,0x01,0x7F,0x40, + 0x01,0x3E,0x40,0x00,0x9C,0x80,0x00,0x9C,0x80, + 0x00,0x49,0x00,0x00,0x49,0x00,0x00,0x3E,0x00, + 0x00,0x3E,0x00,0x00,0x3E,0x00,0x00,0x1C,0x00 +}; + +byte scroll_x = 0; +byte scroll_y = 0; + +void dlist_example(void) { + VIC.ctrl1 = VIC_CTRL1_DEN | VIC_CTRL1_RSEL; + VIC.bordercolor = 5; + + // Flexible line distance (FLD) + // this adds a gap of 1-6 scanlines + DLIST_NEXT(150); + VIC.ctrl1 = (scroll_y & 7) | 0x18; + VIC.bordercolor = 2; + + // this opens up the vertical borders + // it must be done on the last row (247-249) + DLIST_NEXT(249); + VIC.ctrl1 = VIC_CTRL1_DEN; + + // move sprites and restart the display list + scroll_x++; + scroll_y++; + VIC.spr0_y++; + VIC.spr7_y--; + VIC.bordercolor = 4; + DLIST_RESTART(30); +} + + +void SieveOfEratosthenes() { + const int n = 1023; + int primes[1024]; + int i,p; + memset(primes, 1, sizeof(primes)); + + for (p = 2; p*p <= n; p++) { + if (primes[p]) { + for (i = p*p; i <= n; i += p) + primes[i] = 0; + } + } + + for (p = 2; p <= n; p++) + if (primes[p]) + printf("%d ", p); +} + +void main(void) { + byte i; + + clrscr(); + + sprite_clear(); + sprite_set_shapes(spriteshape, 192, 1); + + sprshad.spr_exp_x = 0xff; + for (i=0; i<8; i++) { + sprshad.spr_color[i] = i+3; + sprite_draw(i, i*38+24, 248, 192); + } + sprite_update(DEFAULT_SCREEN); + + DLIST_SETUP(dlist_example); + + // do something complicated while IRQ runs... + while (1) { + SieveOfEratosthenes(); + } +} diff --git a/presets/c64/test_display_list.c b/presets/c64/test_display_list.c new file mode 100644 index 00000000..3f582fe6 --- /dev/null +++ b/presets/c64/test_display_list.c @@ -0,0 +1,143 @@ + +#include "common.h" +//#link "common.c" + +#include "rasterirq.h" +//#link "rasterirq.ca65" + +#include "bcd.h" +//#link "bcd.c" + +///// DEFINES + +#define GAME_BASE 0x400 // scrolling screen ram +#define SCORE_BASE 0x2c00 // scoreboard screen ram + +#define SCROLL_TOP 8 // scroll top row +#define SCROLL_ROWS 14 // scroll # of rows +#define GROUND_ROW 7 // ground row (+ top row) + +///// VARIABLES + +word scroll_x = 0; // current scroll X position +word score = 0; // current player score + +///// FUNCTIONS + +// display list used by rasterirq.h +// draws scoreboard and sets scroll register +void display_list() { + // set x scroll register to scroll value + SET_SCROLL_X(scroll_x); + // set background color + VIC.bgcolor[0] = COLOR_CYAN; + // next interrupt is two rows from bottom + DLIST_NEXT(250-16); + + // set background color + VIC.bgcolor[0] = COLOR_BLUE; + // screen memory = 0x2800 + SET_VIC_SCREEN(SCORE_BASE); + // clear x scroll register + SET_SCROLL_X(0); + // next interrupt is bottom of frame + DLIST_NEXT(250); + + // reset screen to 0x400 + SET_VIC_SCREEN(0x400); + // next interrupt is above top of next frame + DLIST_RESTART(40); +} + +void update_scoreboard() { + draw_bcd_word(SCRNADR(SCORE_BASE,7,24), score); +} + +void add_score(int delta) { + score = bcd_add(score, delta); +} + +// clear scoreboard and draw initial strings +void init_scoreboard() { + memset((void*)SCORE_BASE, ' ', 1024); + memcpy((void*)SCRNADR(SCORE_BASE,1,24), "SCORE:", 6); + update_scoreboard(); +} + +byte get_char_for_row(byte row) { + // ground? + if (row >= GROUND_ROW) { return 253; } + // obstacle? + if (row >= GROUND_ROW-3) { + // only show obstacle for certain values of scroll_x + if ((scroll_x & 0b1110000) == 0) { return 247; } + } + // default is the sky (empty space) + return 32; +} + +void draw_right_column() { + // get the top-right corner address of scroll area + word addr = SCRNADR(GAME_BASE, 39, SCROLL_TOP); + byte row; + // draw one character per row + for (row=0; row #include @@ -71,13 +70,13 @@ int main (void) rx -= 24; if (rx >= 0 && rx < 366) { // Set MSB of x coordinate for sprite if x position > 255 - if (x >= 256) { + if (rx >= 256) { msb |= LUT[t]; // look up 1 << t } - VIC.spr_pos[t].x = x; + VIC.spr_pos[t].x = rx; // Y position is an indirect Sinus function of X, using array // index for retrieving the Y value - VIC.spr_pos[t].y = yValues[x & 63] + 40; + VIC.spr_pos[t].y = yValues[rx & 63] + 40; } else { VIC.spr_pos[t].x = 0; } diff --git a/presets/vcs/skeleton.remote:llvm-mos b/presets/vcs/skeleton.remote:llvm-mos new file mode 100644 index 00000000..3e5c8f64 --- /dev/null +++ b/presets/vcs/skeleton.remote:llvm-mos @@ -0,0 +1,67 @@ + +#include +#include +#include +#include + +#ifdef __ATARI2600_MAPPER_3E__ +MAPPER_CART_ROM_KB(6); // 6K ROM +#endif + +#ifdef MAPPER_BANKED_ROM +#define ROM_BANK(index) __attribute__((noinline, section(".rom"#index))) +#else +#define ROM_BANK(index) +#endif + +#define KERNEL_BANK 1 + +ROM_BANK(KERNEL_BANK) void my_preframe(void) { +} + +ROM_BANK(KERNEL_BANK) void my_doframe(void) { + int i; + // Set player sprite color + TIA.colup0 = COLOR_CONV(0xfe); + // Draw each scanline + for (i=0; i<192; i++) { + TIA.wsync = 0; // sync to scanline + TIA.colubk = i; // set background color + TIA.pf1 = i; // set playfield + TIA.grp0 = i; // set sprite bitmap + } + TIA.grp0 = 0; // clear sprite + TIA.colubk = 0; // clear background +} + +ROM_BANK(KERNEL_BANK) void my_postframe(void) { + // additional post-frame processing goes here +} + +// Display kernel loop +ROM_BANK(KERNEL_BANK) void do_kernel_loop() { + // loop until reset released + while (SW_RESET()) { } + // loop forever + while (1) { + kernel_1(); + my_preframe(); + kernel_2(); + my_doframe(); + kernel_3(); + my_postframe(); + kernel_4(); + } +} + +int main() { + + // test banked rom call, if available +#ifdef MAPPER_BANKED_ROM + banked_call_rom(KERNEL_BANK, do_kernel_loop); +#else + do_kernel_loop(); +#endif + + return 0; +} diff --git a/src/common/analysis.ts b/src/common/analysis.ts index cd0d46ab..51108f8e 100644 --- a/src/common/analysis.ts +++ b/src/common/analysis.ts @@ -1,30 +1,30 @@ import { hex, byte2signed } from "./util"; -import { Platform } from "./baseplatform"; +import { OpcodeMetadata, Platform } from "./baseplatform"; const debug = false; export interface CodeAnalyzer { - showLoopTimingForPC(pc:number); - pc2clockrange : {[key:number]:ClockRange}; - MAX_CLOCKS : number; + showLoopTimingForPC(pc: number); + pc2clockrange: { [key: number]: ClockRange }; + MAX_CLOCKS: number; } /// VCS TIMING ANALYSIS // [taken, not taken] const BRANCH_CONSTRAINTS = [ - [{N:0},{N:1}], - [{N:1},{N:0}], - [{V:0},{V:1}], - [{V:1},{V:0}], - [{C:0},{C:1}], - [{C:1},{C:0}], - [{Z:0},{Z:1}], - [{Z:1},{Z:0}] + [{ N: 0 }, { N: 1 }], + [{ N: 1 }, { N: 0 }], + [{ V: 0 }, { V: 1 }], + [{ V: 1 }, { V: 0 }], + [{ C: 0 }, { C: 1 }], + [{ C: 1 }, { C: 0 }], + [{ Z: 0 }, { Z: 1 }], + [{ Z: 1 }, { Z: 0 }] ]; -function constraintEquals(a,b) { +function constraintEquals(a, b) { if (a == null || b == null) return null; for (var n in a) { @@ -44,15 +44,15 @@ interface ClockRange { } abstract class CodeAnalyzer6502 implements CodeAnalyzer { - pc2clockrange : {[key:number]:ClockRange} = {}; - jsrresult : {[key:number]:ClockRange} = {}; - START_CLOCKS : number; - MAX_CLOCKS : number; - WRAP_CLOCKS : boolean; - platform : Platform; - MAX_CYCLES : number = 2000; - - constructor(platform : Platform) { + pc2clockrange: { [key: number]: ClockRange } = {}; + jsrresult: { [key: number]: ClockRange } = {}; + START_CLOCKS: number; + MAX_CLOCKS: number; + WRAP_CLOCKS: boolean; + platform: Platform; + MAX_CYCLES: number = 2000; + + constructor(platform: Platform) { this.platform = platform; } @@ -62,12 +62,12 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer { return meta; // minCycles, maxCycles } - traceInstructions(pc:number, minclocks:number, maxclocks:number, subaddr:number, constraints) { + traceInstructions(pc: number, minclocks: number, maxclocks: number, subaddr: number, constraints) { if (debug) console.log("trace", hex(pc), minclocks, maxclocks); if (!constraints) constraints = {}; var modified = true; var abort = false; - for (let i=0; modified && !abort; i++) { + for (let i = 0; modified && !abort; i++) { if (i >= this.MAX_CYCLES) { console.log("too many cycles @", hex(pc), "routine", hex(subaddr)); break; @@ -77,10 +77,10 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer { // wrap clocks minclocks = minclocks % this.MAX_CLOCKS; maxclocks = maxclocks % this.MAX_CLOCKS; - if (maxclocks == minclocks-1) { + if (maxclocks == minclocks - 1) { if (debug) console.log("0-75", hex(pc), minclocks, maxclocks); minclocks = 0; - maxclocks = this.MAX_CLOCKS-1; + maxclocks = this.MAX_CLOCKS - 1; } } else { // truncate clocks @@ -88,13 +88,13 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer { maxclocks = Math.min(this.MAX_CLOCKS, maxclocks); } let meta = this.getClockCountsAtPC(pc); - let lob = this.platform.readAddress(pc+1); - let hib = this.platform.readAddress(pc+2); + let lob = this.platform.readAddress(pc + 1); + let hib = this.platform.readAddress(pc + 2); let addr = lob + (hib << 8); let pc0 = pc; let pcrange = this.pc2clockrange[pc0]; if (pcrange == null) { - this.pc2clockrange[pc0] = pcrange = {minclocks:minclocks, maxclocks:maxclocks}; + this.pc2clockrange[pc0] = pcrange = { minclocks: minclocks, maxclocks: maxclocks }; if (debug) console.log("new", hex(pc), hex(pc0), hex(subaddr), minclocks, maxclocks); modified = true; } @@ -103,7 +103,7 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer { if (this.WRAP_CLOCKS && (minclocks <= maxclocks) != (pcrange.minclocks <= pcrange.maxclocks)) { if (debug) console.log("wrap", hex(pc), hex(pc0), hex(subaddr), minclocks, maxclocks, pcrange); pcrange.minclocks = minclocks = 0; - pcrange.maxclocks = maxclocks = this.MAX_CLOCKS-1; + pcrange.maxclocks = maxclocks = this.MAX_CLOCKS - 1; modified = true; } if (minclocks < pcrange.minclocks) { @@ -124,106 +124,88 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer { pc += meta.insnlength; var oldconstraints = constraints; constraints = null; - // TODO: if jump to zero-page, maybe assume RTS? - switch (meta.opcode) { - case 0x19: case 0x1d: - case 0x39: case 0x3d: - case 0x59: case 0x5d: - case 0x79: case 0x7d: - case 0xb9: case 0xbb: - case 0xbc: case 0xbd: case 0xbe: case 0xbf: - case 0xd9: case 0xdd: - case 0xf9: case 0xfd: - if (lob == 0) meta.maxCycles -= 1; // no page boundary crossed - break; - // TODO: only VCS - case 0x85: - if (lob == 0x2) { // STA WSYNC - minclocks = maxclocks = 0; - meta.minCycles = meta.maxCycles = 0; - } - break; - // TODO: only NES (sprite 0 poll) - case 0x2c: - if (lob == 0x02 && hib == 0x20) { // BIT $2002 - minclocks = 0; - maxclocks = 4; // uncertainty b/c of assumed branch poll - meta.minCycles = meta.maxCycles = 0; - } - break; - // TODO: only Apple2 (vapor lock) - /* - case 0xad: - if (lob == 0x61 && hib == 0xc0) { // LDA $C061 - minclocks = 0; - maxclocks = 4; // uncertainty? - meta.minCycles = meta.maxCycles = 0; - } - break; - */ - case 0x20: // JSR - // TODO: handle bare RTS case - minclocks += meta.minCycles; - maxclocks += meta.maxCycles; - this.traceInstructions(addr, minclocks, maxclocks, addr, constraints); - var result = this.jsrresult[addr]; - if (result) { - minclocks = result.minclocks; - maxclocks = result.maxclocks; - } else { - console.log("No JSR result!", hex(pc), hex(addr)); - minclocks = maxclocks; - //return; - } - break; - case 0x4c: // JMP - pc = addr; // TODO: make sure in ROM space - break; - case 0x40: // RTI - abort = true; - break; - case 0x60: // RTS - if (subaddr) { // TODO: 0 doesn't work - // TODO: combine with previous result - var result = this.jsrresult[subaddr]; - if (!result) { - result = {minclocks:minclocks, maxclocks:maxclocks}; + let syncMaxCycles = this.getMaxCyclesForSync(meta, lob, hib); + if (typeof syncMaxCycles === 'number') { + minclocks = 0; + maxclocks = syncMaxCycles; + meta.minCycles = meta.maxCycles = 0; + } else { + // TODO: if jump to zero-page, maybe assume RTS? + switch (meta.opcode) { + case 0x19: case 0x1d: + case 0x39: case 0x3d: + case 0x59: case 0x5d: + case 0x79: case 0x7d: + case 0xb9: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xd9: case 0xdd: + case 0xf9: case 0xfd: + if (lob == 0) meta.maxCycles -= 1; // no page boundary crossed + break; + case 0x20: // JSR + // TODO: handle bare RTS case + minclocks += meta.minCycles; + maxclocks += meta.maxCycles; + this.traceInstructions(addr, minclocks, maxclocks, addr, constraints); + var result = this.jsrresult[addr]; + if (result) { + minclocks = result.minclocks; + maxclocks = result.maxclocks; } else { - result = { - minclocks:Math.min(minclocks,result.minclocks), - maxclocks:Math.max(maxclocks,result.maxclocks) - } + console.log("No JSR result!", hex(pc), hex(addr)); + minclocks = maxclocks; + //return; } - this.jsrresult[subaddr] = result; - console.log("RTS", hex(pc), hex(subaddr), this.jsrresult[subaddr]); - } - return; - case 0x10: case 0x30: // branch - case 0x50: case 0x70: - case 0x90: case 0xB0: - case 0xD0: case 0xF0: - var newpc = pc + byte2signed(lob); - var crosspage = (pc>>8) != (newpc>>8); - if (!crosspage) meta.maxCycles--; - // TODO: other instructions might modify flags too - var cons = BRANCH_CONSTRAINTS[Math.floor((meta.opcode-0x10)/0x20)]; - var cons0 = constraintEquals(oldconstraints, cons[0]); - var cons1 = constraintEquals(oldconstraints, cons[1]); - // recursively trace the taken branch - if (true || cons0 !== false) { // TODO? - this.traceInstructions(newpc, minclocks+meta.maxCycles, maxclocks+meta.maxCycles, subaddr, cons[0]); - } - // abort if we will always take the branch - if (cons1 === false) { - console.log("branch always taken", hex(pc), oldconstraints, cons[1]); + break; + case 0x4c: // JMP + pc = addr; // TODO: make sure in ROM space + break; + case 0x40: // RTI abort = true; - } - constraints = cons[1]; // not taken - meta.maxCycles = meta.minCycles; // branch not taken, no extra clock(s) - break; - case 0x6c: - console.log("Instruction not supported!", hex(pc), hex(meta.opcode), meta); // TODO - return; + break; + case 0x60: // RTS + if (subaddr) { // TODO: 0 doesn't work + // TODO: combine with previous result + var result = this.jsrresult[subaddr]; + if (!result) { + result = { minclocks: minclocks, maxclocks: maxclocks }; + } else { + result = { + minclocks: Math.min(minclocks, result.minclocks), + maxclocks: Math.max(maxclocks, result.maxclocks) + } + } + this.jsrresult[subaddr] = result; + console.log("RTS", hex(pc), hex(subaddr), this.jsrresult[subaddr]); + } + return; + case 0x10: case 0x30: // branch + case 0x50: case 0x70: + case 0x90: case 0xB0: + case 0xD0: case 0xF0: + var newpc = pc + byte2signed(lob); + var crosspage = (pc >> 8) != (newpc >> 8); + if (!crosspage) meta.maxCycles--; + // TODO: other instructions might modify flags too + var cons = BRANCH_CONSTRAINTS[Math.floor((meta.opcode - 0x10) / 0x20)]; + var cons0 = constraintEquals(oldconstraints, cons[0]); + var cons1 = constraintEquals(oldconstraints, cons[1]); + // recursively trace the taken branch + if (true || cons0 !== false) { // TODO? + this.traceInstructions(newpc, minclocks + meta.maxCycles, maxclocks + meta.maxCycles, subaddr, cons[0]); + } + // abort if we will always take the branch + if (cons1 === false) { + console.log("branch always taken", hex(pc), oldconstraints, cons[1]); + abort = true; + } + constraints = cons[1]; // not taken + meta.maxCycles = meta.minCycles; // branch not taken, no extra clock(s) + break; + case 0x6c: + console.log("Instruction not supported!", hex(pc), hex(meta.opcode), meta); // TODO + return; + } } // add min/max instruction time to min/max clocks bound if (debug) console.log("add", hex(pc), meta.minCycles, meta.maxCycles); @@ -232,41 +214,65 @@ abstract class CodeAnalyzer6502 implements CodeAnalyzer { } } - showLoopTimingForPC(pc:number) { + showLoopTimingForPC(pc: number) { this.pc2clockrange = {}; this.jsrresult = {}; // recurse through all traces this.traceInstructions(pc | this.platform.getOriginPC(), this.START_CLOCKS, this.MAX_CLOCKS, 0, {}); } + + getMaxCyclesForSync(meta: OpcodeMetadata, lob: number, hib: number) { + } } // 76 cycles export class CodeAnalyzer_vcs extends CodeAnalyzer6502 { - constructor(platform : Platform) { + constructor(platform: Platform) { super(platform); this.MAX_CLOCKS = 76; // 1 scanline this.START_CLOCKS = 0; // TODO? this.WRAP_CLOCKS = true; } + getMaxCyclesForSync(meta: OpcodeMetadata, lob: number, hib: number) { + if (meta.opcode == 0x85) { + if (lob == 0x2) { // STA WSYNC + return 0; + } + } + } } // https://wiki.nesdev.com/w/index.php/PPU_rendering#Line-by-line_timing // TODO: sprite 0 hit, CPU stalls export class CodeAnalyzer_nes extends CodeAnalyzer6502 { - constructor(platform : Platform) { + constructor(platform: Platform) { super(platform); this.MAX_CLOCKS = 114; // 341 clocks for 3 scanlines this.START_CLOCKS = 0; this.WRAP_CLOCKS = true; } + getMaxCyclesForSync(meta: OpcodeMetadata, lob: number, hib: number) { + if (meta.opcode == 0x2c) { + if (lob == 0x02 && hib == 0x20) { // BIT $2002 + return 4; // uncertainty b/c of assumed branch poll + } + } + } } export class CodeAnalyzer_apple2 extends CodeAnalyzer6502 { - constructor(platform : Platform) { + constructor(platform: Platform) { super(platform); this.MAX_CLOCKS = 65; this.START_CLOCKS = 0; this.WRAP_CLOCKS = true; } + getMaxCyclesForSync(meta: OpcodeMetadata, lob: number, hib: number) { + if (meta.opcode == 0xad) { + if (lob == 0x61 && hib == 0xc0) { // LDA $C061 + return 4; // uncertainty b/c of assumed branch poll + } + } + } } diff --git a/src/platform/c64.ts b/src/platform/c64.ts index 65847938..0274d245 100644 --- a/src/platform/c64.ts +++ b/src/platform/c64.ts @@ -13,15 +13,17 @@ const C64_PRESETS = [ {id:'joymove.c', name:'Sprite Movement'}, {id:'sprite_collision.c', name:'Sprite Collision'}, {id:'scroll1.c', name:'Scrolling (Single Buffer)'}, + {id:'test_display_list.c', name:'Display List / Raster IRQ'}, + {id:'scrolling_text.c', name:'Big Scrolling Text'}, + {id:'side_scroller.c', name:'Side-Scrolling Game'}, {id:'scroll2.c', name:'Scrolling (Double Buffer)'}, {id:'scroll3.c', name:'Scrolling (Multidirectional)'}, {id:'scroll4.c', name:'Scrolling (Color RAM Buffering)'}, {id:'scroll5.c', name:'Scrolling (Camera Following)'}, - {id:'side_scroller.c', name:'Side-Scrolling Game'}, + {id:'scrollingmap1.c', name:'Scrolling Tile Map'}, {id:'fullscrollgame.c', name:'Full-Scrolling Game'}, {id:'test_multiplex.c', name:'Sprite Retriggering'}, {id:'test_multispritelib.c', name:'Sprite Multiplexing Library'}, - {id:'scrolling_text.c', name:'Big Scrolling Text'}, {id:'mcbitmap.c', name:'Multicolor Bitmap Mode'}, {id:'testlz4.c', name:'LZ4 Bitmap Compression'}, //{id:'mandel.c', name:'Mandelbrot Fractal'}, @@ -29,6 +31,9 @@ const C64_PRESETS = [ //{id:'sidtune.dasm', name:'Tiny SID Tune (ASM)'}, {id:'siddemo.c', name:'SID Player Demo'}, {id:'climber.c', name:'Climber Game'}, + {id:'test_border_sprites.c', name:'Sprites in the Borders'}, + {id:'sprite_stretch.c', name:'Sprite Stretching'}, + {id:'plasma.c', name:'Plasma Demo'}, {id:'hello.wiz', name:'Hello Wiz (Wiz)'}, ]; diff --git a/src/worker/server/buildenv.ts b/src/worker/server/buildenv.ts index 06a33083..e9c5e079 100644 --- a/src/worker/server/buildenv.ts +++ b/src/worker/server/buildenv.ts @@ -18,7 +18,7 @@ const LLVM_MOS_TOOL: ServerBuildTool = { default: { binpath: 'llvm-mos/bin', command: 'mos-clang', - args: ['-Os', '-g', '-o', '$OUTFILE', '$INFILES'], + args: ['-Os', '-g', '-D', '__8BITWORKSHOP__', '-o', '$OUTFILE', '$INFILES'], }, debug: { // TODO binpath: 'llvm-mos/bin',