45 #define DISK_IMAGE_SIZE 819200
62 #define CPU_PORT_DEFAULT_VALUE0 0xFF
63 #define CPU_PORT_DEFAULT_VALUE1 0xFF
65 #define BASIC_ROM_OFFSET 0x10000
66 #define KERNAL_ROM_OFFSET 0x12000
67 #define CHAR_ROM_OFFSET 0x14000
68 #define IO_OFFSET 0x15000
71 #define IO_VIRT_ADDR (memory + IO_OFFSET)
73 #define MAP_RAM memory
74 #define MAP_BASIC memory + BASIC_ROM_OFFSET - 0xA000
75 #define MAP_KERNAL memory + KERNAL_ROM_OFFSET - 0xE000
76 #define MAP_CHRROM memory + CHAR_ROM_OFFSET - 0xD000
77 #define MAP_IO memory + IO_OFFSET - 0xD000
78 #define MAP_RAM_TWICE MAP_RAM,MAP_RAM
79 #define MAP_RAM_10_TIMES MAP_RAM_TWICE,MAP_RAM_TWICE,MAP_RAM_TWICE,MAP_RAM_TWICE,MAP_RAM_TWICE
80 #define MAP_BASIC_TWICE MAP_BASIC,MAP_BASIC
81 #define MAP_KERNAL_TWICE MAP_KERNAL,MAP_KERNAL
83 #define KERNAL_PATCH_ADDR 0xE388
84 #define PATCH_P memory[KERNAL_PATCH_ADDR - 0xE000 + KERNAL_ROM_OFFSET]
85 #define PATCH_OLD_BYTE 0x6C
86 #define PATCH_NEW_BYTE CPU65_TRAP_OPCODE
89 static Uint8 *memcfgs[8][2][16] = {
93 {{
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_RAM,
MAP_RAM_TWICE }, {
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_RAM,
MAP_RAM_TWICE }},
94 {{
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_CHRROM,
MAP_RAM_TWICE }, {
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_RAM,
MAP_RAM_TWICE }},
95 {{
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_CHRROM,
MAP_KERNAL_TWICE }, {
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_RAM,
MAP_RAM_TWICE }},
96 {{
MAP_RAM_10_TIMES,
MAP_BASIC_TWICE,
MAP_RAM,
MAP_CHRROM,
MAP_KERNAL_TWICE }, {
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_RAM,
MAP_RAM_TWICE }},
97 {{
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_RAM,
MAP_RAM_TWICE }, {
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_RAM,
MAP_RAM_TWICE }},
98 {{
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_IO,
MAP_RAM_TWICE }, {
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_IO,
MAP_RAM_TWICE }},
99 {{
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_IO,
MAP_KERNAL_TWICE }, {
MAP_RAM_10_TIMES,
MAP_RAM_TWICE,
MAP_RAM,
MAP_IO,
MAP_RAM_TWICE }},
103 #define GET_READ_P(a) (memcfgs[cpu_port_memconfig][0][(a)>>12] + (a))
104 #define GET_WRITE_P(a) (memcfgs[cpu_port_memconfig][1][(a)>>12] + (a))
105 #define IS_P_IO(p) ((p) >= IO_VIRT_ADDR)
107 static const char *rom_fatal_msg =
"This is one of the selected ROMs. Without it, Xemu won't work.\nInstall it, or use -romXXX CLI switches to specify another path, see the -h output for help.";
109 static const char *memconfig_descriptions[8] = {
110 "ALL RAM [v1]",
"CHAR+RAM",
"CHAR+KERNAL",
"ALL *ROM*",
111 "ALL RAM [v2]",
"IO+RAM",
"IO+KERNAL",
"BASIC+IO+KERNAL"
115 static int vic2_16k_bank;
118 static Uint8 vic2_registers[0x40];
119 static int cpu_port_memconfig = 7;
120 static Uint32 palette[16];
121 static int compare_raster;
122 static int vic2_interrupt_status;
123 static Uint8 *vic2_sprite_pointers;
125 static int geos_loaded = 0;
126 static int nmi_level;
129 static const Uint8 init_vic2_palette_rgb[16 * 3] = {
154 #define CHECK_PIXEL_POINTER
156 #ifdef CHECK_PIXEL_POINTER
158 static Uint32 *pixel_pointer_check_base;
159 static Uint32 *pixel_pointer_check_end;
160 static const char *pixel_pointer_check_modn;
161 static inline void PIXEL_POINTER_CHECK_INIT(
Uint32 *
base,
int tail,
const char *module )
163 pixel_pointer_check_base =
base;
164 pixel_pointer_check_end =
base + (320 + tail) * 200;
165 pixel_pointer_check_modn = module;
167 static inline void PIXEL_POINTER_CHECK_ASSERT (
Uint32 *p )
169 if (p < pixel_pointer_check_base)
170 FATAL(
"FATAL ASSERT: accessing texture (%p) under the base limit (%p).\nIn program module: %s", p, pixel_pointer_check_base, pixel_pointer_check_modn);
171 if (p >= pixel_pointer_check_end)
172 FATAL(
"FATAL ASSERT: accessing texture (%p) above the upper limit (%p).\nIn program module: %s", p, pixel_pointer_check_end, pixel_pointer_check_modn);
174 static inline void PIXEL_POINTER_FINAL_ASSERT (
Uint32 *p )
176 if (p != pixel_pointer_check_end)
177 FATAL(
"FATAL ASSERT: final texture pointer (%p) is not the same as the desired one (%p),\nIn program module %s", p, pixel_pointer_check_end, pixel_pointer_check_modn);
180 # define PIXEL_POINTER_CHECK_INIT(base,tail,mod)
181 # define PIXEL_POINTER_CHECK_ASSERT(p)
182 # define PIXEL_POINTER_FINAL_ASSERT(p)
189 static void vic2_interrupt_checker (
void )
191 int vic_irq_old = cpu65.irqLevel & 2;
193 if (vic2_interrupt_status & vic2_registers[0x1A]) {
194 vic2_interrupt_status |= 128;
197 vic2_interrupt_status &= 127;
200 if (vic_irq_old != vic_irq_new) {
201 DEBUG(
"VIC2: interrupt change %s -> %s" NL, vic_irq_old ?
"active" :
"inactive", vic_irq_new ?
"active" :
"inactive");
205 cpu65.irqLevel &= ~2;
219 if (scanline == compare_raster)
220 vic2_interrupt_status |= 1;
222 vic2_interrupt_status &= 0xFE;
223 vic2_interrupt_checker();
238 compare_raster = (compare_raster & 0xFF) | ((
data & 128) ? 0x100 : 0);
239 DEBUG(
"VIC2: compare raster is now %d" NL, compare_raster);
242 compare_raster = (compare_raster & 0xFF00) |
data;
243 DEBUG(
"VIC2: compare raster is now %d" NL, compare_raster);
246 vic2_interrupt_status = vic2_interrupt_status & (~
data) & 15;
247 vic2_interrupt_checker();
250 vic2_registers[0x1A] &= 15;
264 result = (vic2_registers[0x11] & 0x7F) | ((scanline & 256) ? 0x80 : 0);
267 result = scanline & 0xFF;
270 result = vic2_registers[
addr] | (128 + 64);
273 result = vic2_interrupt_status | (64 + 32 + 16);
276 result = vic2_registers[
addr] | 0xF0;
279 result = vic2_registers[
addr] | 1;
282 result = vic2_registers[
addr];
287 DEBUG(
"VIC2: read reg $%02X with result $%02X" NL,
addr, result);
297 static inline void vic2_render_screen_text (
Uint32 *p,
int tail )
301 int x = 0,
y = 0, charline = 0;
307 vidp =
memory + ((vic2_registers[0x18] & 0xF0) << 6) + vic2_16k_bank;
308 vic2_sprite_pointers = vidp + 1016;
310 bg = palette[vic2_registers[0x21] & 15];
311 PIXEL_POINTER_CHECK_INIT(p, tail,
"vic2_render_screen_text");
313 Uint8 chrdata = chrg[((*(vidp++)) << 3) + charline];
314 Uint8 coldata = *(colp++);
315 Uint32 fg = palette[coldata & 15];
317 PIXEL_POINTER_CHECK_ASSERT(p + 7);
318 *(p++) = chrdata & 128 ? fg : bg;
319 *(p++) = chrdata & 64 ? fg : bg;
320 *(p++) = chrdata & 32 ? fg : bg;
321 *(p++) = chrdata & 16 ? fg : bg;
322 *(p++) = chrdata & 8 ? fg : bg;
323 *(p++) = chrdata & 4 ? fg : bg;
324 *(p++) = chrdata & 2 ? fg : bg;
325 *(p++) = chrdata & 1 ? fg : bg;
342 PIXEL_POINTER_FINAL_ASSERT(p);
349 static inline void vic2_render_screen_bmm (
Uint32 *p,
int tail )
351 int x = 0,
y = 0, charline = 0;
353 vidp =
memory + ((vic2_registers[0x18] & 0xF0) << 6) + vic2_16k_bank;
354 vic2_sprite_pointers = vidp + 1016;
355 chrp =
memory + ((vic2_registers[0x18] & 8) ? 8192 : 0) + vic2_16k_bank;
356 PIXEL_POINTER_CHECK_INIT(p, tail,
"vic2_render_screen_bmm");
363 PIXEL_POINTER_CHECK_ASSERT(p);
364 p[0] =
data & 128 ? fg : bg;
365 p[1] =
data & 64 ? fg : bg;
366 p[2] =
data & 32 ? fg : bg;
367 p[3] =
data & 16 ? fg : bg;
368 p[4] =
data & 8 ? fg : bg;
369 p[5] =
data & 4 ? fg : bg;
370 p[6] =
data & 2 ? fg : bg;
371 p[7] =
data & 1 ? fg : bg;
390 PIXEL_POINTER_FINAL_ASSERT(p);
393 #define SPRITE_X_START_SCREEN 24
394 #define SPRITE_Y_START_SCREEN 50
406 static void vic2_render_sprite (
int sprite_no,
int sprite_mask,
Uint8 *
data,
Uint32 *p,
int tail )
409 int sprite_x = ((vic2_registers[sprite_no * 2] | ((vic2_registers[16] & sprite_mask) ? 0x100 : 0)) -
SPRITE_X_START_SCREEN) * 1;
410 Uint32 colour = palette[vic2_registers[39 + sprite_no] & 15];
411 int expand_x = vic2_registers[29] & sprite_mask;
412 int expand_y = vic2_registers[23] & sprite_mask;
413 int lim_y = sprite_y + ((expand_y) ? 42 : 21);
415 p += (320 + tail) * sprite_y;
416 for (
y = sprite_y;
y < lim_y;
y += (expand_y ? 2 : 1), p += (320 + tail) * (expand_y ? 2 : 1))
417 if (y < 0 || y >= 200)
420 int mask, a,
x = sprite_x;
421 for (a = 0; a < 3; a++) {
424 if (
x >= 0 &&
x < 320) {
426 if (expand_y &&
y < 200)
430 if (expand_x &&
x >= 0 &&
x < 320) {
432 if (expand_y &&
y < 200)
437 x += expand_x ? 2 : 1;
457 int sprites = vic2_registers[0x15];
458 if (vic2_registers[0x11] & 32)
459 vic2_render_screen_bmm(p_sdl, tail_sdl);
461 vic2_render_screen_text(p_sdl, tail_sdl);
464 for (a = 7; a >= 0; a--) {
467 vic2_render_sprite(a,
mask,
memory + vic2_16k_bank + (vic2_sprite_pointers[a] << 6), p_sdl, tail_sdl);
475 static void cia1_setint_cb (
int level )
477 DEBUG(
"%s: IRQ level changed to %d" NL, cia1.name, level);
481 cpu65.irqLevel &= ~1;
485 static inline void nmi_set (
int level,
int mask )
497 nmi_new_level = nmi_level |
mask;
499 nmi_new_level = nmi_level & (~
mask);
500 if ((!nmi_level) && nmi_new_level) {
501 DEBUG(
"NMI edge is emulated towards the CPU (%d->%d)" NL, nmi_level, nmi_new_level);
504 nmi_level = nmi_new_level;
508 static void cia2_setint_cb (
int level )
520 static Uint8 cia1_in_b (
void )
522 return c64_keyboard_read_on_CIA1_B(
523 cia1.PRA | (~cia1.DDRA),
524 cia1.PRB | (~cia1.DDRB),
530 static Uint8 cia1_in_a (
void )
532 return c64_keyboard_read_on_CIA1_A(
533 cia1.PRB | (~cia1.DDRB),
534 cia1.PRA | (~cia1.DDRA),
543 DEBUG(
"VIC2: 16K BANK is set to $%04X (CIA mask=$%02X)" NL, vic2_16k_bank,
cia2.
DDRA);
549 static Uint8 cia_port_in_dummy (
void )
560 if (cpu_port_memconfig == (
data & 7))
561 DEBUG(
"MEM: memory configuration is the SAME: %d %s @ PC = $%04X" NL, cpu_port_memconfig, memconfig_descriptions[cpu_port_memconfig], cpu65.pc);
563 DEBUG(
"MEM: memory configuration is CHANGED : %d %s (from %d %s) @ PC = $%02X" NL,
564 data & 7, memconfig_descriptions[
data & 7],
565 cpu_port_memconfig, memconfig_descriptions[cpu_port_memconfig],
568 cpu_port_memconfig =
data & 7;
574 static void geosemu_init (
void )
596 FATAL(
"FATAL: ROM problem, patching point does not contain the expected value!");
600 memset(vic2_registers, 0,
sizeof vic2_registers);
603 vic2_interrupt_status = 0;
628 DEBUG(
"INIT: end of initialization!" NL);
635 DEBUG(
"IO: reading $%04X @ PC=$%04X" NL,
addr, cpu65.pc);
653 DEBUG(
"IO: writing $%04X with $%02X @ PC=$%04X" NL,
addr,
data, cpu65.pc);
682 FATAL(
"FATAL: CPU trap at unknown address in warp mode (pre-GEOS loading) PC=$%04X OP=$%02X" NL, cpu65.pc, opcode);
683 if (pc_p >=
memory + 0x10000)
684 FATAL(
"FATAL: unknown CPU trap not in the RAM PC=$%04X OP=$%02X" NL, cpu65.pc, opcode);
685 if (geos_loaded != 2)
686 FATAL(
"FATAL: unknown CPU without GEOS loaded PC=$%04X OP=$%02X" NL, cpu65.pc, opcode);
711 ERROR_WINDOW(
"Unemulated NMOS 6502 opcode $%02X at PC=$%04X", cpu65.op, cpu65.pc - 1);
752 cpu_port_write(
addr, new_data);
757 static void shutdown_callback (
void )
759 DEBUG(
"SHUTDOWN: @ PC=$%04X" NL, cpu65.pc);
767 if (key == SDL_SCANCODE_F10) {
773 }
else if (key == SDL_SCANCODE_KP_ENTER)
780 static void update_emulator (
void )
797 int main (
int argc,
char **argv )
821 init_vic2_palette_rgb,
844 vic2_registers[0] = 80;
845 vic2_registers[1] = 80;
846 vic2_registers[16] = 0;
847 vic2_registers[21] = 0xFF;
852 if (scanline == 312) {