Improve and simplify 16 bit I/O writes too
This commit is contained in:
parent
a53399af58
commit
64b19d1301
1 changed files with 80 additions and 160 deletions
240
gba_memory.c
240
gba_memory.c
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue