.area io_page
; read
- .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7800
- .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7808
+ .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7800
+ .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7808
.ds 0x30
; write
- .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7840 (z80 7800)
- .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7848 (z80 7808)
+ .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7840 (z80 7800)
+ .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7848 (z80 7808)
.ds 0x30
.ds 0x380
; read
- .db 0xff ; 7c00
+ .db 0x00 ; 7c00
.ds 0x3f
; write
- .db 0xff ; 7c40 (z80 7c00)
+ .db 0x00 ; 7c40 (z80 7c00)
.ds 0x3f
; read
- .db 0xff ; 7c80
+ .db 0x00 ; 7c80
.ds 0x3f
; write
- .db 0xff ; 7cc0 (z80 7c80)
+ .db 0x00 ; 7cc0 (z80 7c80)
.ds 0x3f
; read
- .db 0xff ; 7d00
+ .db 0x00 ; 7d00
.ds 0x3f
; write
- .db 0xff ; 7d40 (z80 7d00)
+ .db 0x00 ; 7d40 (z80 7d00)
.ds 0x3f
; read
- .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7d80
+ .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7d80
.ds 0x38
; write
- .db 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff ; 7dc0 (z80 7d80)
+ .db 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 ; 7dc0 (z80 7d80)
.ds 0x38
#include "stty_sane.h"
#include "z80/z80.h"
-#define INVADERS 1
+#define DKONG 1
+#define INVADERS 0
#define GALAXIAN 0
#define PACMAN 0
#define APPLE 0
-#if INVADERS
+#if DKONG
+#define DKONG_WIDTH 224
+#define DKONG_HEIGHT 256
+
+#define PADDED_WIDTH DKONG_WIDTH
+#define PADDED_HEIGHT DKONG_HEIGHT
+
+#define WINDOW_X_SCALE 3
+#define WINDOW_Y_SCALE 3
+#elif INVADERS
#define INVADERS_WIDTH 224
#define INVADERS_HEIGHT 256
#define SAMPLES_PER_UPDATE 735 // 60 Hz @ 44100 Hz
#endif
-#if INVADERS
+#if DKONG
+#define RAM_START 0x6000
+#define RAM_SIZE 0x1800
+
+#define SPRITE_RAM 0x6900
+#define TILE_RAM 0x7400
+
+#define IO_START 0x7800
+#define IO_SIZE 0x600
+
+#define HW_INT_ENABLE 0x7dc4 // z80 7d84
+#define HW_PALETTE_A 0x7dc6 // z80 7d86
+#define HW_PALETTE_B 0x7dc7 // z80 7d87
+#elif INVADERS
#define INPUT_PORT0 0
#define INPUT_PORT1 1
#define INPUT_PORT2 2
#define VIDEO_RAM 0x2400
#elif GALAXIAN
#define RAM_START 0x4000
-#define RAM_SIZE 0x1000
+#define RAM_SIZE 0x2000
#define TILE_RAM 0x5000
#define SPRITE_RAM 0x5800
z80 cpu;
-#if INVADERS
+#if DKONG
+#define ROM_C_5ET_G_ADDR 0
+#define ROM_C_5CT_G_ADDR 0x1000
+#define ROM_C_5BT_G_ADDR 0x2000
+#define ROM_C_5AT_G_ADDR 0x3000
+#define ROM_C_2K_2J_ADDR 0x7e00
+#define ROM_V_5E_ADDR 0x7f00
+#define ROM_S_3I_B_ADDR 0x8000
+#define ROM_S_3J_B_ADDR 0x8800
+#define ROM_V_5H_B_ADDR 0xa000
+#define ROM_V_3PT_ADDR 0xa800
+#define ROM_L_4M_B_ADDR 0xb000
+#define ROM_L_4N_B_ADDR 0xb800
+#define ROM_L_4R_B_ADDR 0xc000
+#define ROM_L_4S_B_ADDR 0xc800
+#define MEM_SIZE 0xd000
+#elif INVADERS
#define ROM_INVADERS_H_ADDR 0
#define ROM_INVADERS_G_ADDR 0x800
#define ROM_INVADERS_F_ADDR 0x1000
uint8_t dos_lo;
int usleep_count, exit_flag;
-#if INVADERS
+#if DKONG
+uint8_t int_vector;
+
+// just for now until we have dkong audio
+#define C0X0_SOFT_SWITCH_TAPEOUT 4
+#define C0X0_SOFT_SWITCH_SPKR 8
+uint8_t c0x0_soft_switches = 0;
+
+// every n cycles, sample the tape and speaker outputs to here
+#define C0X0_SOFT_SWITCHES_BUF_SIZE 0x400 // next power of 2 >= 441 * 2
+int c0x0_soft_switches_buf_head;
+int c0x0_soft_switches_buf_count;
+uint8_t c0x0_soft_switches_buf[C0X0_SOFT_SWITCHES_BUF_SIZE];
+#elif INVADERS
uint16_t shift_buffer;
uint8_t shift_count;
}
uint8_t rb(void *userdata, uint16_t addr0) {
-#if INVADERS
+#if DKONG
+ int addr = addr0;
+
+ if (addr < IO_START) { // ROM, RAM
+#if MEM_TRACE
+ int pc = cpu.pc;
+ fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
+#endif
+ return mem[addr];
+ }
+ if (addr < IO_START + IO_SIZE && (addr & 0x40) == 0) { // I/O
+#if MEM_TRACE
+ int pc = cpu.pc;
+ fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
+#endif
+ return mem[addr];
+ }
+#elif INVADERS
int addr = addr0;
if (addr < RAM_START + RAM_SIZE) { // ROM, RAM
#elif PACMAN
int addr = addr0;
- if (addr < IO_START + 0x100) { // ROM, RAM, I/O
+ if (addr < IO_START + IO_SIZE) { // ROM, RAM, I/O
#if MEM_TRACE
int pc = cpu.pc;
fprintf(stderr, "pc=%04x addr=%04x rd=%02x\n", pc, addr, mem[addr]);
}
void wb(void *userdata, uint16_t addr0, uint8_t val) {
-#if INVADERS
+#if DKONG
+ int addr = addr0;
+
+ if (addr < RAM_START) // ROM
+ ;
+ else if (addr < IO_START) { // RAM
+#if MEM_TRACE
+ int pc = cpu.pc;
+ fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
+#endif
+ mem[addr] = val;
+ }
+ else if (addr < IO_START + IO_SIZE && (addr & 0x40) == 0) { // RAM, I/O
+ addr |= 0x40; // separate read and write registers
+#if MEM_TRACE
+ int pc = cpu.pc;
+ fprintf(stderr, "pc=%04x addr=%04x wr=%02x\n", pc, addr, val);
+#endif
+ mem[addr] = val;
+ }
+#elif INVADERS
int addr = addr0;
if (addr < RAM_START) // ROM
if (addr < RAM_START) // ROM
;
- else if (addr < IO_START + 0x100) { // RAM, I/O
+ else if (addr < IO_START + IO_SIZE) { // RAM, I/O
if (addr >= IO_START)
addr += 0x100; // separate read and write registers
#if MEM_TRACE
bool timing = false;
while (argn < argc) {
if (strcmp(argv[argn], "--help") == 0) {
-#if GALAXIAN || PACMAN
+#if DKONG || INVADERS || GALAXIAN || PACMAN
printf("usage: %s [--timing] [program.obj[,aNNNN] ...] [-- child-executable [child-argument ...]]\n", argv[0]);
#else // APPLE
printf("usage: %s [--cg-rom=file.bin] [--video-rom=file.bin] [--NN-rom=file.bin ...] [--timing] [program.obj[,aNNNN] ...] [-- child-executable [child-argument ...]]\n", argv[0]);
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 0xff);
SDL_RenderClear(renderer);
-#if INVADERS
+#if DKONG
+ // send z80 a vertical refresh interrupt
+ if (mem[HW_INT_ENABLE] & 1)
+ z80_gen_nmi(&cpu);
+
+ // draw tiles
+ int palette_base0 =
+ ((mem[HW_PALETTE_A] & 1) << 6) |
+ ((mem[HW_PALETTE_B] & 1) << 7) |
+ ROM_C_2K_2J_ADDR;
+ for (int i = 0; i < 32; ++i)
+ for (int j = 0; j < 28; ++j) {
+ int palette_base1 =
+ ((mem[i | ((j & 0x1c) << 3) | ROM_V_5E_ADDR] & 0xf) << 2) |
+ palette_base0;
+ int tile_base =
+ 7 |
+ (mem[i | ((29 - j) << 5) | TILE_RAM] << 3);
+ int tile_base0 = tile_base | ROM_V_5H_B_ADDR;
+ int tile_base1 = tile_base | ROM_V_3PT_ADDR;
+ for (int k = 0; k < 8; ++k) {
+ int y1 = (k | (i << 3)) * 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);
+ int colour = ~mem[
+ ((data0 & 0x80) >> 7) |
+ ((data1 & 0x80) >> 6) |
+ palette_base1
+ ]; // approximately rrrgggbb
+ uint32_t rgb =
+ ((((colour & 0xe0) * 0x49) & 0x3fc0) << 10) |
+ ((((colour & 0x1c) * 0x49) & 0x7f8) << 5) |
+ ((colour & 3) * 0x55) |
+ 0xff000000;
+ int x1 = (l | (j << 3)) * WINDOW_X_SCALE;
+ for (int m = 0; m < WINDOW_Y_SCALE; ++m)
+ for (int n = 0; n < WINDOW_X_SCALE; ++n)
+ frame[y1 + m][x1 + n] = rgb;
+ }
+ }
+ }
+
+ // draw sprites
+ // from MAME /src/mame/video/galaxian.cpp:
+ // spriteram[0x40] = vertical position of sprite 0
+ // spriteram[0x41] = picture number and H/V flip of sprite 0
+ // spriteram[0x42] = color of sprite 0
+ // spriteram[0x43] = horizontal position of sprite 0
+ // ...
+ // spriteram[0x61] = vertical position of shell 0
+ // spriteram[0x63] = horizontal count until shell 0 starts rendering
+ // ...
+ for (int i = 0x7f; i >= 0; --i) {
+ int data1 = mem[1 | (i << 2) | SPRITE_RAM];
+ int data2 = mem[2 | (i << 2) | SPRITE_RAM];
+ bool x_flip = (data1 >> 7) & 1;
+ bool y_flip = (data2 >> 7) & 1;
+ int sprite_base =
+ (!x_flip * 0xf) |
+ (y_flip * 0x800) |
+ ((data1 & 0x7f) << 4);
+ int shift_flip = y_flip * 7;
+ int sprite_base0 = sprite_base | ROM_L_4M_B_ADDR;
+ int sprite_base1 = sprite_base | ROM_L_4R_B_ADDR;
+ int palette_base1 = ((data2 & 0xf) << 2) | palette_base0;
+ int x = mem[(i << 2) | SPRITE_RAM] - 23;
+ int y = mem[3 | (i << 2) | SPRITE_RAM] - 8;
+ for (int j = 0; j < 16; ++j) {
+ int y1 = y + j;
+ if (y1 >= 0 && y1 < DKONG_HEIGHT) {
+ y1 *= WINDOW_Y_SCALE;
+ for (int k = 0; k < 16; ++k) {
+ int x1 = x + k;
+ if (x1 >= 0 && x1 < DKONG_WIDTH) {
+ int addr = k ^ ((j & 8) << 8);
+ int shift = (j & 7) ^ shift_flip;
+ int data0 = mem[addr ^ sprite_base0] << shift;
+ int data1 = mem[addr ^ sprite_base1] << shift;
+ if ((data0 | data1) & 0x80) {
+ int colour = ~mem[
+ ((data0 & 0x80) >> 7) |
+ ((data1 & 0x80) >> 6) |
+ palette_base1
+ ]; // approximately rrrgggbb
+ uint32_t rgb =
+ ((((colour & 0xe0) * 0x49) & 0x3fc0) << 10) |
+ ((((colour & 0x1c) * 0x49) & 0x7f8) << 5) |
+ ((colour & 3) * 0x55) |
+ 0xff000000;
+ //rgb = 0xff808080 + i * 0x101010;
+ x1 *= WINDOW_X_SCALE;
+ for (int l = 0; l < WINDOW_Y_SCALE; ++l)
+ for (int m = 0; m < WINDOW_X_SCALE; ++m)
+ frame[y1 + l][x1 + m] = rgb;
+ }
+ }
+ }
+ }
+ }
+ }
+#elif INVADERS
// send z80 a vertical refresh interrupt
int j0, j1;
if (frame_half == false) {
bool y_flip = (data >> 7) & 1;
int sprite_base =
(!x_flip * 0x17) |
- (y_flip * 0x28) |
+ (y_flip * 8) |
((data & 0x3f) << 5);
+ int shift_flip = y_flip * 7;
int sprite_base0 = sprite_base | ROM_1K_ADDR;
int sprite_base1 = sprite_base | ROM_1H_ADDR;
int palette_base =
for (int k = 0; k < 16; ++k) {
int x1 = x + k;
if (x1 >= 0 && x1 < GALAXIAN_WIDTH) {
- if (!y_flip) {
- int addr = (k & 7) ^ (j & 8) ^ ((k & 8) << 1);
- int shift = j & 7;
- int data0 = mem[addr ^ sprite_base0] << shift;
- int data1 = mem[addr ^ sprite_base1] << shift;
- if ((data0 | data1) & 0x80) {
- 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) >> 6) | // 0x3fc0 >> 6
- 0xff000000;
- //rgb = 0xff808080 + i * 0x101010;
- x1 *= WINDOW_X_SCALE;
- for (int l = 0; l < WINDOW_Y_SCALE; ++l)
- for (int m = 0; m < WINDOW_X_SCALE; ++m)
- frame[y1 + l][x1 + m] = rgb;
- }
- }
- else {
- int addr = (k & 7) ^ (j & 8) ^ ((k & 8) << 1);
- int shift = j & 7;
- int data0 = mem[addr ^ sprite_base0] >> shift;
- int data1 = mem[addr ^ sprite_base1] >> shift;
- if ((data0 | data1) & 1) {
- 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) >> 6) | // 0x3fc0 >> 6
- 0xff000000;
+ int addr = (k & 7) ^ (j & 8) ^ ((k & 8) << 1);
+ int shift = (j & 7) ^ shift_flip;
+ int data0 = mem[addr ^ sprite_base0] << shift;
+ int data1 = mem[addr ^ sprite_base1] << shift;
+ if ((data0 | data1) & 0x80) {
+ 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) >> 6) | // 0x3fc0 >> 6
+ 0xff000000;
//rgb = 0xff808080 + i * 0x101010;
- x1 *= WINDOW_X_SCALE;
- for (int l = 0; l < WINDOW_Y_SCALE; ++l)
- for (int m = 0; m < WINDOW_X_SCALE; ++m)
- frame[y1 + l][x1 + m] = rgb;
- }
+ x1 *= WINDOW_X_SCALE;
+ for (int l = 0; l < WINDOW_Y_SCALE; ++l)
+ for (int m = 0; m < WINDOW_X_SCALE; ++m)
+ frame[y1 + l][x1 + m] = rgb;
}
}
}
(y_flip * 0x18) |
((data & 0xfc) << 4) |
ROM_PACMAN_5F_ADDR;
+ int y_cycle = 4 - (y_flip << 3);
+ int shift_flip = y_flip * 3;
int palette_base =
((mem[1 | (i << 1) | SPRITE_CONFIG] & 0x3f) << 2) |
ROM_82S126_4A_ADDR;
for (int k = 0; k < 16; ++k) {
int x1 = x + k;
if (x1 >= 0 && x1 < PACMAN_WIDTH) {
- if (!y_flip) {
- int data = mem[
- (k & 7) ^
- (((j + 4) & 0xc) << 1) ^
- ((k & 8) << 2) ^
- sprite_base
- ] << (j & 3);
- int colour = mem[
- ((data & 8) >> 3) |
- ((data & 0x80) >> 6) |
- palette_base
- ] & 0x1f; // first stage lookup
- if (colour) {
- colour = mem[
- colour | ROM_82S123_7F_ADDR
- ]; // second stage lookup, approximately bbgggrrr
- uint32_t rgb =
- ((((colour & 7) * 0x49) & 0x1fe) << 15) |
- ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
- (((colour & 0xc0) * 0x55) >> 6) | // 0x3fc0 >> 6
- 0xff000000;
- //rgb = 0xff808080 + i * 0x101010;
- x1 *= WINDOW_X_SCALE;
- for (int l = 0; l < WINDOW_Y_SCALE; ++l)
- for (int m = 0; m < WINDOW_X_SCALE; ++m)
- frame[y1 + l][x1 + m] = rgb;
- }
- }
- else {
- int data = mem[
- (k & 7) ^
- (((j - 4) & 0xc) << 1) ^
- ((k & 8) << 2) ^
- sprite_base
- ] >> (j & 3);
- int colour = mem[
- (data & 1) |
- ((data & 0x10) >> 3) |
- palette_base
- ] & 0x1f; // first stage lookup
- if (colour) {
- colour = mem[
- colour | ROM_82S123_7F_ADDR
- ]; // second stage lookup, approximately bbgggrrr
- uint32_t rgb =
- ((((colour & 7) * 0x49) & 0x1fe) << 15) |
- ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
- (((colour & 0xc0) * 0x55) >> 6) | // 0x3fc0 >> 6
- 0xff000000;
+ int data = mem[
+ (k & 7) ^
+ (((j + y_cycle) & 0xc) << 1) ^
+ ((k & 8) << 2) ^
+ sprite_base
+ ] << ((j & 3) ^ shift_flip);
+ int colour = mem[
+ ((data & 8) >> 3) |
+ ((data & 0x80) >> 6) |
+ palette_base
+ ] & 0x1f; // first stage lookup
+ if (colour) {
+ colour = mem[
+ colour | ROM_82S123_7F_ADDR
+ ]; // second stage lookup, approximately bbgggrrr
+ uint32_t rgb =
+ ((((colour & 7) * 0x49) & 0x1fe) << 15) |
+ ((((colour & 0x38) * 0x49) & 0xff0) << 4) |
+ (((colour & 0xc0) * 0x55) >> 6) | // 0x3fc0 >> 6
+ 0xff000000;
//rgb = 0xff808080 + i * 0x101010;
- x1 *= WINDOW_X_SCALE;
- for (int l = 0; l < WINDOW_Y_SCALE; ++l)
- for (int m = 0; m < WINDOW_X_SCALE; ++m)
- frame[y1 + l][x1 + m] = rgb;
- }
+ x1 *= WINDOW_X_SCALE;
+ for (int l = 0; l < WINDOW_Y_SCALE; ++l)
+ for (int m = 0; m < WINDOW_X_SCALE; ++m)
+ frame[y1 + l][x1 + m] = rgb;
}
}
}