diff --git a/src/include/86box/vid_ega_render_remap.h b/src/include/86box/vid_ega_render_remap.h index a33b27ed4..37f6904db 100644 --- a/src/include/86box/vid_ega_render_remap.h +++ b/src/include/86box/vid_ega_render_remap.h @@ -20,11 +20,11 @@ break; \ \ case VAR_WORD_MODE_MA13: \ - out_addr = ((in_addr << 1) & 0x1fff8) | ((in_addr >> 13) & 0x4) | (in_addr & ~0x1ffff); \ + out_addr = ((in_addr << 1) & 0x3fff8) | ((in_addr >> 13) & 0x4) | (in_addr & ~0x3ffff); \ break; \ \ case VAR_WORD_MODE_MA15: \ - out_addr = ((in_addr << 1) & 0x1fff8) | ((in_addr >> 15) & 0x4) | (in_addr & ~0x1ffff); \ + out_addr = ((in_addr << 1) & 0x3fff8) | ((in_addr >> 15) & 0x4) | (in_addr & ~0x3ffff); \ break; \ \ case VAR_DWORD_MODE: \ @@ -85,7 +85,7 @@ ega_recalc_remap_func(ega_t *ega) func_nr = VAR_DWORD_MODE; else if (ega->crtc[0x17] & 0x40) func_nr = VAR_BYTE_MODE; - else if (ega->crtc[0x17] & 0x20) + else if ((ega->crtc[0x17] & 0x20) && ega->vram_limit > 64*1024) func_nr = VAR_WORD_MODE_MA15; else func_nr = VAR_WORD_MODE_MA13; diff --git a/src/video/vid_ega.c b/src/video/vid_ega.c index bfac7d503..6ad8bfb5e 100644 --- a/src/video/vid_ega.c +++ b/src/video/vid_ega.c @@ -752,6 +752,73 @@ ega_doblit(int wx, int wy, ega_t *ega) ega->y_add >>= 1; } +uint32_t +ega_remap_cpu_addr(uint32_t inaddr, ega_t *ega) +{ + int a0mux; + uint32_t addr = inaddr; + + // The CPU A0 line is multiplexed via a 3-to-8 mux. + // Input bits are: + // bit 0: 1 = 64K, 0 = 128K+ (from memory expansion connector) + // bit 1: 1 = Odd/Even mode, 0 = normal mode (from GC reg 6 bit 1) + // bit 2: 1 = 128K mapping, 0 = other mapping (from memory decode PROM) + a0mux = 0; + + if (ega->gdcreg[6] & 2) { + a0mux |= 2; + } + if (ega->vram_limit <= 64*1024) { + a0mux |= 1; + } + + switch ((ega->gdcreg[6] & 0xC)) { + case 0x0: // 128K A000 + addr &= 0xFFFF; + // TODO: Confirm the behaviour of this on actual hardware + a0mux |= 4; + break; + case 0x4: // 64K A000 + addr &= 0xFFFF; + break; + case 0x8: // 32K B000 + addr &= 0x7FFF; + break; + case 0xC: // 32K B800 + addr &= 0x7FFF; + break; + } + + switch (a0mux) { + case 0: + case 1: + case 4: + case 5: + case 7: // A0 becomes A0 + break; + case 2: + // A0 becomes the inversion of PGSEL (reg 0x3C2, miscout, bit 5) + // That is, 1 selects the "low" 64k, and 0 selects the "high" 64k. + addr &= ~1; + addr |= (~ega->miscout>>5)&1; + break; + case 3: // A0 becomes A14 + addr &= ~1; + addr |= (inaddr>>14)&1; + break; + case 6: // A0 becomes A16 + addr &= ~1; + addr |= (inaddr>>16)&1; + break; + } + + // In 64k mode, only select the first 16Kword/64KB bank + if (!(ega->seqregs[4] & 2)) { + addr &= 0x3FFF; + } + return addr; +} + void ega_write(uint32_t addr, uint8_t val, void *p) { @@ -761,21 +828,14 @@ ega_write(uint32_t addr, uint8_t val, void *p) cycles -= video_timing_write_b; - if (addr >= 0xB0000) - addr &= 0x7fff; - else - addr &= 0xffff; - if (ega->chain2_write) { writemask2 &= ~0xa; if (addr & 1) writemask2 <<= 1; - addr &= ~1; - if (addr & 0x4000) - addr |= 1; - addr &= ~0x4000; } + addr = ega_remap_cpu_addr(addr, ega); + addr <<= 2; if (addr >= ega->vram_limit) @@ -939,19 +999,13 @@ ega_read(uint32_t addr, void *p) int readplane = ega->readplane; cycles -= video_timing_read_b; - if (addr >= 0xb0000) - addr &= 0x7fff; - else - addr &= 0xffff; if (ega->chain2_read) { readplane = (readplane & 2) | (addr & 1); - addr &= ~1; - if (addr & 0x4000) - addr |= 1; - addr &= ~0x4000; } + addr = ega_remap_cpu_addr(addr, ega); + addr <<= 2; if (addr >= ega->vram_limit) diff --git a/src/video/vid_ega_render.c b/src/video/vid_ega_render.c index b2d5cb5c1..97ac8c5d4 100644 --- a/src/video/vid_ega_render.c +++ b/src/video/vid_ega_render.c @@ -336,7 +336,7 @@ ega_render_2bpp_highres(ega_t *ega) void ega_render_4bpp_lowres(ega_t *ega) { - int x, oddeven; + int x, secondcclk; uint8_t dat, edat[4]; uint32_t addr, *p; @@ -349,21 +349,25 @@ ega_render_4bpp_lowres(ega_t *ega) ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; + secondcclk = 0; for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 16) { addr = ega->remap_func(ega, ega->ma); - oddeven = 0; + addr &= ega->vrammask; if (ega->seqregs[1] & 4) { - oddeven = (addr & 4) ? 1 : 0; - edat[0] = ega->vram[addr | oddeven]; - edat[2] = ega->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - ega->ma += 2; + // FIXME: Verify the behaviour of planes 1,3 on actual hardware + edat[0] = ega->vram[(addr | 0) ^ secondcclk]; + edat[1] = ega->vram[(addr | 1) ^ secondcclk]; + edat[2] = ega->vram[(addr | 2) ^ secondcclk]; + edat[3] = ega->vram[(addr | 3) ^ secondcclk]; + secondcclk = (secondcclk + 1) & 1; + if (secondcclk == 0) + ega->ma += 4; } else { *(uint32_t *) (&edat[0]) = *(uint32_t *) (&ega->vram[addr]); ega->ma += 4; } - ega->ma &= ega->vrammask; + ega->ma &= 0x3ffff; if (ega->crtc[0x17] & 0x80) { dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); @@ -388,7 +392,7 @@ ega_render_4bpp_lowres(ega_t *ega) void ega_render_4bpp_highres(ega_t *ega) { - int x, oddeven; + int x, secondcclk; uint8_t dat, edat[4]; uint32_t addr, *p; @@ -401,21 +405,24 @@ ega_render_4bpp_highres(ega_t *ega) ega->firstline_draw = ega->displine; ega->lastline_draw = ega->displine; + secondcclk = 0; for (x = 0; x <= (ega->hdisp + ega->scrollcache); x += 8) { addr = ega->remap_func(ega, ega->ma); - oddeven = 0; - + addr &= ega->vrammask; if (ega->seqregs[1] & 4) { - oddeven = (addr & 4) ? 1 : 0; - edat[0] = ega->vram[addr | oddeven]; - edat[2] = ega->vram[addr | oddeven | 0x2]; - edat[1] = edat[3] = 0; - ega->ma += 2; + // FIXME: Verify the behaviour of planes 1,3 on actual hardware + edat[0] = ega->vram[(addr | 0) ^ secondcclk]; + edat[1] = ega->vram[(addr | 1) ^ secondcclk]; + edat[2] = ega->vram[(addr | 2) ^ secondcclk]; + edat[3] = ega->vram[(addr | 3) ^ secondcclk]; + secondcclk = (secondcclk + 1) & 1; + if (secondcclk == 0) + ega->ma += 4; } else { *(uint32_t *) (&edat[0]) = *(uint32_t *) (&ega->vram[addr]); ega->ma += 4; } - ega->ma &= ega->vrammask; + ega->ma &= 0x3ffff; if (ega->crtc[0x17] & 0x80) { dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2);