1
0
mirror of https://github.com/sehugg/8bitworkshop.git synced 2024-06-01 05:41:31 +00:00

astrocade: updated presets, added memory bus contention, palette layout

This commit is contained in:
Steven Hugg 2019-05-26 21:54:37 -04:00
parent 8e19a65968
commit c93ba6fd75
22 changed files with 371 additions and 86 deletions

View File

@ -0,0 +1,95 @@
.module biosasm
.globl _STIMER,_CTIMER,_BIGFONT,_SMLFONT
.area BIOSSTART (ABS)
.org 0x0
BIOSStart:
di ; disable interrupts
ld HL,#0x2000
ld A,(HL) ; A <- mem[0x2000]
cp #0x55 ; found sentinel byte? ($55)
jp Z,FoundSentinel ; yes, load program
.if 1
jp 0x2000 ; jump to $2000
.else
jp _main ; jump to test program
.endif
FoundSentinel:
ld SP,#0x4fce ; position stack below BIOS vars
call _bios_init ; misc. bios init routines
ld HL,#0x2005 ; cartridge start vector
ld A,(HL)
inc HL
ld H,(HL)
ld L,A
jp (HL) ; jump to cart start vector
SYSCALL38:
.org 0x38
push hl
push af
push bc
push de
push ix
push iy
ld hl,#0
add hl,sp
push hl ; HL points to context block
call _SYSCALL ; syscall handler
pop hl
pop iy
pop ix
pop de
pop bc
pop af
pop hl
ret
DOPEVector:
.org 0x200
JP _STIMER
JP _CTIMER
.db 0x20, 8, 8, 1, 7 ; Font descriptor (big font)
.dw _BIGFONT
.db 0xa0, 4, 6, 1, 5 ; Font descriptor (small font)
.dw _SMLFONT
ReloadRegs:
ld c,(hl)
inc hl
ld b,(hl)
inc hl
push bc
pop iy
ld c,(hl)
inc hl
ld b,(hl)
inc hl
push bc
pop ix
ld c,(hl)
inc hl
ld b,(hl)
inc hl
push bc
pop de
ld c,(hl)
inc hl
ld b,(hl)
inc hl
push bc
ld c,(hl)
inc hl
ld b,(hl)
inc hl
push bc
pop af
ld c,(hl)
inc hl
ld b,(hl)
inc hl
push bc
pop hl
pop bc
ret

View File

@ -13,6 +13,7 @@
PrgName: DB "HELLO, WORLDS!"; String PrgName: DB "HELLO, WORLDS!"; String
DB 0 ; ... which must be followed by 0 DB 0 ; ... which must be followed by 0
PrgStart: DI ; Disable interrupts PrgStart: DI ; Disable interrupts
; db $ed,$ff
SYSTEM INTPC ; Begin interpreter mode SYSTEM INTPC ; Begin interpreter mode
DO SETOUT ; Set output ports DO SETOUT ; Set output ports
DB 100*2 ; ... with VBLANK line set to line 100 DB 100*2 ; ... with VBLANK line set to line 100

View File

@ -9,6 +9,17 @@ void clrscr() {
memset(vidmem, 0, VHEIGHT*VBWIDTH); // clear page 1 memset(vidmem, 0, VHEIGHT*VBWIDTH); // clear page 1
} }
// set entire palette at once (8 bytes to port 0xb)
// bytes in array should be in reverse
void set_palette(byte palette[8]) __naked {
palette;
__asm
ld bc,#0x80b ; B -> 8, C -> 0xb
otir ; write C bytes to B
ret ; return
__endasm;
}
// draw vertical line // draw vertical line
void vline(byte x, byte y1, byte y2, byte col, byte op) { void vline(byte x, byte y1, byte y2, byte col, byte op) {
byte xb = x>>2; // divide x by 4 byte xb = x>>2; // divide x by 4
@ -33,33 +44,31 @@ void render_sprite(const byte* src, byte x, byte y, byte op) {
byte i,j; byte i,j;
byte w = *src++; // get width from 1st byte of sprite byte w = *src++; // get width from 1st byte of sprite
byte h = *src++; // get height from 2nd byte of sprite byte h = *src++; // get height from 2nd byte of sprite
byte xb = x>>2; // divide x by 4 byte* dest = &vmagic[y][x>>2];// destination address
byte* dest = &vmagic[y][xb]; // destination address
hw_magic = M_SHIFT(x) | op; // set magic register hw_magic = M_SHIFT(x) | op; // set magic register
for (j=0; j<h; j++) { // y clipping off bottom
EXIT_CLIPDEST(dest); if (y+h >= VHEIGHT) {
for (i=0; i<w; i++) { if (y >= VHEIGHT) return;
*dest++ = *src++; h = VHEIGHT-y;
}
*dest = 0; // rest of shifted byte
dest += VBWIDTH-w; // dest address to next scanline
} }
} // memory copy loop
if (op != M_ERASE) {
// erase a sprite for (j=0; j<h; j++) {
void erase_sprite(const byte* src, byte x, byte y) { for (i=0; i<w; i++) {
byte i,j; *dest++ = *src++;
byte w = *src++; // get width from 1st byte of sprite }
byte h = *src++; // get height from 2nd byte of sprite *dest = 0; // rest of shifted byte
byte xb = x>>2; // divide x by 4 dest += VBWIDTH-w; // dest address to next scanline
byte* dest = &vidmem[y][xb]; // destination address }
for (j=0; j<h; j++) { // erase sprite loop
EXIT_CLIPDEST(dest); } else {
for (i=0; i<w; i++) { for (j=0; j<h; j++) {
*dest++ = 0; for (i=0; i<w; i++) {
*dest++ = 0;
}
*dest = 0; // rest of shifted byte
dest += VBWIDTH-w; // dest address to next scanline
} }
*dest = 0; // rest of shifted byte
dest += VBWIDTH-w; // dest address to next scanline
} }
} }
@ -79,8 +88,12 @@ void draw_char(byte ch, byte x, byte y, byte op) {
EXIT_CLIPDEST(dest); EXIT_CLIPDEST(dest);
*dest++ = b; // expand lower nibble -> 1st byte *dest++ = b; // expand lower nibble -> 1st byte
*dest++ = b; // expand upper nibble -> 2nd byte *dest++ = b; // expand upper nibble -> 2nd byte
*dest++ = 0; // leftover -> 3rd byte if (x & 3) {
*dest = 0; // reset upper/lower flag *dest++ = 0; // leftover -> 3rd byte
*dest = 0; // reset upper/lower flag
} else {
dest++;
}
dest += VBWIDTH-3; // we incremented 3 bytes for this line dest += VBWIDTH-3; // we incremented 3 bytes for this line
} }
} }
@ -89,7 +102,7 @@ void draw_string(const char* str, byte x, byte y) {
do { do {
byte ch = *str++; byte ch = *str++;
if (!ch) break; if (!ch) break;
draw_char(ch, x, y, M_MOVE); draw_char(ch, x, y, M_XOR);
x += 8; x += 8;
} while (1); } while (1);
} }
@ -105,24 +118,24 @@ void draw_bcd_word(word bcd, byte x, byte y, byte op) {
} }
// add two 16-bit BCD values // add two 16-bit BCD values
word bcd_add(word a, word b) { word bcd_add(word a, word b) __naked {
a; b; // to avoid warning a; b; // to avoid warning
__asm __asm
ld hl,#4 push ix
add hl,sp ld ix,#0
ld iy,#2 add ix,sp
add iy,sp ld a,4 (ix)
ld a,0 (iy) add a, 6 (ix)
add a, (hl) daa
daa ld c,a
ld c,a ld a,5 (ix)
ld a,1 (iy) adc a, 7 (ix)
inc hl daa
adc a, (hl) ld b,a
daa ld l, c
ld b,a ld h, b
ld l, c pop ix
ld h, b ret
__endasm; __endasm;
} }

View File

@ -2,11 +2,14 @@
#ifndef _ACLIB_H #ifndef _ACLIB_H
#define _ACLIB_H #define _ACLIB_H
// convenient type definitions
typedef unsigned char byte; typedef unsigned char byte;
typedef signed char sbyte; typedef signed char sbyte;
typedef unsigned short word; typedef unsigned short word;
typedef enum { false, true } bool;
/// HARDWARE /// registers
__sfr __at(0x00) hw_col0r; // palette 0 __sfr __at(0x00) hw_col0r; // palette 0
__sfr __at(0x01) hw_col1r; __sfr __at(0x01) hw_col1r;
@ -24,10 +27,12 @@ __sfr __at(0x19) hw_xpand; // expander register
__sfr __at(0x08) hw_intst; // intercept test feedback __sfr __at(0x08) hw_intst; // intercept test feedback
__sfr __at(0x10) hw_p1ctrl; // player controls __sfr __at(0x10) hw_p1ctrl; // player 1 controls
__sfr __at(0x11) hw_p2ctrl; // player controls __sfr __at(0x11) hw_p2ctrl; // player 2 controls
__sfr __at(0x12) hw_p3ctrl; // player controls __sfr __at(0x12) hw_p3ctrl; // player 3 controls
__sfr __at(0x13) hw_p4ctrl; // player controls __sfr __at(0x13) hw_p4ctrl; // player 4 controls
// flags
#define M_SHIFT0 0x00 #define M_SHIFT0 0x00
#define M_SHIFT1 0x01 #define M_SHIFT1 0x01
@ -40,14 +45,19 @@ __sfr __at(0x13) hw_p4ctrl; // player controls
#define M_FLOP 0x40 #define M_FLOP 0x40
#define M_SHIFT(x) ((x)&3) #define M_SHIFT(x) ((x)&3)
#define XPAND_COLORS(off,on) (((off)&3) | (((on)&3)<<2)) #define XPAND_COLORS(off,on) (((off)&3) | (((on)&3)<<2))
#define M_ERASE 0x04 // special case for draw_sprite()
#define VHEIGHT 89 // number of scanlines #define VTOTAL 102 // number of total scanlines
#define VHEIGHT 89 // number of scanlines in use
#define VBWIDTH 40 // number of bytes per scanline #define VBWIDTH 40 // number of bytes per scanline
#define PIXWIDTH 160 // 4 pixels per byte #define PIXWIDTH 160 // 4 pixels per byte
byte __at (0x0000) vmagic[VHEIGHT][VBWIDTH]; // magic register active area
byte __at (0x4000) vidmem[VHEIGHT][VBWIDTH]; byte __at (0x0000) vmagic[VTOTAL][VBWIDTH];
// regular frame buffer RAM
byte __at (0x4000) vidmem[VTOTAL][VBWIDTH];
// font constants
#define LOCHAR 32 #define LOCHAR 32
#define HICHAR 127 #define HICHAR 127
#define FONT_BWIDTH 1 #define FONT_BWIDTH 1
@ -56,13 +66,15 @@ byte __at (0x4000) vidmem[VHEIGHT][VBWIDTH];
/// GRAPHICS FUNCTIONS /// GRAPHICS FUNCTIONS
void clrscr(); void clrscr();
void set_palette(byte palette[8]); // palette in reverse order
void vline(byte x, byte y1, byte y2, byte col, byte op); void vline(byte x, byte y1, byte y2, byte col, byte op);
void pixel(byte x, byte y, byte col, byte op); void pixel(byte x, byte y, byte col, byte op);
void render_sprite(const byte* src, byte x, byte y, byte op); void render_sprite(const byte* src, byte x, byte y, byte op);
void erase_sprite(const byte* src, byte x, byte y);
void draw_char(byte ch, byte x, byte y, byte op); void draw_char(byte ch, byte x, byte y, byte op);
void draw_string(const char* str, byte x, byte y); void draw_string(const char* str, byte x, byte y);
void draw_bcd_word(word bcd, byte x, byte y, byte op); void draw_bcd_word(word bcd, byte x, byte y, byte op);
word bcd_add(word a, word b); word bcd_add(word a, word b);
#define erase_sprite(src,x,y) render_sprite(src,x,y,M_ERASE);
#endif #endif

View File

@ -21,17 +21,17 @@
const byte player_bitmap[] = const byte player_bitmap[] =
{3,14,/*{w:12,h:16,bpp:2,brev:1}*/0x00,0x3C,0x00,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x18,0x00,0x04,0x18,0x20,0x0C,0x3C,0x30,0x3C,0x3C,0x3C,0x1F,0xE7,0xF4,0x1F,0x66,0xF4,0x17,0xE7,0xE4,0x17,0xE7,0xE4,0x1C,0x7E,0x34,0x1C,0xFF,0x34,0x3C,0x18,0x3C,0x0C,0x18,0x30,0x04,0x18,0x20}; {3,14,/*{w:12,h:16,bpp:2,brev:1}*/0x00,0x3C,0x00,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x18,0x00,0x04,0x18,0x20,0x0C,0x3C,0x30,0x3C,0x3C,0x3C,0x1F,0xE7,0xF4,0x1F,0x66,0xF4,0x17,0xE7,0xE4,0x17,0xE7,0xE4,0x1C,0x7E,0x34,0x1C,0xFF,0x34,0x3C,0x18,0x3C,0x0C,0x18,0x30,0x04,0x18,0x20};
const byte bomb_bitmap[] = const byte bomb_bitmap[] =
{1,5,/*{w:8,h:5,bpp:2,brev:1}*/0x88,0x55,0x77,0x55,0x88}; {1,5,/*{w:4,h:5,bpp:2,brev:1}*/0x88,0x55,0x77,0x55,0x88};
const byte bullet_bitmap[] = const byte bullet_bitmap[] =
{1,5,/*{w:8,h:5,bpp:2,brev:1}*/0x14,0x28,0x14,0x14,0x28}; {1,5,/*{w:4,h:5,bpp:2,brev:1}*/0x14,0x28,0x14,0x14,0x28};
const byte enemy1_bitmap[] = const byte enemy1_bitmap[] =
{2,8,/*{w:16,h:8,bpp:2,brev:1}*/0x00,0x00,0x70,0x38,0xF8,0x7C,0xFC,0xFC,0xFE,0xFC,0xFE,0xFF,0xFC,0xFF,0xF8,0x7F,0xF0,0x3F,0x88,0x47,0xF0,0x3F,0xF0,0x3F,0xD0,0x2F,0x8C,0xC7,0x48,0x48,0x80,0x04}; {2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x00,0x00,0x70,0x38,0xF8,0x7C,0xFC,0xFC,0xFE,0xFC,0xFE,0xFF,0xFC,0xFF,0xF8,0x7F,0xF0,0x3F,0x88,0x47,0xF0,0x3F,0xF0,0x3F,0xD0,0x2F,0x8C,0xC7,0x48,0x48,0x80,0x04};
const byte enemy2_bitmap[] = const byte enemy2_bitmap[] =
{2,8,/*{w:16,h:8,bpp:2,brev:1}*/0x00,0x00,0x30,0x0C,0x14,0x28,0x2E,0x74,0x08,0x10,0x20,0x04,0xE0,0x07,0xD0,0x0B,0xB0,0x0D,0xB2,0x4D,0x19,0x98,0x8E,0x71,0x82,0x41,0xB1,0x8D,0x59,0x9A,0x4A,0x52}; {2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x00,0x00,0x30,0x0C,0x14,0x28,0x2E,0x74,0x08,0x10,0x20,0x04,0xE0,0x07,0xD0,0x0B,0xB0,0x0D,0xB2,0x4D,0x19,0x98,0x8E,0x71,0x82,0x41,0xB1,0x8D,0x59,0x9A,0x4A,0x52};
const byte enemy3_bitmap[] = const byte enemy3_bitmap[] =
{2,8,/*{w:16,h:8,bpp:2,brev:1}*/0x00,0x00,0x00,0x00,0x04,0x20,0x05,0xA0,0x05,0xA0,0x25,0xA4,0xA7,0xE5,0xF7,0xEF,0xF7,0xEF,0xFE,0x7F,0xFC,0x3F,0xBC,0x3D,0xE4,0x27,0x20,0x00,0x00,0x00,0x00,0x00}; {2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x00,0x00,0x00,0x00,0x04,0x20,0x05,0xA0,0x05,0xA0,0x25,0xA4,0xA7,0xE5,0xF7,0xEF,0xF7,0xEF,0xFE,0x7F,0xFC,0x3F,0xBC,0x3D,0xE4,0x27,0x20,0x00,0x00,0x00,0x00,0x00};
const byte enemy4_bitmap[] = const byte enemy4_bitmap[] =
{2,8,/*{w:16,h:8,bpp:2,brev:1}*/0x00,0x00,0x00,0x00,0xF0,0x0F,0xF8,0x1F,0xD8,0x1B,0xF8,0x1F,0xF8,0x1F,0xF8,0x1F,0xF0,0x0F,0xA8,0x15,0xCC,0x33,0xE8,0x17,0x66,0x66,0x33,0xCC,0x61,0x86,0x40,0x02}; {2,8,/*{w:8,h:8,bpp:2,brev:1}*/0x00,0x00,0x00,0x00,0xF0,0x0F,0xF8,0x1F,0xD8,0x1B,0xF8,0x1F,0xF8,0x1F,0xF8,0x1F,0xF0,0x0F,0xA8,0x15,0xCC,0x33,0xE8,0x17,0x66,0x66,0x33,0xCC,0x61,0x86,0x40,0x02};
const byte* const enemy_bitmaps[4] = { const byte* const enemy_bitmaps[4] = {
enemy1_bitmap, enemy1_bitmap,
@ -88,7 +88,7 @@ void draw_lives() {
byte i; byte i;
byte n = lives; byte n = lives;
byte y = 0; byte y = 0;
byte x = PIXWIDTH-4*5; byte x = PIXWIDTH-4*6;
hw_xpand = XPAND_COLORS(0, COLOR_SCORE); hw_xpand = XPAND_COLORS(0, COLOR_SCORE);
for (i=0; i<MAXLIVES; i++) { for (i=0; i<MAXLIVES; i++) {
draw_char(i<n?'|':' ', x, y, M_MOVE); draw_char(i<n?'|':' ', x, y, M_MOVE);

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

@ -0,0 +1,32 @@
#include "aclib.h"
//#link "aclib.c"
//#link "acheader.s"
#include <stdlib.h>
#include <string.h>
/*{pal:"astrocade",layout:"astrocade"}*/
const byte palette[8] = {
0x06, 0x62, 0xF1, 0x04,
0x07, 0xD4, 0x35, 0x00,
};
void setup_registers() {
// setup colors
set_palette(palette);
// horizontal palette split
hw_horcb = 12;
// height of screen
hw_verbl = VHEIGHT*2;
}
void main() {
setup_registers();
clrscr();
hw_xpand = XPAND_COLORS(0, 2);
draw_string("Hello, World!", 2, 0);
// infinite loop
while (1) {
}
}

View File

@ -10,7 +10,6 @@
; > Version 2.6 - March 2, 2004 - as seen on BallyAlley.com ; > Version 2.6 - March 2, 2004 - as seen on BallyAlley.com
; > Version 3.0 - 2009 ; > Version 3.0 - 2009
; > Version 3.01 - Changed "FonT BASE character" comment ; > Version 3.01 - Changed "FonT BASE character" comment
; > (also patched for latest zmac with default args)
; > ; >
; > This file contains the equates and macros that Bally ; > This file contains the equates and macros that Bally
; > programs require for assembly. This file has been ; > programs require for assembly. This file has been

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

@ -0,0 +1,50 @@
#include "aclib.h"
//#link "aclib.c"
//#link "acheader.s"
#include <stdlib.h>
#include <string.h>
void draw_line(int x0, int y0, int x1, int y1, byte color) {
int dx = abs(x1-x0);
int sx = x0<x1 ? 1 : -1;
int dy = abs(y1-y0);
int sy = y0<y1 ? 1 : -1;
int err = (dx>dy ? dx : -dy)>>1;
int e2;
for(;;) {
pixel(x0, y0, color, M_XOR);
if (x0==x1 && y0==y1) break;
e2 = err;
if (e2 > -dx) { err -= dy; x0 += sx; }
if (e2 < dy) { err += dx; y0 += sy; }
}
}
/*{pal:"astrocade",layout:"astrocade"}*/
const byte palette[8] = {
0x06, 0x62, 0xF1, 0x04,
0x07, 0xD4, 0x35, 0x00,
};
void setup_registers() {
set_palette(palette);
// horizontal palette split
hw_horcb = 20;
// height of screen
hw_verbl = VHEIGHT*2;
}
void main() {
setup_registers();
clrscr();
hw_xpand = XPAND_COLORS(0, 2);
draw_string("Hello, Lines!", 2, 80);
draw_line(0, 0, 159, 95, 1);
// infinite loop
srand(1);
while(1) {
draw_line(rand()%159, rand()%79, rand()%159, rand()%79, rand()&3);
}
}

View File

@ -1,8 +1,29 @@
#include "aclib.h"
//#link "aclib.c"
//#link "acheader.s" //#link "acheader.s"
#include <stdlib.h>
#include <string.h> #include <string.h>
void main() { void setup_registers() {
memset((void*)0x4000, 0, 0xe00); // clear screen, avoid vars and stack (1e00-1fff) // setup colors
hw_col0r = 0x00;
hw_col1r = 0x2f;
hw_col2r = 0xef;
hw_col3r = 0xaf;
// horizontal palette split
hw_horcb = 12;
// height of screen
hw_verbl = VHEIGHT*2;
}
void main() {
setup_registers();
clrscr();
hw_xpand = XPAND_COLORS(0, 2);
draw_string("Hello, World!", 2, 0);
// infinite loop
while (1) {
}
} }

View File

@ -0,0 +1,34 @@
#include <string.h>
#include "aclib.h"
//#link "aclib.c"
//#link "acheader.s"
const byte player_bitmap[] =
{3,14,/*{w:12,h:16,bpp:2,brev:1}*/0x00,0x3C,0x00,0x00,0x18,0x00,0x00,0x3C,0x00,0x00,0x18,0x00,0x04,0x18,0x20,0x0C,0x3C,0x30,0x3C,0x3C,0x3C,0x1F,0xE7,0xF4,0x1F,0x66,0xF4,0x17,0xE7,0xE4,0x17,0xE7,0xE4,0x1C,0x7E,0x34,0x1C,0xFF,0x34,0x3C,0x18,0x3C,0x0C,0x18,0x30,0x04,0x18,0x20};
/*{pal:"astrocade",layout:"astrocade"}*/
const byte palette[8] = {
0x06, 0x62, 0xF1, 0x04,
0x07, 0xD4, 0x35, 0x00,
};
void setup_registers() {
set_palette(palette);
hw_horcb = 0;
hw_verbl = VHEIGHT*2;
}
void main() {
byte x,y;
x=10;
y=10;
setup_registers();
clrscr();
while (1) {
render_sprite(player_bitmap, x, y, M_MOVE);
x++;
y++;
}
}

View File

@ -118,6 +118,8 @@ export interface Preset {
export interface MemoryBus { export interface MemoryBus {
read : (address:number) => number; read : (address:number) => number;
write : (address:number, value:number) => void; write : (address:number, value:number) => void;
contend?: (address:number, cycles:number) => number;
isContended?: (address:number) => boolean;
} }
export type DebugCondition = () => boolean; export type DebugCondition = () => boolean;
@ -508,6 +510,12 @@ export function BusProbe(bus : MemoryBus) {
} }
bus.write(a,v); bus.write(a,v);
} }
this.contend = function(addr,cyc) {
return bus.contend(addr,cyc);
}
this.isContended = function(addr) {
return bus.isContended(addr);
}
} }
export abstract class BaseZ80Platform extends BaseDebugPlatform { export abstract class BaseZ80Platform extends BaseDebugPlatform {
@ -515,10 +523,9 @@ export abstract class BaseZ80Platform extends BaseDebugPlatform {
_cpu; _cpu;
probe; probe;
newCPU(membus : MemoryBus, iobus : MemoryBus) { newCPU(membus : MemoryBus, iobus : MemoryBus, z80opts? : {}) {
this.probe = new BusProbe(membus); this.probe = new BusProbe(membus);
var z80opts = {}; this._cpu = buildZ80(z80opts || {})({
this._cpu = buildZ80(z80opts)({
display: {}, display: {},
memory: this.probe, memory: this.probe,
ioBus: iobus ioBus: iobus

View File

@ -299,7 +299,8 @@ var PREDEF_PALETTES = {
0x003814,0x003814, 0x1c5c34,0x1c5c34, 0x387c50,0x387c50, 0x50986c,0x50986c, 0x68b484,0x68b484, 0x7ccc9c,0x7ccc9c, 0x90e4b4,0x90e4b4, 0xa4fcc8,0xa4fcc8, 0x003814,0x003814, 0x1c5c34,0x1c5c34, 0x387c50,0x387c50, 0x50986c,0x50986c, 0x68b484,0x68b484, 0x7ccc9c,0x7ccc9c, 0x90e4b4,0x90e4b4, 0xa4fcc8,0xa4fcc8,
0x00302c,0x00302c, 0x1c504c,0x1c504c, 0x347068,0x347068, 0x4c8c84,0x4c8c84, 0x64a89c,0x64a89c, 0x78c0b4,0x78c0b4, 0x88d4cc,0x88d4cc, 0x9cece0,0x9cece0, 0x00302c,0x00302c, 0x1c504c,0x1c504c, 0x347068,0x347068, 0x4c8c84,0x4c8c84, 0x64a89c,0x64a89c, 0x78c0b4,0x78c0b4, 0x88d4cc,0x88d4cc, 0x9cece0,0x9cece0,
0x002844,0x002844, 0x184864,0x184864, 0x306884,0x306884, 0x4484a0,0x4484a0, 0x589cb8,0x589cb8, 0x6cb4d0,0x6cb4d0, 0x7ccce8,0x7ccce8, 0x8ce0fc,0x8ce0fc 0x002844,0x002844, 0x184864,0x184864, 0x306884,0x306884, 0x4484a0,0x4484a0, 0x589cb8,0x589cb8, 0x6cb4d0,0x6cb4d0, 0x7ccce8,0x7ccce8, 0x8ce0fc,0x8ce0fc
] ],
'astrocade':[0,2368548,4737096,7171437,9539985,11974326,14342874,16777215,12255269,14680137,16716142,16725394,16734903,16744155,16753663,16762879,11534409,13959277,16318866,16721334,16730842,16740095,16749311,16758783,10420330,12779662,15138995,16718039,16727291,16736767,16745983,16755199,8847495,11206827,13631696,15994612,16724735,16733951,16743423,16752639,6946975,9306307,11731175,14092287,16461055,16732415,16741631,16751103,4784304,7143637,9568505,11929087,14297599,16731647,16741119,16750335,2425019,4784352,7209215,9570047,12004095,14372863,16741375,16750847,191,2359523,4718847,7146495,9515263,11949311,14318079,16752127,187,224,2294015,4658431,7092735,9461247,11895551,14264063,176,213,249,2367999,4736511,7105279,9539327,11908095,159,195,3303,209151,2577919,4946431,7380735,9749247,135,171,7888,17140,681983,3050495,5484543,7853311,106,3470,12723,22231,31483,1548031,3916799,6285311,73,8557,17810,27318,36570,373759,2742271,5176575,4389,13641,23150,32402,41911,51163,2026495,4456447,9472,18724,27976,37485,46737,56246,1834970,4194303,14080,23296,32803,42055,51564,60816,2031541,4456409,18176,27648,36864,46116,55624,392556,2752401,5177269,21760,30976,40192,49667,58919,1572683,3932016,6291348,24320,33536,43008,52224,716810,3079982,5504851,7864183,25856,35328,44544,250368,2619136,4980503,7405371,9764703,26624,35840,45312,2413824,4782336,7143173,9568041,11927374,26112,35584,2338560,4707328,7141376,9502464,11927326,14286659,24832,2393344,4762112,7196160,9564928,11992832,14352155,16711487,2447360,4815872,7250176,9618688,12052992,14417664,16776990,16777027,4803328,7172096,9606144,11974912,14343424,16776965,16777001,16777038,6962176,9330688,11764992,14133504,16502272,16773655,16777019,16777055,8858112,11226880,13660928,16029440,16759818,16769070,16777043,16777079,10426112,12794624,15163392,16745475,16754727,16764235,16773488,16777108,11534848,13969152,16337664,16740388,16749640,16759148,16768401,16777141,12255232,14684928,16725795,16735047,16744556,16753808,16763317,16772569],
}; };
var PREDEF_LAYOUTS : {[id:string]:PixelEditorPaletteLayout} = { var PREDEF_LAYOUTS : {[id:string]:PixelEditorPaletteLayout} = {
@ -314,6 +315,10 @@ var PREDEF_LAYOUTS : {[id:string]:PixelEditorPaletteLayout} = {
['Sprite 2', 0x19, 3], ['Sprite 2', 0x19, 3],
['Sprite 3', 0x1d, 3] ['Sprite 3', 0x1d, 3]
], ],
'astrocade':[
['Left', 0x04, -4],
['Right', 0x00, -4]
],
}; };
///// /////
@ -587,7 +592,6 @@ function dedupPalette(cols : UintArray) : Uint32Array {
} }
export class PaletteFormatToRGB extends PixNode { export class PaletteFormatToRGB extends PixNode {
words : UintArray; words : UintArray;
rgbimgs : Uint32Array[]; rgbimgs : Uint32Array[];
palette : Uint32Array; palette : Uint32Array;

View File

@ -11,6 +11,9 @@ const ASTROCADE_PRESETS = [
{id:'01-helloworlds.asm', name:'Hello World'}, {id:'01-helloworlds.asm', name:'Hello World'},
{id:'02-telephone.asm', name:'Telephone'}, {id:'02-telephone.asm', name:'Telephone'},
{id:'03-horcbpal.asm', name:'Paddle Demo'}, {id:'03-horcbpal.asm', name:'Paddle Demo'},
{id:'hello.c', name:'Hello World'},
{id:'lines.c', name:'Lines'},
{id:'sprites.c', name:'Sprites'},
{id:'cosmic.c', name:'Cosmic Impalas Game'}, {id:'cosmic.c', name:'Cosmic Impalas Game'},
]; ];
@ -68,7 +71,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
const sheight = arcade ? 204 : 102; const sheight = arcade ? 204 : 102;
const swbytes = Math.floor(swidth / 4); const swbytes = Math.floor(swidth / 4);
const cpuFrequency = 1789000; const cpuFrequency = 1789000;
const cpuCyclesPerLine = cpuFrequency/(60*sheight); // TODO: wait states? const cpuCyclesPerLine = cpuFrequency/(60*262);
const INITIAL_WATCHDOG = 256; const INITIAL_WATCHDOG = 256;
const PIXEL_ON = 0xffeeeeee; const PIXEL_ON = 0xffeeeeee;
const PIXEL_OFF = 0xff000000; const PIXEL_OFF = 0xff000000;
@ -90,6 +93,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
palette[i] = ASTROCADE_PALETTE[i]; palette[i] = ASTROCADE_PALETTE[i];
var refreshlines = 0; var refreshlines = 0;
var vidactive = false;
function ramwrite(a:number, v:number) { function ramwrite(a:number, v:number) {
ram.mem[a] = v; ram.mem[a] = v;
@ -176,6 +180,8 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
} }
class BallyAstrocadePlatform extends BaseZ80Platform implements Platform { class BallyAstrocadePlatform extends BaseZ80Platform implements Platform {
scanline : number;
getPresets() { getPresets() {
return ASTROCADE_PRESETS; return ASTROCADE_PRESETS;
@ -196,7 +202,10 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
[0x4000, 0x4fff, 0xfff, ramwrite], [0x4000, 0x4fff, 0xfff, ramwrite],
[0x0000, 0x3fff, 0x3fff, magicwrite], [0x0000, 0x3fff, 0x3fff, magicwrite],
]), ]),
isContended: function() { return false; }, // TODO: correct values?
// TODO: no contention on hblank
isContended: () => { return true; },
contend: () => { return vidactive ? 1 : 0; },
}; };
} else { } else {
// arcade game // arcade game
@ -211,10 +220,17 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
[0xd000, 0xdfff, 0xfff, function(a,v) { ramwrite(a+0x4000, v); } ], // static RAM [0xd000, 0xdfff, 0xfff, function(a,v) { ramwrite(a+0x4000, v); } ], // static RAM
[0x0000, 0x3fff, 0x3fff, magicwrite], [0x0000, 0x3fff, 0x3fff, magicwrite],
]), ]),
isContended: function() { return false; }, isContended: () => { return true; },
contend: () => { return vidactive ? 1 : 0; },
}; };
} }
iobus = { iobus = {
isULAPort: function(addr) {
return false; // TODO?
},
contend: function(addr) {
return 0; // TODO?
},
read: function(addr) { read: function(addr) {
addr &= 0x1f; addr &= 0x1f;
var rtn = inputs[addr]; var rtn = inputs[addr];
@ -285,7 +301,7 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
} }
} }
}; };
cpu = this.newCPU(membus, iobus); cpu = this.newCPU(membus, iobus, {applyContention:true});
audio = new MasterAudio(); audio = new MasterAudio();
psg = new AstrocadeAudio(audio); psg = new AstrocadeAudio(audio);
video = new RasterVideo(mainElement,swidth,sheight,{}); video = new RasterVideo(mainElement,swidth,sheight,{});
@ -308,13 +324,14 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
advance(novideo : boolean) { advance(novideo : boolean) {
this.loadControls(); this.loadControls();
for (var sl=0; sl<sheight; sl++) { for (var sl=0; sl<131; sl++) {
//console.log(sl, hex(cpu.getPC(),4), cpu.saveState()); this.scanline = sl;
this.runCPU(cpu, cpuCyclesPerLine); vidactive = sl < verbl;
this.runCPU(cpu, cpuCyclesPerLine*2); // TODO?
if (sl == inlin && (inmod & 0x8)) { if (sl == inlin && (inmod & 0x8)) {
this.requestInterrupt(cpu, infbk); this.requestInterrupt(cpu, infbk);
} }
if (refreshlines>0) { if (sl < sheight && refreshlines>0) {
refreshline(sl); refreshline(sl);
refreshlines--; refreshlines--;
} }
@ -329,6 +346,8 @@ const _BallyAstrocadePlatform = function(mainElement, arcade) {
} }
*/ */
} }
getRasterScanline() { return this.scanline; }
loadROM(title, data) { loadROM(title, data) {
rom = padBytes(data, arcade ? 0xb000 : 0x2000); rom = padBytes(data, arcade ? 0xb000 : 0x2000);
@ -476,7 +495,7 @@ for (var i=0; i<256; i++) {
0004 7E [ 7] 198 LD A,(HL) ; A <- mem[0x2000] 0004 7E [ 7] 198 LD A,(HL) ; A <- mem[0x2000]
0005 FE 55 [ 7] 199 CP #0x55 ; found sentinel byte? ($55) 0005 FE 55 [ 7] 199 CP #0x55 ; found sentinel byte? ($55)
0007 CA 0D 00 [10] 200 JP Z,FoundSentinel ; yes, load program 0007 CA 0D 00 [10] 200 JP Z,FoundSentinel ; yes, load program
000A C3 AB 0E [10] 201 JP _main ; jump to test program 000A C3 00 20 [10] 201 JP _main ; jump to test program
000D 202 FoundSentinel: 000D 202 FoundSentinel:
000D 31 CE 4F [10] 203 LD SP,#0x4fce ; position stack below BIOS vars 000D 31 CE 4F [10] 203 LD SP,#0x4fce ; position stack below BIOS vars
0010 CD 84 02 [17] 204 CALL _bios_init ; misc. bios init routines 0010 CD 84 02 [17] 204 CALL _bios_init ; misc. bios init routines
@ -488,7 +507,7 @@ for (var i=0; i<256; i++) {
001A E9 [ 4] 210 JP (HL) ; jump to cart start vector 001A E9 [ 4] 210 JP (HL) ; jump to cart start vector
*/ */
var ASTROCADE_MINIMAL_BIOS = [ var ASTROCADE_MINIMAL_BIOS = [
0xf3, 0x21, 0x00, 0x20, 0x7e, 0xfe, 0x55, 0xca, 0x0d, 0x00, 0xc3, 0xab, 0x0e, 0xf3, 0x21, 0x00, 0x20, 0x7e, 0xfe, 0x55, 0xca, 0x0d, 0x00, 0xc3, 0x00, 0x20,
0x31, 0xce, 0x4f, 0xcd, 0x84, 0x02, 0x21, 0x05, 0x20, 0x7e, 0x23, 0x66, 0x6f, 0x31, 0xce, 0x4f, 0xcd, 0x84, 0x02, 0x21, 0x05, 0x20, 0x7e, 0x23, 0x66, 0x6f,
0xe9, 0xe9,
]; ];

View File

@ -32,7 +32,6 @@ var Base_Z80Platform = function(mainElement) {
write: newAddressDecoder([ write: newAddressDecoder([
[0x8000, 0xffff, 0x7fff, function(a,v) { ram.mem[a] = v; }], [0x8000, 0xffff, 0x7fff, function(a,v) { ram.mem[a] = v; }],
]), ]),
isContended: function() { return false; },
}; };
this.readAddress = membus.read; this.readAddress = membus.read;
iobus = { iobus = {

View File

@ -89,7 +89,6 @@ const _ColecoVisionPlatform = function(mainElement) {
write: newAddressDecoder([ write: newAddressDecoder([
[0x6000, 0x7fff, 0x3ff, function(a,v) { ram.mem[a] = v; }], [0x6000, 0x7fff, 0x3ff, function(a,v) { ram.mem[a] = v; }],
]), ]),
isContended: function() { return false; },
}; };
iobus = { iobus = {
read: function(addr) { read: function(addr) {

View File

@ -249,7 +249,6 @@ const _GalaxianPlatform = function(mainElement, options) {
//[0x8200, 0x8203, 0, function(a,v){ /* PPI 1 */ }], //[0x8200, 0x8203, 0, function(a,v){ /* PPI 1 */ }],
//[0, 0xffff, 0, function(a,v) { console.log(hex(a),hex(v)); }] //[0, 0xffff, 0, function(a,v) { console.log(hex(a),hex(v)); }]
]), ]),
isContended: function() { return false; },
}; };
} else { } else {
inputs = [0xe,0x8,0x0]; inputs = [0xe,0x8,0x0];

View File

@ -78,7 +78,6 @@ class MSXPlatform extends BasicZ80ScanlinePlatform implements Platform {
let slot = this.slots[slotnum]; let slot = this.slots[slotnum];
if (slot) slot.write(a, v); if (slot) slot.write(a, v);
}, },
isContended: () => { return false; },
}; };
} }

View File

@ -62,7 +62,6 @@ class Midway8080BWPlatform extends BasicZ80ScanlinePlatform implements Platform
//if (displayPCs) displayPCs[a] = cpu.getPC(); // save program counter //if (displayPCs) displayPCs[a] = cpu.getPC(); // save program counter
}], }],
]), ]),
isContended: function() { return false; },
}; };
} }

View File

@ -78,7 +78,6 @@ class SG1000Platform extends BasicZ80ScanlinePlatform implements Platform {
write: newAddressDecoder([ write: newAddressDecoder([
[0xc000, 0xffff, 0x3ff, (a,v) => { this.ram[a] = v; }], [0xc000, 0xffff, 0x3ff, (a,v) => { this.ram[a] = v; }],
]), ]),
isContended: () => { return false; },
}; };
} }

View File

@ -72,7 +72,6 @@ var WilliamsSoundPlatform = function(mainElement) {
write: newAddressDecoder([ write: newAddressDecoder([
[0x4000, 0x7fff, 0x3ff, function(a,v) { ram.mem[a] = v; }], [0x4000, 0x7fff, 0x3ff, function(a,v) { ram.mem[a] = v; }],
]), ]),
isContended: function() { return false; },
}; };
iobus = { iobus = {
read: function(addr) { read: function(addr) {

View File

@ -136,7 +136,6 @@ class VicDualPlatform extends BasicZ80ScanlinePlatform implements Platform {
write: newAddressDecoder([ write: newAddressDecoder([
[0x8000, 0xffff, 0x0fff, (a, v) => { this.ram[a] = v; }], [0x8000, 0xffff, 0x0fff, (a, v) => { this.ram[a] = v; }],
]), ]),
isContended: () => { return false; },
}; };
} }

View File

@ -955,6 +955,10 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
if (len == matchlen) { if (len == matchlen) {
var rgbs = palette.slice(start, start+len); var rgbs = palette.slice(start, start+len);
result.push({node:node, name:name, palette:rgbs}); result.push({node:node, name:name, palette:rgbs});
} else if (-len == matchlen) { // reverse order
var rgbs = palette.slice(start, start-len);
rgbs.reverse();
result.push({node:node, name:name, palette:rgbs});
} else if (len+1 == matchlen) { } else if (len+1 == matchlen) {
var rgbs = new Uint32Array(matchlen); var rgbs = new Uint32Array(matchlen);
rgbs[0] = palette[0]; rgbs[0] = palette[0];
@ -1107,8 +1111,10 @@ export class AssetEditorView implements ProjectView, pixed.EditorContext {
var arow = $('<tr/>').appendTo(atable); var arow = $('<tr/>').appendTo(atable);
$('<td/>').text(name).appendTo(arow); $('<td/>').text(name).appendTo(arow);
var inds = []; var inds = [];
for (var k=start; k<start+len; k++) for (var k=start; k<start+Math.abs(len); k++)
inds.push(k); inds.push(k);
if (len < 0)
inds.reverse();
inds.forEach( (i) => { inds.forEach( (i) => {
var cell = $('<td/>').addClass('asset_cell asset_editable').appendTo(arow); var cell = $('<td/>').addClass('asset_cell asset_editable').appendTo(arow);
updateCell(cell, i); updateCell(cell, i);