Improve and simplify 16 bit I/O writes too

This commit is contained in:
David Guillen Fandos 2023-04-21 22:21:01 +02:00
parent a53399af58
commit 64b19d1301

View file

@ -718,238 +718,158 @@ static cpu_alert_type trigger_dma(u32 dma_number, u32 value)
return CPU_ALERT_NONE; return CPU_ALERT_NONE;
} }
static inline s32 signext28(u32 value)
#define access_register16_high(address) \ {
value = (value << 16) | (readaddress16(io_registers, address)) \ s32 ret = (s32)(value << 4);
return ret >> 4;
#define access_register16_low(address) \ }
value = ((readaddress16(io_registers, address + 2)) << 16) | value \
cpu_alert_type function_cc write_io_register16(u32 address, u32 value) cpu_alert_type function_cc write_io_register16(u32 address, u32 value)
{ {
uint16_t ioreg = (address & 0x3FE) >> 1;
value &= 0xffff; value &= 0xffff;
switch(address) switch(ioreg)
{ {
case 0x00: case REG_DISPCNT:
{ // Changing the lowest 3 bits might require object re-sorting
u32 dispcnt = read_ioreg(REG_DISPCNT); reg[OAM_UPDATED] |= ((value & 0x07) != (read_ioreg(REG_DISPCNT) & 0x07));
if((value & 0x07) != (dispcnt & 0x07))
reg[OAM_UPDATED] = 1;
write_ioreg(REG_DISPCNT, value); write_ioreg(REG_DISPCNT, value);
break; break;
}
// DISPSTAT // DISPSTAT has 3 read only bits, controlled by the LCD controller
case 0x04: case REG_DISPSTAT:
write_ioreg(REG_DISPSTAT, (read_ioreg(REG_DISPSTAT) & 0x07) | (value & ~0x07)); write_ioreg(REG_DISPSTAT, (read_ioreg(REG_DISPSTAT) & 0x07) | (value & ~0x07));
break; break;
// VCOUNT
case 0x06:
break;
// BG2 reference X // BG2 reference X
case 0x28: case REG_BG2X_L:
access_register16_low(0x28); case REG_BG2X_H:
affine_reference_x[0] = (s32)(value << 4) >> 4; write_ioreg(ioreg, value);
address32(io_registers, 0x28) = eswap32(value); affine_reference_x[0] = signext28(read_ioreg32(REG_BG2X_L));
break;
case 0x2A:
access_register16_high(0x28);
affine_reference_x[0] = (s32)(value << 4) >> 4;
address32(io_registers, 0x28) = eswap32(value);
break; break;
// BG2 reference Y // BG2 reference Y
case 0x2C: case REG_BG2Y_L:
access_register16_low(0x2C); case REG_BG2Y_H:
affine_reference_y[0] = (s32)(value << 4) >> 4; write_ioreg(ioreg, value);
address32(io_registers, 0x2C) = eswap32(value); affine_reference_y[0] = signext28(read_ioreg32(REG_BG2Y_L));
break;
case 0x2E:
access_register16_high(0x2C);
affine_reference_y[0] = (s32)(value << 4) >> 4;
address32(io_registers, 0x2C) = eswap32(value);
break; break;
// BG3 reference X // BG3 reference X
case REG_BG3X_L:
case 0x38: case REG_BG3X_H:
access_register16_low(0x38); write_ioreg(ioreg, value);
affine_reference_x[1] = (s32)(value << 4) >> 4; affine_reference_x[1] = signext28(read_ioreg32(REG_BG3X_L));
address32(io_registers, 0x38) = eswap32(value);
break;
case 0x3A:
access_register16_high(0x38);
affine_reference_x[1] = (s32)(value << 4) >> 4;
address32(io_registers, 0x38) = eswap32(value);
break; break;
// BG3 reference Y // BG3 reference Y
case 0x3C: case REG_BG3Y_L:
access_register16_low(0x3C); case REG_BG3Y_H:
affine_reference_y[1] = (s32)(value << 4) >> 4; write_ioreg(ioreg, value);
address32(io_registers, 0x3C) = eswap32(value); affine_reference_y[1] = signext28(read_ioreg32(REG_BG3Y_L));
break; break;
case 0x3E: // Sound 1 registers
access_register16_high(0x3C); case REG_SOUND1CNT_L: // control sweep
affine_reference_y[1] = (s32)(value << 4) >> 4;
address32(io_registers, 0x3C) = eswap32(value);
break;
// Sound 1 control sweep
case 0x60:
gbc_sound_tone_control_sweep(); gbc_sound_tone_control_sweep();
break; break;
// Sound 1 control duty/length/envelope case REG_SOUND1CNT_H: // control duty/length/envelope
case 0x62:
gbc_sound_tone_control_low(0, REG_SOUND1CNT_H); gbc_sound_tone_control_low(0, REG_SOUND1CNT_H);
break; break;
// Sound 1 control frequency case REG_SOUND1CNT_X: // control frequency
case 0x64:
gbc_sound_tone_control_high(0, REG_SOUND1CNT_X); gbc_sound_tone_control_high(0, REG_SOUND1CNT_X);
break; break;
// Sound 2 control duty/length/envelope // Sound 2 registers
case 0x68: case REG_SOUND2CNT_L: // control duty/length/envelope
gbc_sound_tone_control_low(1, REG_SOUND2CNT_L); gbc_sound_tone_control_low(1, REG_SOUND2CNT_L);
break; break;
// Sound 2 control frequency case REG_SOUND2CNT_H: // control frequency
case 0x6C:
gbc_sound_tone_control_high(1, REG_SOUND2CNT_H); gbc_sound_tone_control_high(1, REG_SOUND2CNT_H);
break; break;
// Sound 3 control wave // Sound 3 registers
case 0x70: case REG_SOUND3CNT_L: // control wave
gbc_sound_wave_control(); gbc_sound_wave_control();
break; break;
// Sound 3 control length/volume case REG_SOUND3CNT_H: // control length/volume
case 0x72:
gbc_sound_tone_control_low_wave(); gbc_sound_tone_control_low_wave();
break; break;
// Sound 3 control frequency case REG_SOUND3CNT_X: // control frequency
case 0x74:
gbc_sound_tone_control_high_wave(); gbc_sound_tone_control_high_wave();
break; break;
// Sound 4 control length/envelope // Sound 4 registers
case 0x78: case REG_SOUND4CNT_L: // length/envelope
gbc_sound_tone_control_low(3, REG_SOUND4CNT_L); gbc_sound_tone_control_low(3, REG_SOUND4CNT_L);
break; break;
// Sound 4 control frequency case REG_SOUND4CNT_H: // control frequency
case 0x7C:
gbc_sound_noise_control(); gbc_sound_noise_control();
break; break;
// Sound control L // Sound control registers
case 0x80: case REG_SOUNDCNT_L:
gbc_trigger_sound(value); gbc_trigger_sound(value);
break; break;
// Sound control H case REG_SOUNDCNT_H:
case 0x82:
trigger_sound(); trigger_sound();
break; break;
// Sound control X case REG_SOUNDCNT_X:
case 0x84:
sound_control_x(value); sound_control_x(value);
break; break;
// Sound wave RAM // Sound wave RAM, flag wave table update
case 0x90 ... 0x9E: case REG_SOUNDWAVE_0 ... REG_SOUNDWAVE_7:
gbc_sound_wave_update = 1; gbc_sound_wave_update = 1;
address16(io_registers, address) = eswap16(value); write_ioreg(ioreg, value);
break; break;
// DMA control // DMA control register: can cause an IRQ
case 0xBA: case REG_DMA0CNT_H: return trigger_dma(0, value);
return trigger_dma(0, value); case REG_DMA1CNT_H: return trigger_dma(1, value);
case REG_DMA2CNT_H: return trigger_dma(2, value);
case REG_DMA3CNT_H: return trigger_dma(3, value);
case 0xC6: // Timer counter reload
return trigger_dma(1, value); case REG_TM0D: count_timer(0); break;
case REG_TM1D: count_timer(1); break;
case REG_TM2D: count_timer(2); break;
case REG_TM3D: count_timer(3); break;
case 0xD2: /* Timer control register (0..3)*/
return trigger_dma(2, value); case REG_TM0CNT: trigger_timer(0, value); break;
case REG_TM1CNT: trigger_timer(1, value); break;
case REG_TM2CNT: trigger_timer(2, value); break;
case REG_TM3CNT: trigger_timer(3, value); break;
case 0xDE: // Interrupt flag, clears the bits it tries to write
return trigger_dma(3, value); case REG_IF:
// Timer counts
case 0x100:
count_timer(0);
break;
case 0x104:
count_timer(1);
break;
case 0x108:
count_timer(2);
break;
case 0x10C:
count_timer(3);
break;
/* Timer control 0 */
case 0x102:
trigger_timer(0, value);
break;
/* Timer control 1 */
case 0x106:
trigger_timer(1, value);
break;
/* Timer control 2 */
case 0x10A:
trigger_timer(2, value);
break;
/* Timer control 3 */
case 0x10E:
trigger_timer(3, value);
break;
// P1
case 0x130:
break;
// REG_IE
case 0x200:
write_ioreg(REG_IE, value);
return check_interrupt();
// Interrupt flag
case 0x202:
write_ioreg(REG_IF, read_ioreg(REG_IF) & (~value)); write_ioreg(REG_IF, read_ioreg(REG_IF) & (~value));
break; break;
// WAITCNT // Register writes with side-effects, can raise an IRQ
case 0x204: case REG_IE:
write_ioreg(REG_WAITCNT, value); case REG_IME:
break; write_ioreg(ioreg, value);
// REG_IME
case 0x208:
write_ioreg(REG_IME, value);
return check_interrupt(); return check_interrupt();
// Read-only registers
case REG_P1:
case REG_VCOUNT:
break; // Do nothing
// Registers without side effects
case REG_WAITCNT:
default: default:
address16(io_registers, address) = eswap16(value); write_ioreg(ioreg, value);
break; break;
} }
@ -968,9 +888,9 @@ cpu_alert_type function_cc write_io_register8(u32 address, u32 value)
// Partial 16 bit write, treat like a regular merge-write // Partial 16 bit write, treat like a regular merge-write
if (address & 1) if (address & 1)
value = (value << 8) | (read_ioreg((address >> 1) & 0x1FF) & 0x00ff); value = (value << 8) | (read_ioreg(address >> 1) & 0x00ff);
else else
value = (value & 0xff) | (read_ioreg((address >> 1) & 0x1FF) & 0xff00); value = (value & 0xff) | (read_ioreg(address >> 1) & 0xff00);
return write_io_register16(address & 0x3FE, value); return write_io_register16(address & 0x3FE, value);
} }