#define SAMPLES_PER_UPDATE 500
#if GALAXIAN
-#define INT_VECTOR 0
-
#define RAM_START 0x4000
#define TILE_RAM 0x5000
-#define PALETTE_RAM 0x5400
#define SPRITE_RAM 0x5800
#define IO_PAGE 0x6000
+#define HW_INT_ENABLE 0x6031 // z80 7001
#elif PACMAN
#define INT_VECTOR 0
#define SPRITE_CONFIG 0x4ff0
#define IO_PAGE 0x5000
-#define SPRITE_COORDS 0x5060
+#define HW_INT_ENABLE 0x5100 // z80 5000
+#define SPRITE_COORDS 0x5160 // z80 5060
#else // APPLE
#define IO_PAGE 0xe000
#define HW_KBD 0xe000 // R last key pressed + 128
#define TRACE 0
#define IO_TRACE 0
-#define MEM_TRACE 1
+#define MEM_TRACE 0
extern char **environ;
int usleep_count, exit_flag;
#if GALAXIAN
-uint8_t int_vector;
-
// just for now until we have galaxian audio
#define C0X0_SOFT_SWITCH_TAPEOUT 4
#define C0X0_SOFT_SWITCH_SPKR 8
uint8_t c0x0_soft_switches_buf[C0X0_SOFT_SWITCHES_BUF_SIZE];
#elif PACMAN
uint8_t int_vector;
-uint8_t sprite_coords[0x10];
// just for now until we have pacman audio
#define C0X0_SOFT_SWITCH_TAPEOUT 4
}
uint8_t rb(void *userdata, uint16_t addr0) {
-#if GALAXIAN || PACMAN
+#if GALAXIAN
int addr = addr0;
if (addr < IO_PAGE) {
#endif
return mem[addr];
}
+ else if (addr < 0x8000 && (addr & 0x7f8) == 0) {
+ addr -= IO_PAGE;
+ addr = (addr & 7) | ((addr >> 8) & 0x18);
+ addr += IO_PAGE;
#if MEM_TRACE
- int pc = cpu.pc;
- fprintf(stderr, "pc=%04x addr=%04x rd=??\n", pc, addr);
+ int pc = cpu.pc;
+ fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
#endif
+ return mem[addr];
+ }
+#elif PACMAN
+ int addr = addr0;
+
+ if (addr < IO_PAGE + 0x100) {
+#if MEM_TRACE
+ int pc = cpu.pc;
+ fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
+#endif
+ return mem[addr];
+ }
#else
// for joystick, for now count memory accesses as proxy for cycles
if (joystick_count < JOYSTICK_COUNT) {
}
void wb(void *userdata, uint16_t addr0, uint8_t val) {
-#if GALAXIAN || PACMAN
+#if GALAXIAN
int addr = addr0;
if (addr < RAM_START)
#endif
mem[addr] = val;
}
- else if (addr < IO_PAGE + 0x100) {
+ else if (addr < 0x8000 && (addr & 0x7f8) == 0) {
+ addr -= IO_PAGE;
+ addr = (addr & 7) | ((addr >> 8) & 0x18);
+ addr += IO_PAGE | 0x20; // separate read and write registers
#if MEM_TRACE
int pc = cpu.pc;
- fprintf(stderr, "pc=%04x addr=%04x wr=%02x (io)\n", pc, addr, val);
-#endif
-#if PACMAN
- switch (addr) {
- case SPRITE_COORDS: // 0x5060
- case SPRITE_COORDS | 1: // 0x5061
- case SPRITE_COORDS | 2: // 0x5062
- case SPRITE_COORDS | 3: // 0x5063
- case SPRITE_COORDS | 4: // 0x5064
- case SPRITE_COORDS | 5: // 0x5065
- case SPRITE_COORDS | 6: // 0x5066
- case SPRITE_COORDS | 7: // 0x5067
- case SPRITE_COORDS | 8: // 0x5068
- case SPRITE_COORDS | 9: // 0x5069
- case SPRITE_COORDS | 0xa: // 0x506a
- case SPRITE_COORDS | 0xb: // 0x506b
- case SPRITE_COORDS | 0xc: // 0x506c
- case SPRITE_COORDS | 0xd: // 0x506d
- case SPRITE_COORDS | 0xe: // 0x506e
- case SPRITE_COORDS | 0xf: // 0x506f
- sprite_coords[addr & 0xf] = val;
- break;
- }
+ fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
#endif
+ mem[addr] = val;
}
+#elif PACMAN
+ int addr = addr0;
+
+ if (addr < RAM_START)
+ ;
+ else if (addr < IO_PAGE + 0x100) {
+ if (addr >= IO_PAGE)
+ addr += 0x100; // separate read and write registers
#if MEM_TRACE
- else {
int pc = cpu.pc;
- fprintf(stderr, "pc=%04x addr=%04x wr=%02x (nop)\n", pc, addr, val);
- }
+ fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
#endif
+ mem[addr] = val;
+ }
#else
// for joystick, for now count memory accesses as proxy for cycles
if (joystick_count < JOYSTICK_COUNT) {
#endif
switch (port) {
-#if GALAXIAN || PACMAN
+#if PACMAN
case INT_VECTOR:
int_vector = val;
break;
#if GALAXIAN
// send z80 a vertical refresh interrupt
- cpu.int_pending = true;
- cpu.int_data = int_vector;
+ if (mem[HW_INT_ENABLE] & 1)
+ cpu.nmi_pending = true;
// draw tiles
- for (int i = 0; i < 32; ++i)
+ for (int i = 0; i < 32; ++i) {
+ int palette_base =
+ ((mem[i | SPRITE_RAM] & 7) << 2) |
+ ROM_GALAXIAN_CLR_ADDR;
for (int j = 0; j < 28; ++j) {
int offset = i + ((27 - j) << 5);
int tile_base = 7 | (mem[TILE_RAM | offset] << 3);
- int tile_base0 = tile_base | ROM_1H_ADDR;
- int tile_base1 = tile_base | ROM_1K_ADDR;
- int palette_base =
- ((mem[PALETTE_RAM | offset] & 0x3f) << 2) | ROM_GALAXIAN_CLR_ADDR;
+ int tile_base0 = tile_base | ROM_1K_ADDR;
+ int tile_base1 = tile_base | ROM_1H_ADDR;
for (int k = 0; k < 8; ++k) {
int y = ((i << 3) | k) * WINDOW_Y_SCALE;
for (int l = 0; l < 8; ++l) {
int data0 = mem[l ^ tile_base0] << (k & 7);
int data1 = mem[l ^ tile_base1] << (k & 7);
- uint32_t rgb = palette[
- mem[
- ((data0 & 0x80) >> 7) | ((data1 & 0x80) >> 6) | palette_base
- ] & 0xf
- ];
+ int colour = mem[
+ ((data0 & 0x80) >> 7) |
+ ((data1 & 0x80) >> 6) |
+ palette_base
+ ]; // approximately bbgggrrr
+ uint32_t rgb =
+ ((((colour & 7) * 0x49) & 0x1fe) << 15) |
+ ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
+ ((((colour & 0xc0) * 0x55) & 0x3fc0) >> 6) |
+ 0xff000000;
int x = ((j << 3) | l) * WINDOW_X_SCALE;
for (int m = 0; m < WINDOW_Y_SCALE; ++m)
for (int n = 0; n < WINDOW_X_SCALE; ++n)
}
}
}
+ }
// draw sprites
// from MAME /src/mame/video/galaxian.cpp:
(!x_flip * 0x17) |
(y_flip * 0x28) |
((data & 0x3f) << 5);
- int sprite_base0 = sprite_base | ROM_1H_ADDR;
- int sprite_base1 = sprite_base | ROM_1K_ADDR;
+ int sprite_base0 = sprite_base | ROM_1K_ADDR;
+ int sprite_base1 = sprite_base | ROM_1H_ADDR;
int palette_base =
((mem[0x42 | (i << 2) | SPRITE_RAM] & 7) << 2) |
ROM_GALAXIAN_CLR_ADDR;
- int x = GALAXIAN_WIDTH + 15 - mem[0x43 | (i << 2) | SPRITE_RAM];
- int y = GALAXIAN_HEIGHT - mem[0x40 | (i << 2) | SPRITE_RAM];
+ int x = mem[0x40 | (i << 2) | SPRITE_RAM] - 16;
+ int y = mem[0x43 | (i << 2) | SPRITE_RAM];
for (int j = 0; j < 16; ++j) {
int y1 = y + j;
if (y1 >= 0 && y1 < GALAXIAN_HEIGHT) {
int data0 = mem[addr ^ sprite_base0] << shift;
int data1 = mem[addr ^ sprite_base1] << shift;
if ((data0 | data1) & 0x80) {
- uint32_t rgb = palette[
- mem[
- ((data0 & 0x80) >> 7) |
- ((data1 & 0x80) >> 6) |
- palette_base
- ] & 0xf
- ];
+ int colour = mem[
+ ((data0 & 0x80) >> 7) |
+ ((data1 & 0x80) >> 6) |
+ palette_base
+ ]; // approximately bbgggrrr
+ uint32_t rgb =
+ ((((colour & 7) * 0x49) & 0x1fe) << 15) |
+ ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
+ ((((colour & 0xc0) * 0x55) & 0x3fc0) >> 6) |
+ 0xff000000;
x1 *= WINDOW_X_SCALE;
for (int l = 0; l < WINDOW_Y_SCALE; ++l)
for (int m = 0; m < WINDOW_X_SCALE; ++m)
int data0 = mem[addr ^ sprite_base0] >> shift;
int data1 = mem[addr ^ sprite_base1] >> shift;
if ((data0 | data1) & 1) {
- uint32_t rgb = palette[
- mem[
- ((data0 & 0x80) >> 7) |
- ((data1 & 0x80) >> 6) |
- palette_base
- ] & 0xf
- ];
+ int colour = mem[
+ (data0 & 1) ^
+ ((data1 & 1) << 1) ^
+ palette_base
+ ]; // approximately bbgggrrr
+ uint32_t rgb =
+ ((((colour & 7) * 0x49) & 0x1fe) << 15) |
+ ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
+ ((((colour & 0xc0) * 0x55) & 0x3fc0) >> 6) |
+ 0xff000000;
x1 *= WINDOW_X_SCALE;
for (int l = 0; l < WINDOW_Y_SCALE; ++l)
for (int m = 0; m < WINDOW_X_SCALE; ++m)
}
#elif PACMAN
// send z80 a vertical refresh interrupt
- cpu.int_pending = true;
- cpu.int_data = int_vector;
+ if (mem[HW_INT_ENABLE] & 1) {
+ cpu.int_pending = true;
+ cpu.int_data = int_vector;
+ }
// draw tiles
for (int i = 0; i < 36; ++i)
0x3a0 - 2 + i - (j << 5) :
0x1d - (34 << 5) + (i << 5) - j;
int tile_base =
- 0xf | (mem[TILE_RAM | offset] << 4) | ROM_PACMAN_5E_ADDR;
+ 0xf | (mem[offset | TILE_RAM] << 4) | ROM_PACMAN_5E_ADDR;
int palette_base =
- ((mem[PALETTE_RAM | offset] & 0x3f) << 2) | ROM_82S126_4A_ADDR;
+ ((mem[offset | PALETTE_RAM] & 0x3f) << 2) | ROM_82S126_4A_ADDR;
for (int k = 0; k < 8; ++k) {
int y = ((i << 3) | k) * WINDOW_Y_SCALE;
for (int l = 0; l < 8; ++l) {
int palette_base =
((mem[1 | (i << 1) | SPRITE_CONFIG] & 0x3f) << 2) |
ROM_82S126_4A_ADDR;
- int x = PACMAN_WIDTH + 15 - sprite_coords[i << 1];
- int y = PACMAN_HEIGHT - 16 - sprite_coords[1 | (i << 1)];
+ int x = PACMAN_WIDTH + 15 - mem[(i << 1) | SPRITE_COORDS];
+ int y = PACMAN_HEIGHT - 16 - mem[1 | (i << 1) | SPRITE_COORDS];
for (int j = 0; j < 16; ++j) {
int y1 = y + j;
if (y1 >= 0 && y1 < PACMAN_HEIGHT) {
--- /dev/null
+; we implement the I/O page as RAM, basically used as communication
+; area between the program and the emulator -- for example, if the
+; joystick moves, the emulator saves the new state in the I/O page,
+; then the program picks it up later using an ordinary memory read
+; this file contains the initial contents, e.g. to set DIP switches
+
+ .area io_page
+
+ ; read
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5000
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5008
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5010
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5018
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5020
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5028
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5030
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5038
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5040
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5048
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5050
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5058
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5060
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5068
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5070
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5078
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5080
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5088
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5090
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5098
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50a0
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50a8
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50b0
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50b8
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50c0
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50c8
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50d0
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50d8
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50e0
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50e8
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50f0
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 50f8
+
+ ; write
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5100 (z80 5000)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5108 (z80 5008)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5110 (z80 5010)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5118 (z80 5018)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5120 (z80 5020)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5128 (z80 5028)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5130 (z80 5030)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5138 (z80 5038)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5140 (z80 5040)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5148 (z80 5048)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5150 (z80 5050)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5158 (z80 5058)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5160 (z80 5060)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5168 (z80 5068)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5170 (z80 5070)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5178 (z80 5078)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5180 (z80 5080)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5188 (z80 5088)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5190 (z80 5090)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 5198 (z80 5098)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51a0 (z80 50a0)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51a8 (z80 50a8)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51b0 (z80 50b0)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51b8 (z80 50b8)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51c0 (z80 50c0)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51c8 (z80 50c8)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51d0 (z80 50d0)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51d8 (z80 50d8)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51e0 (z80 50e0)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51e8 (z80 50e8)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51f0 (z80 50f0)
+ .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 51f8 (z80 50f8)