Skip to content

Commit

Permalink
MEGA65: MEGA65-compliant palette handling finally
Browse files Browse the repository at this point in the history
  • Loading branch information
lgblgblgb committed Jul 16, 2020
1 parent 3b17903 commit 95c8168
Show file tree
Hide file tree
Showing 7 changed files with 315 additions and 88 deletions.
2 changes: 1 addition & 1 deletion targets/mega65/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ TARGET = mega65
PRG_TARGET = xmega65
EMU_DESCRIPTION = MEGA65

SRCS_TARGET_xmega65 = mega65.c sdcard.c uart_monitor.c hypervisor.c m65_snapshot.c memory_mapper.c io_mapper.c vic4.c ethernet65.c input_devices.c memcontent.c ui.c fat32.c sdcontent.c inject.c
SRCS_TARGET_xmega65 = mega65.c sdcard.c uart_monitor.c hypervisor.c m65_snapshot.c memory_mapper.c io_mapper.c vic4.c vic4_palette.c ethernet65.c input_devices.c memcontent.c ui.c fat32.c sdcontent.c inject.c
SRCS_COMMON_xmega65 = emutools.c cpu65.c cia6526.c emutools_hid.c sid.c f011_core.c f018_core.c c64_kbd_mapping.c emutools_config.c emutools_snapshot.c emutools_files.c emutools_umon.c ethertap.c d81access.c emutools_gui.c basic_text.c
CFLAGS_TARGET_xmega65 = $(SDL2_CFLAGS) $(MATH_CFLAGS) $(SOCKET_CFLAGS) $(XEMUGUI_CFLAGS)
LDFLAGS_TARGET_xmega65 = $(SDL2_LIBS) $(MATH_LIBS) $(SOCKET_LIBS) $(XEMUGUI_LIBS)
Expand Down
20 changes: 16 additions & 4 deletions targets/mega65/io_mapper.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* A work-in-progess MEGA65 (Commodore 65 clone origins) emulator
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
I/O decoding part (used by memory_mapper.h and DMA mainly)
Copyright (C)2016-2018 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
Copyright (C)2016-2020 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -25,6 +25,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "xemu/emutools_hid.h"
//#include "xemu/cpu65.h"
#include "vic4.h"
#include "vic4_palette.h"
#include "sdcard.h"
#include "hypervisor.h"
#include "ethernet65.h"
Expand Down Expand Up @@ -123,10 +124,13 @@ Uint8 io_read ( unsigned int addr )
case 0x11: // $D100-$D1FF ~ C65 I/O mode
case 0x12: // $D200-$D2FF ~ C65 I/O mode
case 0x13: // $D300-$D3FF ~ C65 I/O mode
return 0xFF; // FIXME: AFAIK C65 does not allow to read palette register back, however M65 I/O mode does allow (?)
case 0x31: // $D100-$D1FF ~ M65 I/O mode
return vic4_read_palette_reg_red(addr); // function takes care using only 8 low bits of addr, no need to do here
case 0x32: // $D200-$D2FF ~ M65 I/O mode
return vic4_read_palette_reg_green(addr);
case 0x33: // $D300-$D3FF ~ M65 I/O mode
return 0xFF; // FIXME: check, if applies: palette register entries are write-only, in both of C65 and M65 modes??
return vic4_read_palette_reg_blue(addr);
/* ------------------------------------------------ */
/* $D400-$D7FF: SID, SID+UART+DMA, SID+UART+DMA+M65 */
/* ------------------------------------------------ */
Expand Down Expand Up @@ -314,14 +318,22 @@ void io_write ( unsigned int addr, Uint8 data )
}
RETURN_ON_IO_WRITE_NOT_IMPLEMENTED("RAM expansion controller");
case 0x11: // $D100-$D1FF ~ C65 I/O mode
vic3_write_palette_reg_red(addr, data); // function takes care using only 8 low bits of addr, no need to do here
return;
case 0x12: // $D200-$D2FF ~ C65 I/O mode
vic3_write_palette_reg_green(addr, data);
return;
case 0x13: // $D300-$D3FF ~ C65 I/O mode
vic3_write_palette_reg(addr - 0x1100, data);
vic3_write_palette_reg_blue(addr, data);
return;
case 0x31: // $D100-$D1FF ~ M65 I/O mode
vic4_write_palette_reg_red(addr, data);
return;
case 0x32: // $D200-$D2FF ~ M65 I/O mode
vic4_write_palette_reg_green(addr, data);
return;
case 0x33: // $D300-$D3FF ~ M65 I/O mode
vic4_write_palette_reg(addr - 0x3100, data);
vic4_write_palette_reg_blue(addr, data);
return;
/* ------------------------------------------------ */
/* $D400-$D7FF: SID, SID+UART+DMA, SID+UART+DMA+M65 */
Expand Down
6 changes: 3 additions & 3 deletions targets/mega65/io_mapper.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* A work-in-progess MEGA65 (Commodore-65 clone origins) emulator
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
Copyright (C)2016-2018 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
Copyright (C)2016-2020 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -16,8 +16,8 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

#ifndef __XEMU_MEGA65_IO_MAPPER_H_INCLUDED
#define __XEMU_MEGA65_IO_MAPPER_H_INCLUDED
#ifndef XEMU_MEGA65_IO_MAPPER_H_INCLUDED
#define XEMU_MEGA65_IO_MAPPER_H_INCLUDED

#include "xemu/cia6526.h"
#include "xemu/sid.h"
Expand Down
108 changes: 33 additions & 75 deletions targets/mega65/vic4.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* A work-in-progess MEGA65 (Commodore 65 clone origins) emulator
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
Copyright (C)2016,2017 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
Copyright (C)2016-2020 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
This is the VIC-IV "emulation". Currently it does one-frame-at-once
kind of horrible work, and only a subset of VIC2 and VIC3 knowledge
Expand Down Expand Up @@ -30,18 +30,20 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mega65.h"
#include "xemu/cpu65.h"
#include "vic4.h"
#include "vic4_palette.h"
#include "memory_mapper.h"

#define RGB(r,g,b) rgb_palette[((r) << 8) | ((g) << 4) | (b)]
//#define RGB(r,g,b) rgb_palette[((r) << 8) | ((g) << 4) | (b)]

static const char *iomode_names[4] = { "VIC2", "VIC3", "BAD!", "VIC4" };

static Uint32 rgb_palette[4096]; // all the C65 palette, 4096 colours (SDL pixel format related form)
static Uint32 vic3_palette[0x100]; // VIC3 palette in SDL pixel format related form (can be written into the texture directly to be rendered)
static Uint32 vic3_rom_palette[0x100]; // the "ROM" palette, for C64 colours (with some ticks, ie colours above 15 are the same as the "normal" programmable palette)
static Uint32 *palette; // the selected palette ...
static Uint8 vic3_palette_nibbles[0x300];
Uint8 vic_registers[0x80]; // VIC-3 registers. It seems $47 is the last register. But to allow address the full VIC3 reg I/O space, we use $80 here
//static Uint32 rgb_palette[4096]; // all the C65 palette, 4096 colours (SDL pixel format related form)
//static Uint32 vic3_palette[0x100]; // VIC3 palette in SDL pixel format related form (can be written into the texture directly to be rendered)
//static Uint32 vic3_rom_palette[0x100]; // the "ROM" palette, for C64 colours (with some ticks, ie colours above 15 are the same as the "normal" programmable palette)
//static Uint32 *palette; // the selected palette ...
//static Uint8 vic3_palette_nibbles[0x300];

Uint8 vic_registers[0x80]; // VIC-4 registers
int vic_iomode; // VIC2/VIC3/VIC4 mode
int force_fast; // POKE 0,64 and 0,65 trick ...
int scanline; // current scan line number
Expand Down Expand Up @@ -104,54 +106,25 @@ static inline void PIXEL_POINTER_FINAL_ASSERT ( Uint32 *p )

void vic_init ( void )
{
int r, g, b, i;
// *** Init 4096 element palette with RGB components for faster access later on palette register changes (avoid SDL calls to convert)
// TODO: for M65 mode, where a colour component is 8 bit, this is kind of problematic though :(
for (r = 0, i = 0; r < 16; r++)
for (g = 0; g < 16; g++)
for (b = 0; b < 16; b++)
rgb_palette[i++] = SDL_MapRGBA(sdl_pix_fmt, r * 17, g * 17, b * 17, 0xFF); // 15*17=255, last arg 0xFF: alpha channel for SDL
vic4_init_palette();
force_fast = 0;
// *** Init VIC3 registers and palette
vic2_16k_bank = 0;
vic_iomode = VIC2_IOMODE;
interrupt_status = 0;
palette = vic3_rom_palette;
// FIXME: add ROM palette by default? What is ROM palette on MEGA65?
scanline = 0;
compare_raster = 0;
for (i = 0; i < 0x100; i++) { // Initiailize all palette registers to zero, initially, to have something ...
if (i < sizeof vic_registers)
vic_registers[i] = 0; // Also the VIC registers ...
vic3_rom_palette[i] = vic3_palette[i] = rgb_palette[0];
vic3_palette_nibbles[i] = 0;
vic3_palette_nibbles[i + 0x100] = 0;
vic3_palette_nibbles[i + 0x200] = 0;
}
// *** the ROM palette "fixed" colours
vic3_rom_palette[ 0] = RGB( 0, 0, 0); // black
vic3_rom_palette[ 1] = RGB(15, 15, 15); // white
vic3_rom_palette[ 2] = RGB(15, 0, 0); // red
vic3_rom_palette[ 3] = RGB( 0, 15, 15); // cyan
vic3_rom_palette[ 4] = RGB(15, 0, 15); // magenta
vic3_rom_palette[ 5] = RGB( 0, 15, 0); // green
vic3_rom_palette[ 6] = RGB( 0, 0, 15); // blue
vic3_rom_palette[ 7] = RGB(15, 15, 0); // yellow
vic3_rom_palette[ 8] = RGB(15, 6, 0); // orange
vic3_rom_palette[ 9] = RGB(10, 4, 0); // brown
vic3_rom_palette[10] = RGB(15, 7, 7); // pink
vic3_rom_palette[11] = RGB( 5, 5, 5); // dark grey
vic3_rom_palette[12] = RGB( 8, 8, 8); // medium grey
vic3_rom_palette[13] = RGB( 9, 15, 9); // light green
vic3_rom_palette[14] = RGB( 9, 9, 15); // light blue
vic3_rom_palette[15] = RGB(11, 11, 11); // light grey
// *** Just a check to try all possible regs (in VIC2,VIC3 and VIC4 modes), it should not panic ...
// It may also sets/initializes some internal variables sets by register writes, which would cause a crash on screen rendering without prior setup!
for (i = 0; i < 0x140; i++) {
for (int i = 0; i < 0x140; i++) { // $140=the last $40 register for VIC-2 mode, when we have fewer ones
vic_write_reg(i, 0);
(void)vic_read_reg(i);
}
c128_d030_reg = 0xFE; // this may be set to 2MHz in the previous step, so be sure to set to FF here, BUT FIX: bit 0 should be inverted!!
machine_set_speed(0);
//vic_registers[0x30] = 4; // ROM palette?
//palette = vic_palettes + 0x400;
DEBUG("VIC4: has been initialized." NL);
}

Expand Down Expand Up @@ -303,7 +276,7 @@ void vic_write_reg ( unsigned int addr, Uint8 data )
/* --- NO MORE VIC-II REGS FROM HERE --- */
CASE_VIC_3_4(0x30):
memory_set_vic3_rom_mapping(data);
palette = (data & 4) ? vic3_palette : vic3_rom_palette;
check_if_rom_palette(data & 4);
break;
CASE_VIC_3_4(0x31):
vic_registers[0x31] = data; // we need this work-around, since reg-write happens _after_ this switch statement, but machine_set_speed above needs it ...
Expand All @@ -329,7 +302,7 @@ void vic_write_reg ( unsigned int addr, Uint8 data )
CASE_VIC_4(0x55): CASE_VIC_4(0x56): CASE_VIC_4(0x57): CASE_VIC_4(0x58): CASE_VIC_4(0x59): CASE_VIC_4(0x5A): CASE_VIC_4(0x5B): CASE_VIC_4(0x5C):
CASE_VIC_4(0x5D): CASE_VIC_4(0x5E): CASE_VIC_4(0x5F): /*CASE_VIC_4(0x60): CASE_VIC_4(0x61): CASE_VIC_4(0x62): CASE_VIC_4(0x63):*/ CASE_VIC_4(0x64):
CASE_VIC_4(0x65): CASE_VIC_4(0x66): CASE_VIC_4(0x67): /*CASE_VIC_4(0x68): CASE_VIC_4(0x69): CASE_VIC_4(0x6A):*/ CASE_VIC_4(0x6B): /*CASE_VIC_4(0x6C):
CASE_VIC_4(0x6D): CASE_VIC_4(0x6E):*/ CASE_VIC_4(0x6F): CASE_VIC_4(0x70): CASE_VIC_4(0x71): CASE_VIC_4(0x72): CASE_VIC_4(0x73): CASE_VIC_4(0x74):
CASE_VIC_4(0x6D): CASE_VIC_4(0x6E):*/ CASE_VIC_4(0x6F): /*CASE_VIC_4(0x70):*/ CASE_VIC_4(0x71): CASE_VIC_4(0x72): CASE_VIC_4(0x73): CASE_VIC_4(0x74):
CASE_VIC_4(0x75): CASE_VIC_4(0x76): CASE_VIC_4(0x77): CASE_VIC_4(0x78): CASE_VIC_4(0x79): CASE_VIC_4(0x7A): CASE_VIC_4(0x7B): CASE_VIC_4(0x7C):
CASE_VIC_4(0x7D): CASE_VIC_4(0x7E): CASE_VIC_4(0x7F):
break;
Expand All @@ -351,6 +324,13 @@ void vic_write_reg ( unsigned int addr, Uint8 data )
DEBUGPRINT("VIC4: precise sprite pointer address mode" NL);
}
break;
CASE_VIC_4(0x70): // VIC-IV palette selection register
palette = ((data & 0x03) << 8) + vic_palettes;
spritepalette = ((data & 0x0C) << 6) + vic_palettes;
altpalette = ((data & 0x30) << 4) + vic_palettes;
palregaccofs = ((data & 0xC0) << 2);
check_if_rom_palette(vic_registers[0x30] & 4);
break;
/* --- NON-EXISTING REGISTERS --- */
CASE_VIC_2(0x31): CASE_VIC_2(0x32): CASE_VIC_2(0x33): CASE_VIC_2(0x34): CASE_VIC_2(0x35): CASE_VIC_2(0x36): CASE_VIC_2(0x37): CASE_VIC_2(0x38):
CASE_VIC_2(0x39): CASE_VIC_2(0x3A): CASE_VIC_2(0x3B): CASE_VIC_2(0x3C): CASE_VIC_2(0x3D): CASE_VIC_2(0x3E): CASE_VIC_2(0x3F):
Expand Down Expand Up @@ -489,33 +469,6 @@ Uint8 vic_read_reg ( int unsigned addr )
#undef CASE_VIC_3_4


// "num" is 0-$ff for red, $100-$1ff for green and $200-$2ff for blue nibbles
void vic3_write_palette_reg ( int num, Uint8 data )
{
vic3_palette_nibbles[num] = data & 15;
// recalculate the given RGB entry based on the new data as well
vic3_palette[num & 0xFF] = RGB(
vic3_palette_nibbles[ num & 0xFF],
vic3_palette_nibbles[(num & 0xFF) | 0x100],
vic3_palette_nibbles[(num & 0xFF) | 0x200]
);
// Also, update the "ROM based" palette struct, BUT only colours above 15,
// since the lower 16 are "ROM based"! This is only a trick to be able
// to have full 256 colours for ROMPAL sel and without that too!
// The low 16 colours are the one which are ROM based for real, that's why
// we don't want to update them here!
if ((num & 0xF0))
vic3_rom_palette[num & 0xFF] = vic3_palette[num & 0xFF];
}

// TODO: for VIC-4 mode, the palette registers are 8 bit, reversed nibble order to be compatible with C65
// however, yet I don't support it, so only 4 bits can be used still by colour channel :(
void vic4_write_palette_reg ( int num, Uint8 data )
{
vic3_write_palette_reg(num, data); // TODO: now only call the VIC-3 solution, which is not so correct for M65/VIC-4
}


static inline Uint8 *vic2_get_chargen_pointer ( void )
{
if (vic_chrp_legacy) {
Expand Down Expand Up @@ -571,6 +524,7 @@ static inline void vic2_render_screen_text ( Uint32 *p, int tail )
if (!vic_sprp_legacy) {
sprite_pointers = main_ram + ((vic_registers[0x6C] | (vic_registers[0x6D] << 8) | (vic_registers[0x6E] << 16)) & ((512 << 10) - 1));
}
//DEBUGPRINT("VIC4: vidp = %u, vic_vidp_legacy=%d" NL, (unsigned int)(vidp - main_ram), vic_vidp_legacy);
// Target SDL pixel related format for the background colour
bg = palette[BG_FOR_Y(0)];
PIXEL_POINTER_CHECK_INIT(p, tail, "vic2_render_screen_text");
Expand Down Expand Up @@ -974,7 +928,7 @@ void vic_render_screen ( void )
#include <string.h>

#define SNAPSHOT_VIC4_BLOCK_VERSION 2
#define SNAPSHOT_VIC4_BLOCK_SIZE 0x400
#define SNAPSHOT_VIC4_BLOCK_SIZE (0x100 + ((NO_OF_PALETTE_REGS) * 3))

int vic4_snapshot_load_state ( const struct xemu_snapshot_definition_st *def, struct xemu_snapshot_block_st *block )
{
Expand All @@ -988,8 +942,10 @@ int vic4_snapshot_load_state ( const struct xemu_snapshot_definition_st *def, st
for (a = 0; a < 0x80; a++)
vic_write_reg(a, buffer[a + 0x80]);
c128_d030_reg = buffer[0x7F];
for (a = 0; a < 0x300; a++)
vic3_write_palette_reg(a, buffer[a + 0x100]); // TODO: save VIC4 style stuffs, but it doesn't exist yet ...
memcpy(vic_palette_bytes_red, buffer + 0x100 , NO_OF_PALETTE_REGS);
memcpy(vic_palette_bytes_green, buffer + 0x100 + NO_OF_PALETTE_REGS, NO_OF_PALETTE_REGS);
memcpy(vic_palette_bytes_blue, buffer + 0x100 + 2 * NO_OF_PALETTE_REGS, NO_OF_PALETTE_REGS);
vic4_revalidate_all_palette();
vic_iomode = buffer[0];
DEBUG("SNAP: VIC: changing I/O mode to %d(%s)" NL, vic_iomode, iomode_names[vic_iomode]);
interrupt_status = (int)P_AS_BE32(buffer + 1);
Expand All @@ -1006,7 +962,9 @@ int vic4_snapshot_save_state ( const struct xemu_snapshot_definition_st *def )
/* saving state ... */
memcpy(buffer + 0x80, vic_registers, 0x80); // $80 bytes
buffer[0x7F] = c128_d030_reg;
memcpy(buffer + 0x100, vic3_palette_nibbles, 0x300); // $300 bytes
memcpy(buffer + 0x100 , vic_palette_bytes_red, NO_OF_PALETTE_REGS);
memcpy(buffer + 0x100 + NO_OF_PALETTE_REGS, vic_palette_bytes_green, NO_OF_PALETTE_REGS);
memcpy(buffer + 0x100 + 2 * NO_OF_PALETTE_REGS, vic_palette_bytes_blue, NO_OF_PALETTE_REGS);
buffer[0] = vic_iomode;
U32_AS_BE(buffer + 1, interrupt_status);
return xemusnap_write_sub_block(buffer, sizeof buffer);
Expand Down
10 changes: 5 additions & 5 deletions targets/mega65/vic4.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/* A work-in-progess MEGA65 (Commodore 65 clone origins) emulator
Part of the Xemu project, please visit: https://github.com/lgblgblgb/xemu
Copyright (C)2016,2017 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
Copyright (C)2016-2020 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
Expand All @@ -16,14 +16,16 @@ You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */

#ifndef __XEMU_MEGA65_VIC4_H_INCLUDED
#define __XEMU_MEGA65_VIC4_H_INCLUDED
#ifndef XEMU_MEGA65_VIC4_H_INCLUDED
#define XEMU_MEGA65_VIC4_H_INCLUDED

#define VIC2_IOMODE 0
#define VIC3_IOMODE 1
#define VIC_BAD_IOMODE 2
#define VIC4_IOMODE 3

#define USE_HOTREGS (vic_registers[0x5D] & 0x80)

extern int vic_iomode;
extern int scanline;
extern Uint8 vic_registers[];
Expand All @@ -38,8 +40,6 @@ extern int vic_vidp_legacy, vic_chrp_legacy, vic_sprp_legacy;
extern void vic_init ( void );
extern void vic_write_reg ( unsigned int addr, Uint8 data );
extern Uint8 vic_read_reg ( unsigned int addr );
extern void vic3_write_palette_reg ( int num, Uint8 data );
extern void vic4_write_palette_reg ( int num, Uint8 data );
extern void vic_render_screen ( void );
extern void vic3_check_raster_interrupt ( void );

Expand Down
Loading

1 comment on commit 95c8168

@lgblgblgb
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See #29

Please sign in to comment.