if (gconst_get(r, &a)) {
a += offs;
// check if rom is memory mapped (not bank switched), and address is in rom
- if (dr_is_rom(a) && p32x_sh2_get_mem_ptr(a, &mask, sh2)) {
+ if (dr_is_rom(a) && p32x_sh2_get_mem_ptr(a, &mask, sh2) != (void *)-1) {
switch (size & MF_SIZEMASK) {
case 0: *val = (s8)p32x_sh2_read8(a, sh2s); break; // 8
case 1: *val = (s16)p32x_sh2_read16(a, sh2s); break; // 16
void sh2_drc_mem_setup(SH2 *sh2)
{
- // fill the convenience pointers
- sh2->p_bios = sh2->is_slave ? Pico32xMem->sh2_rom_s.w : Pico32xMem->sh2_rom_m.w;
- sh2->p_da = sh2->data_array;
- sh2->p_sdram = Pico32xMem->sdram;
- sh2->p_rom = Pico.rom;
- // sh2->p_dram filled in dram bank switching
+ // fill the DRC-only convenience pointers
sh2->p_drcblk_da = Pico32xMem->drcblk_da[!!sh2->is_slave];
sh2->p_drcblk_ram = Pico32xMem->drcblk_ram;
}
{
const sh2_memmap *mm = sh2->read8_map;
void *ret = (void *)-1;
- u32 am;
- mm += a >> SH2_READ_SHIFT;
- am = a & ((1 << SH2_READ_SHIFT)-1);
- if (!map_flag_set(mm->addr) && !(am & ~mm->mask)) {
+ mm += SH2MAP_ADDR2OFFS_R(a);
+ if (!map_flag_set(mm->addr)) {
// directly mapped memory (SDRAM, ROM, data array)
ret = (void *)(mm->addr << 1);
*mask = mm->mask;
} else if ((a & ~0x7ff) == 0) {
// BIOS, has handler function since it shares its segment with I/O
- ret = sh2->is_slave ? Pico32xMem->sh2_rom_s.w : Pico32xMem->sh2_rom_m.w;
+ ret = sh2->p_bios;
*mask = 0x7ff;
} else if ((a & 0xc6000000) == 0x02000000) {
// banked ROM. Return bank address
return ret;
}
+int p32x_sh2_memcpy(u32 dst, u32 src, int count, int size, SH2 *sh2)
+{
+ u32 mask;
+ void *ps, *pd;
+ int len, i;
+
+ // check if src and dst points to memory (rom/sdram/dram/da)
+ if ((pd = p32x_sh2_get_mem_ptr(dst, &mask, sh2)) == (void *)-1)
+ return 0;
+ if ((ps = p32x_sh2_get_mem_ptr(src, &mask, sh2)) == (void *)-1)
+ return 0;
+ ps += src & mask;
+ len = count * size;
+
+ // DRAM in byte access is always in overwrite mode
+ if (pd == sh2->p_dram && size == 1)
+ dst |= 0x20000;
+
+ // align dst to halfword
+ if (dst & 1) {
+ p32x_sh2_write8(dst, *(u8 *)((uptr)ps ^ 1), sh2);
+ ps++, dst++, len --;
+ }
+
+ // copy data
+ if ((uptr)ps & 1) {
+ // unaligned, use halfword copy mode to reduce memory bandwidth
+ u16 *sp = (u16 *)(ps - 1);
+ u16 dl, dh = *sp++;
+ for (i = 0; i < (len & ~1); i += 2, dst += 2, sp++) {
+ dl = dh, dh = *sp;
+ p32x_sh2_write16(dst, (dh >> 8) | (dl << 8), sh2);
+ }
+ if (len & 1)
+ p32x_sh2_write8(dst, dh, sh2);
+ } else {
+ // dst and src at least halfword aligned
+ u16 *sp = (u16 *)ps;
+ // align dst to word
+ if ((dst & 2) && len >= 2) {
+ p32x_sh2_write16(dst, *sp++, sh2);
+ dst += 2, len -= 2;
+ }
+ if ((uptr)sp & 2) {
+ // halfword copy, using word writes to reduce memory bandwidth
+ u16 dl, dh;
+ for (i = 0; i < (len & ~3); i += 4, dst += 4, sp += 2) {
+ dl = sp[0], dh = sp[1];
+ p32x_sh2_write32(dst, (dl << 16) | dh, sh2);
+ }
+ } else {
+ // word copy
+ u32 d;
+ for (i = 0; i < (len & ~3); i += 4, dst += 4, sp += 2) {
+ d = *(u32 *)sp;
+ p32x_sh2_write32(dst, (d << 16) | (d >> 16), sh2);
+ }
+ }
+ if (len & 2) {
+ p32x_sh2_write16(dst, *sp++, sh2);
+ dst += 2;
+ }
+ if (len & 1)
+ p32x_sh2_write8(dst, *sp >> 8, sh2);
+ }
+
+ return count;
+}
+
// -----------------------------------------------------------------
static void z80_md_bank_write_32x(unsigned int a, unsigned char d)
ssh2_read16_map[0x04/2].addr = ssh2_read16_map[0x24/2].addr =
ssh2_read32_map[0x04/2].addr = ssh2_read32_map[0x24/2].addr = MAP_MEMORY(Pico32xMem->dram[b]);
- msh2.p_dram = ssh2.p_dram = Pico32xMem->dram[b]; // DRC conveniance ptr
- msh2.p_rom = ssh2.p_rom = Pico.rom;
+ // convenience ptrs
+ msh2.p_sdram = ssh2.p_sdram = Pico32xMem->sdram;
+ msh2.p_dram = ssh2.p_dram = Pico32xMem->dram[b];
+ msh2.p_rom = ssh2.p_rom = Pico.rom;
+ msh2.p_bios = Pico32xMem->sh2_rom_m.w; msh2.p_da = msh2.data_array;
+ ssh2.p_bios = Pico32xMem->sh2_rom_s.w; ssh2.p_da = ssh2.data_array;
}
static void bank_switch_rom_sh2(void)
chan->sar += size;
}
+// optimization for copying around memory with SH2 DMA
+static void dmac_memcpy(struct dma_chan *chan, SH2 *sh2)
+{
+ u32 size = (chan->chcr >> 10) & 3, up = chan->chcr & (1 << 14);
+ int count;
+
+ if (!up || chan->tcr < 4)
+ return;
+ if (size == 3) size = 2; // 4-word xfer mode still counts in words
+ // XXX check TCR being a multiple of 4 in 4-word xfer mode?
+ // XXX check alignment of sar/dar, generating a bus error if unaligned?
+ count = p32x_sh2_memcpy(chan->dar, chan->sar, chan->tcr, 1 << size, sh2);
+
+ chan->sar += count << size;
+ chan->dar += count << size;
+ chan->tcr -= count;
+}
+
// DMA trigger by SH2 register write
static void dmac_trigger(SH2 *sh2, struct dma_chan *chan)
{
if (chan->chcr & DMA_AR) {
// auto-request transfer
sh2->state |= SH2_STATE_SLEEP;
+ if ((((chan->chcr >> 12) ^ (chan->chcr >> 14)) & 3) == 0 &&
+ (((chan->chcr >> 14) ^ (chan->chcr >> 15)) & 1) == 1) {
+ // SM == DM and either DM0 or DM1 are set. check for mem to mem copy
+ dmac_memcpy(chan, sh2);
+ }
while ((int)chan->tcr > 0)
dmac_transfer_one(sh2, chan);
dmac_transfer_complete(sh2, chan);