From f730653b1736793e5d2fb7fea6172bfcb7e962ac Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Tue, 26 Dec 2023 19:12:57 +0200 Subject: [PATCH] Partial NCR 77C22E+ and 77C32BLT emulation. Retina Z2 and Z3. --- gfxboard.cpp | 188 ++- include/gfxboard.h | 4 +- od-win32/winuae_msvc15/winuae_msvc.vcxproj | 1 + .../winuae_msvc15/winuae_msvc.vcxproj.filters | 3 + pcem/pcemglue.cpp | 5 +- pcem/vid_ncr.cpp | 1185 +++++++++++++++++ pcem/vid_ncr.h | 2 + 7 files changed, 1361 insertions(+), 27 deletions(-) create mode 100644 pcem/vid_ncr.cpp create mode 100644 pcem/vid_ncr.h diff --git a/gfxboard.cpp b/gfxboard.cpp index c3e57c19..b5eb8a24 100644 --- a/gfxboard.cpp +++ b/gfxboard.cpp @@ -51,6 +51,7 @@ static bool memlogw = true; #include "pcem/vid_cl5429.h" #include "pcem/vid_s3.h" #include "pcem/vid_voodoo_banshee.h" +#include "pcem/vid_ncr.h" #include "pci.h" #include "pci_hw.h" #include "pcem/pcemglue.h" @@ -233,6 +234,20 @@ static const struct gfxboard boards[] = ROMTYPE_PICASSOIV, 0, NULL, &gd5446_device }, + { + GFXBOARD_ID_RETINA_Z2, + _T("Retina [Zorro II]"), _T("Macro System"), _T("Retina_Z2"), + 18260, 6, 0, 0, + 0x00000000, 0x00100000, 0x00400000, 0x00020000, 0, 2, 2, false, + 0, 0, NULL, &ncr_retina_z2_device + }, + { + GFXBOARD_ID_RETINA_Z3, + _T("Retina [Zorro III]"), _T("Macro System"), _T("Retina_Z3"), + 18260, 16, 0, 0, + 0x00000000, 0x00100000, 0x00400000, 0x00400000, 0, 3, 2, false, + 0, 0, NULL, &ncr_retina_z3_device + }, { GFXBOARD_ID_HARLEQUIN, _T("Harlequin [Zorro II]"), _T("ACS"), _T("Harlequin_PAL"), @@ -335,6 +350,7 @@ struct rtggfxboard int vga_width, vga_height, vga_width_mult, vga_height_mult; bool vga_refresh_active; int device_settings; + uae_u8 extradata[16]; uae_u32 vgaioregionptr, vgavramregionptr, vgabank0regionptr, vgabank1regionptr; @@ -871,7 +887,7 @@ static void init_board (struct rtggfxboard *gb) gb->vram_offset_enabled = false; gb->gfxmem_bank->reserved_size = vramsize; gb->gfxmem_bank->start = gb->gfxboardmem_start; - if (gb->board->manufacturer) { + if (gb->board->manufacturer && gb->board->banksize >= 0x40000) { gb->gfxmem_bank->flags |= ABFLAG_ALLOCINDIRECT | ABFLAG_PPCIOSPACE; gb->gfxmem_bank->label = _T("*"); mapped_malloc(gb->gfxmem_bank); @@ -2730,6 +2746,25 @@ static void REGPARAM2 gfxboard_wput_mem_autoconfig (uaecptr addr, uae_u32 b) gb->pcem_vram_mask = 0x3fffff; gb->pcem_io_mask = 0x3fff; + } else if (boardnum == GFXBOARD_ID_RETINA_Z3) { + + uae_u32 offset = 0xc00000; + for (;;) { + map_banks_z3(&gb->gfxboard_bank_vram_pcem, (start + offset) >> 16, gb->gfxboard_bank_vram_pcem.allocated_size >> 16); + offset += gb->gfxboard_bank_vram_pcem.allocated_size; + if (offset >= 0x1000000) + break; + } + map_banks_z3(&gb->gfxboard_bank_mmio_wbs_pcem, (start + 0xb00000) >> 16, 1); + map_banks_z3(&gb->gfxboard_bank_io_swap_pcem, (start + 0x000000) >> 16, 1); + gb->pcem_vram_offset = 0x800000; + gb->pcem_vram_mask = 0x3fffff; + gb->pcem_io_mask = 0x3fff; + gb->pcem_mmio_offset = 0x00300000; + gb->pcem_mmio_mask = 0xff; + gb->configured_regs = gb->gfxmem_bank->start >> 16; + gb->gfxboard_intena = 1; + } } else { @@ -2871,6 +2906,22 @@ static void REGPARAM2 gfxboard_bput_mem_autoconfig (uaecptr addr, uae_u32 b) gb->pcem_vram_mask = 0x1fffff; gb->pcem_io_mask = 0x3fff; + } else if (boardnum == GFXBOARD_ID_RETINA_Z2) { + + gb->configured_mem = b; + gb->configured_regs = b; + + ab = &gb->gfxboard_bank_special_pcem; + map_banks_z2(ab, b, gb->board->banksize >> 16); + + init_board(gb); + + gb->mem_start[0] = b << 16; + gb->mem_end[0] = gb->mem_start[0] + gb->board->banksize; + gb->pcem_vram_offset = 0x800000; + gb->pcem_vram_mask = 0x3fffff; + gb->pcem_io_mask = 0x3fff; + } else { // Picasso II, Picasso II+ @@ -4320,33 +4371,43 @@ bool gfxboard_init_memory (struct autoconfig_info *aci) z2_flags = 0x05; // 1M z3_flags = 0; + type = 0; bank = gb->board->banksize; - bank /= 0x00100000; - if (bank >= 16) { - ext_size = true; - bank /= 16; - while (bank > 1) { - z3_flags++; - bank >>= 1; + if (bank <= 0x40000) { + z2_flags = 0x00; + while (bank >= 0x10000) { + z2_flags++; + bank /= 2; } + type = z2_flags | 0xc0; } else { - while (bank > 1) { - z2_flags++; - bank >>= 1; + bank /= 0x00100000; + if (bank >= 16) { + ext_size = true; + bank /= 16; + while (bank > 1) { + z3_flags++; + bank >>= 1; + } + } else { + while (bank > 1) { + z2_flags++; + bank >>= 1; + } + z2_flags &= 7; } - z2_flags &= 7; - } - if (gb->board->configtype == 3) { - type = 0x80; - flags |= 0x10; - if (ext_size) { - flags |= 0x20; - type |= z3_flags; + if (gb->board->configtype == 3) { + type = 0x80; + flags |= 0x10; + if (ext_size) { + flags |= 0x20; + type |= z3_flags; + } else { + type |= z2_flags; + } } else { - type |= z2_flags; + type = z2_flags | 0xc0; } - } else { - type = z2_flags | 0xc0; } type |= gb->board->model_registers && !gb->board->model_extra ? 0x08 : 0x00; flags |= gb->board->er_flags; @@ -4571,7 +4632,7 @@ bool gfxboard_init_registersx(struct autoconfig_info *aci, int regnum) } memset (gb->automemory, 0xff, GFXBOARD_AUTOCONFIG_SIZE); - if (gb->rbc->rtgmem_type == GFXBOARD_ID_PIXEL64) { + if (gb->rbc->rtgmem_type == GFXBOARD_ID_PIXEL64 || gb->rbc->rtgmem_type == GFXBOARD_ID_RETINA_Z2) { ew(gb, 0x00, 0xc0 | 0x02); // 128 Z2 size = BOARD_REGISTERS_SIZE * 2; } else { @@ -5451,7 +5512,61 @@ static void special_pcem_put(uaecptr addr, uae_u32 v, int size) write_log(_T("PCEM SPECIAL PUT %08x %08x %d PC=%08x\n"), addr, v, size, M68K_GETPC); #endif - if (boardnum == GFXBOARD_ID_PIXEL64) { + if (boardnum == GFXBOARD_ID_RETINA_Z2) { + + addr &= 0x1ffff; + if (addr & 0x10000) { + // VRAM banks + uaecptr mem = addr & 0xffff; + if (size == 2) { + v = do_byteswap_32(v); + } else if (size == 1) { + v = do_byteswap_16(v); + } + put_mem_pcem(mem + 0xa0000, v, size); + } else if (addr & 0x8000) { + // RAMDAC + int dac = addr & 15; + if (dac == 1) { + // palette index + gb->extradata[0] = v; + gb->extradata[1] = 0; + } else if (dac == 3) { + // palette data + gb->extradata[2 + gb->extradata[1]] = v; + gb->extradata[1]++; + if (gb->extradata[1] == 3) { + put_io_pcem(0x3c8, gb->extradata[0], 0); + put_io_pcem(0x3c9, gb->extradata[2], 0); + put_io_pcem(0x3c9, gb->extradata[3], 0); + put_io_pcem(0x3c9, gb->extradata[4], 0); + gb->extradata[0]++; + gb->extradata[0] &= 255; + gb->extradata[1] = 0; + } + } else if (dac == 13) { + // 16/24 bit mode + if ((v & (0x80 | 0x40 | 0x20)) == (0x80 | 0x40 | 0x20)) { + put_io_pcem(0x3c4, 0x3f, 0); + put_io_pcem(0x3c5, 24, 0); + } else if (v & 0x80) { + put_io_pcem(0x3c4, 0x3f, 0); + put_io_pcem(0x3c5, 16, 0); + } else { + put_io_pcem(0x3c4, 0x3f, 0); + put_io_pcem(0x3c5, 8, 0); + } + } + } else { + // IO + int io = addr & 0x3fff; + if (!(addr & 0x4000)) { + io++; + } + put_io_pcem(io, v, 0); + } + + } else if (boardnum == GFXBOARD_ID_PIXEL64) { addr &= 0xffff; if (size) { @@ -5743,7 +5858,30 @@ static uae_u32 special_pcem_get(uaecptr addr, int size) write_log(_T("PCEM SPECIAL GET %08x %d PC=%08x\n"), addr, size, M68K_GETPC); #endif - if (boardnum == GFXBOARD_ID_PIXEL64) { + if (boardnum == GFXBOARD_ID_RETINA_Z2) { + + addr &= 0x1ffff; + if (addr & 0x10000) { + // VRAM banks + uaecptr mem = addr & 0xffff; + v = get_mem_pcem(mem + 0xa0000, size); + if (size == 2) { + v = do_byteswap_32(v); + } else if (size == 1) { + v = do_byteswap_16(v); + } + } else if (addr & 0x8000) { + // RAMDAC + } else { + // IO + int io = addr & 0x3fff; + if (!(addr & 0x4000)) { + io++; + } + v = get_io_pcem(io, 0); + } + + } else if (boardnum == GFXBOARD_ID_PIXEL64) { if (size) { v = get_io_pcem(addr + 0, 0) << 8; diff --git a/include/gfxboard.h b/include/gfxboard.h index 81a93103..0f8c42af 100644 --- a/include/gfxboard.h +++ b/include/gfxboard.h @@ -81,7 +81,9 @@ int pcem_getvramsize(void); #define GFXBOARD_ID_VOODOO3_PCI 18 #define GFXBOARD_ID_S3VIRGE_PCI 19 #define GFXBOARD_ID_PIXEL64 20 -#define GFXBOARD_ID_VOODOO5_PCI 21 +#define GFXBOARD_ID_RETINA_Z2 21 +#define GFXBOARD_ID_RETINA_Z3 22 +#define GFXBOARD_ID_VOODOO5_PCI 23 struct gfxboard_mode { diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj b/od-win32/winuae_msvc15/winuae_msvc.vcxproj index 5a7ae28f..4d4fcd2a 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj @@ -1378,6 +1378,7 @@ + diff --git a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters index 3cc05090..5e358ac8 100644 --- a/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters +++ b/od-win32/winuae_msvc15/winuae_msvc.vcxproj.filters @@ -1000,6 +1000,9 @@ dsp3210 + + pcem + diff --git a/pcem/pcemglue.cpp b/pcem/pcemglue.cpp index 6e7c7af6..2b07faaf 100644 --- a/pcem/pcemglue.cpp +++ b/pcem/pcemglue.cpp @@ -799,7 +799,7 @@ static mem_mapping_t *getmm(uaecptr *addrp) void put_mem_pcem(uaecptr addr, uae_u32 v, int size) { #if 0 - write_log("%08x %08x %d\n", addr, v, size); + write_log("put_mem_pcem %08x %08x %d\n", addr, v, size); #endif mem_mapping_t *m = getmm(&addr); if (m) { @@ -825,6 +825,9 @@ uae_u32 get_mem_pcem(uaecptr addr, int size) v = m->read_l(addr, m->p); } } +#if 0 + write_log("get_mem_pcem %08x %08x %d\n", addr, v, size); +#endif return v; } diff --git a/pcem/vid_ncr.cpp b/pcem/vid_ncr.cpp new file mode 100644 index 00000000..41996a10 --- /dev/null +++ b/pcem/vid_ncr.cpp @@ -0,0 +1,1185 @@ + +/* NCR 77C22E+ and 77C32BLT emulation by Toni Wilen 2023 */ + +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "pci.h" +#include "mem.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_ncr.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_sdac_ramdac.h" + +extern void activate_debugger(); + +enum +{ + NCR_TYPE_22EP = 2, + NCR_TYPE_32BLT +}; + +typedef struct ncr_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + sdac_ramdac_t ramdac; + + uint8_t ma_ext; + int width; + int bpp; + int ramdacbpp; + + int chip; + + uint8_t id, id_ext; + + uint32_t linear_base, linear_size; + uint32_t mmio_base, mmio_size; + + int card; + uint32_t bank[4]; + uint32_t vram_mask; + + uint8_t subsys_cntl, subsys_stat; + int vblank_irq; + + uint32_t hwc_fg_col, hwc_bg_col; + int hwc_col_stack_pos; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; + + uint8_t hwcursor_pal[2]; + + uint8_t blt_status, blt_rop, blt_hprot, blt_vprot; + uint16_t blt_width, blt_height, blt_control; + uint32_t blt_src, blt_dst, blt_pat; + uint64_t blt_fifo_data; + uint32_t blt_srcbak, blt_dstbak, blt_patbak, blt_patbak2; + uint32_t blt_c0, blt_c1; + uint16_t blt_w, blt_h; + uint8_t blt_stage; + int8_t blt_fifo_read, blt_fifo_write; + uint8_t blt_srcdata, blt_patdata, blt_dstdata; + int8_t blt_expand_offset, blt_expand_bit, blt_first_expand; + uint8_t blt_patdone, blt_start; + uint8_t blt_fifo_size; + uint8_t blt_patx, blt_paty; + uint8_t blt_src_size; + uint8_t blt_bpp; + +} ncr_t; + +void ncr_updatemapping(ncr_t*); +void ncr_updatebanking(ncr_t*); + +static int ncr_vga_vsync_enabled(ncr_t *ncr) +{ + if (!(ncr->svga.crtc[0x11] & 0x20) && ncr->vblank_irq > 0) + return 1; + return 0; +} + +static void ncr_update_irqs(ncr_t *ncr) +{ + if (ncr->vblank_irq > 0 && ncr_vga_vsync_enabled(ncr)) + pci_set_irq(NULL, PCI_INTA); + else + pci_clear_irq(NULL, PCI_INTA); +} + +static void ncr_vblank_start(svga_t *svga) +{ + ncr_t *ncr = (ncr_t *)svga->p; + if (ncr->vblank_irq >= 0) { + ncr->vblank_irq = 1; + ncr_update_irqs(ncr); + } +} + + +void ncr_hwcursor_draw(svga_t *svga, int displine) +{ + ncr_t *ncr = (ncr_t*)svga->p; + int x; + uint8_t dat[2]; + uint32_t c[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int line_offset = 0; + + offset <<= svga->horizontal_linedbl; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += line_offset; + + if (svga->bpp <= 8) { + c[0] = svga->pallook[ncr->hwcursor_pal[0]]; + c[1] = svga->pallook[ncr->hwcursor_pal[1]]; + } else { + for (int i = 0; i < 2; i++) { + uint8_t r = (ncr->hwcursor_pal[i] & (0x80 | 0x40 | 0x20)); + uint8_t b = (ncr->hwcursor_pal[i] & (0x10 | 0x08)) << 3; + uint8_t g = (ncr->hwcursor_pal[i] & (4 | 2 | 1) << 5); + r |= (r >> 3) | (r >> 6); + b |= (b >> 2) | (b >> 4) | (b >> 6); + g |= (g >> 3) | (g >> 6); + c[i] = (r << 16) | (g << 8) | b; + c[i] <<= 8; + } + } + + svga->hwcursor_latch.addr += (svga->hwcursor.xsize / 8); + for (x = 0; x < svga->hwcursor.xsize; x += 8) + { + svga->hwcursor_latch.addr--; + uint32_t addroffset = svga->hwcursor_latch.addr & svga->vram_display_mask; + dat[0] = svga->vram[addroffset]; + addroffset = (svga->hwcursor_latch.addr + (svga->hwcursor.xsize / 8)) & svga->vram_display_mask; + dat[1] = svga->vram[addroffset]; + for (xx = 0; xx < 8; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x80)) + ((uint32_t *)buffer32->line[displine])[offset + 32] = c[(dat[1] & 0x80) ? 0 : 1]; + else if (dat[1] & 0x80) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + svga->hwcursor_latch.addr += (svga->hwcursor.xsize / 8) * 2; + + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += line_offset; +} + + +void ncr_out(uint16_t addr, uint8_t val, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + svga_t *svga = &ncr->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c4: + svga->seqaddr = val & 0x3f; + break; + case 0x3c5: + { + old = svga->seqregs[svga->seqaddr]; + svga->seqregs[svga->seqaddr] = val; + if (old != val && svga->seqaddr >= 0x0a) { + svga->fullchange = changeframecount; + } + switch (svga->seqaddr) + { + case 0x0a: + ncr->hwcursor_pal[0] = val; + break; + case 0x0b: + ncr->hwcursor_pal[1] = val; + break; + case 0x0c: + svga->hwcursor.ena = val & 1; + svga->hwcursor.ysize = 16 << ((val >> 1) & 3); + svga->hwcursor.xsize = (val & 0x80) && ncr->chip == NCR_TYPE_32BLT ? 64 : 32; + break; + case 0x0d: + case 0x0e: + case 0x0f: + case 0x10: + svga->hwcursor.x = (svga->seqregs[0x0d] << 8) | svga->seqregs[0x0e]; + svga->hwcursor.y = (svga->seqregs[0x0f] << 8) | svga->seqregs[0x10]; + return; + case 0x11: + svga->hwcursor.xoff = val & 31; + return; + case 0x12: + svga->hwcursor.yoff = val & 127; + return; + case 0x13: + case 0x14: + case 0x15: + case 0x16: + { + int offset = 0; + if (ncr->chip == NCR_TYPE_32BLT) { + if (svga->seqregs[0x1e] & 0x10) { + offset = (svga->seqregs[0x15] << 8) | svga->seqregs[0x16]; + } + svga->hwcursor.addr = (svga->seqregs[0x13] << 8) | svga->seqregs[0x14]; + svga->hwcursor.addr += offset << 6; + svga->hwcursor.addr &= ~0x3ff; + } else { + svga->hwcursor.addr = (svga->seqregs[0x15] << 16) | (svga->seqregs[0x16] << 8) | svga->seqregs[0x14]; + svga->hwcursor.addr >>= 2; + } + } + break; + case 0x18: + case 0x19: + case 0x1a: + case 0x1b: + case 0x1c: + case 0x1d: + ncr_updatebanking(ncr); + break; + case 0x1e: + ncr_updatemapping(ncr); + break; + case 0x21: + if (val & 1) { + svga->bpp = 8; + svga->bpp = 8 << ((val >> 4) & 3); + if (svga->bpp > 24) { + svga->bpp = 24; + } + } else { + svga->bpp = 4; + } + break; + case 0x30: + case 0x31: + case 0x32: + case 0x33: + ncr_updatemapping(ncr); + break; + case 0x3f: // ram dac fake + ncr->ramdacbpp = val; + break; + } + if (old != val) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x3d4: + svga->crtcreg = val & svga->crtcreg_mask;; + return; + case 0x3d5: + { + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x11: + if (!(val & 0x10)) { + if (ncr->vblank_irq > 0) + ncr->vblank_irq = -1; + } else if (ncr->vblank_irq < 0) { + ncr->vblank_irq = 0; + } + ncr_update_irqs(ncr); + if ((val & ~0x30) == (old & ~0x30)) + old = val; + break; + + case 0x31: + ncr->ma_ext = val & 15; + break; + + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t ncr_in(uint16_t addr, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + svga_t *svga = &ncr->svga; + uint8_t ret; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c2: + ret = svga_in(addr, svga); + ret |= ncr->vblank_irq > 0 ? 0x80 : 0x00; + return ret; + case 0x3c5: + switch(svga->seqaddr) + { + case 0x08: + ret = ncr->chip << 4; + if (ncr->chip == NCR_TYPE_22EP) { + ret |= 8; + } + return ret; + } + if (svga->seqaddr >= 0x08 && svga->seqaddr < 0x40) + return svga->seqregs[svga->seqaddr]; + break; + + case 0x3d4: + return svga->crtcreg; + case 0x3d5: + switch (svga->crtcreg) + { + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +static const int fontwidths[] = +{ + 4, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 8, 8, 8, 8, 8 +}; + +void ncr_recalctimings(svga_t *svga) +{ + ncr_t *ncr = (ncr_t*)svga->p; + + svga->hdisp = svga->crtc[1] - ((svga->crtc[5] & 0x60) >> 5); + if (svga->crtc[0x30] & 0x02) + svga->hdisp += 0x100; + if (svga->crtc[0x32] & 0x02) + svga->hdisp += 0x200; + svga->hdisp++; + if (svga->seqregs[0x1f] & 0x10) { + svga->hdisp *= fontwidths[svga->seqregs[0x1f] & 15]; + } else { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + } + + if (svga->crtc[0x30] & 0x01) + svga->htotal += 0x100; + if (svga->crtc[0x32] & 0x01) + svga->htotal += 0x200; + + if (svga->crtc[0x33] & 0x02) + svga->dispend += 0x400; + if (svga->crtc[0x33] & 0x04) + svga->vblankstart += 0x400; + + if (svga->crtc[0x33] & 0x01) + svga->vtotal += 0x400; + + if (svga->crtc[0x33] & 0x10) + svga->split += 0x400; + + if (svga->crtc[0x31] & 0x10) + svga->rowoffset += 0x100; + + if (!svga->rowoffset) + svga->rowoffset = 256; + + svga->interlace = svga->crtc[0x30] & 0x10; + + if (svga->crtc[0x30] & 0x40) + svga->clock /= 2; + + svga->ma_latch |= (ncr->ma_ext << 16); + + if (svga->seqregs[0x21] & 0x02) + { + svga->render = svga_render_4bpp_highres; + svga->hdisp /= 2; + } + + if (svga->seqregs[0x21] & 0x01) + { + if (ncr->chip < NCR_TYPE_32BLT) { + svga->bpp = ncr->ramdacbpp; + } + } + switch (svga->bpp) + { + case 4: + svga->render = svga_render_4bpp_highres; + break; + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + } + + svga->horizontal_linedbl = svga->dispend * 9 / 10 >= svga->hdisp; +} + + +static void ncr_write(uint32_t addr, uint8_t val, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + svga_t *svga = &ncr->svga; + + addr = (addr & 0xffff) + ncr->bank[(addr >> 15) & 3]; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint8_t *)&svga->vram[addr] = val; +} +static void ncr_writew(uint32_t addr, uint16_t val, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + svga_t *svga = &ncr->svga; + + addr = (addr & 0xffff) + ncr->bank[(addr >> 15) & 3]; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} +static void ncr_writel(uint32_t addr, uint32_t val, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + svga_t *svga = &ncr->svga; + + addr = (addr & 0xffff) + ncr->bank[(addr >> 15) & 3]; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return; + addr &= svga->vram_mask; + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + +static uint8_t ncr_read(uint32_t addr, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + svga_t *svga = &ncr->svga; + + addr = (addr & 0xffff) + ncr->bank[(addr >> 15) & 3]; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xff; + + return *(uint8_t *)&svga->vram[addr & svga->vram_mask]; +} +static uint16_t ncr_readw(uint32_t addr, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + svga_t *svga = &ncr->svga; + + addr = (addr & 0xffff) + ncr->bank[(addr >> 15) & 3]; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; + return *(uint16_t *)&svga->vram[addr & svga->vram_mask]; +} +static uint32_t ncr_readl(uint32_t addr, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + svga_t *svga = &ncr->svga; + + addr = (addr & 0xffff) + ncr->bank[(addr >> 15) & 3]; + + addr &= svga->decode_mask; + if (addr >= svga->vram_max) + return 0xffff; + + return *(uint32_t *)&svga->vram[addr & svga->vram_mask]; +} + +static uint8_t blitter_rop(uint8_t rop, uint8_t src, uint8_t pat, uint8_t dst) +{ + uint8_t out = 0; + for (int c = 0; c < 8; c++) { + uint8_t d = (dst & (1 << c)) ? 1 : 0; + if (src & (1 << c)) + d |= 2; + if (pat & (1 << c)) + d |= 4; + if (rop & (1 << d)) + out |= (1 << c); + } + return out; +} + +static uint8_t blitter_read(ncr_t *ncr, uint32_t addr) +{ + uint32_t offset = ((addr >> 3) + ncr->blt_bpp) & ncr->vram_mask; + return ncr->svga.vram[offset]; +} + +static void blitter_write(ncr_t *ncr, uint32_t addr, uint8_t v) +{ + uint32_t offset = ((addr >> 3) + ncr->blt_bpp) & ncr->vram_mask; + ncr->svga.vram[offset] = v; + ncr->svga.changedvram[offset >> 12] = changeframecount; +} + +static bool blitter_proc(ncr_t *ncr) +{ + bool colorfill = (ncr->blt_control & (1 << 9)) != 0; + bool colorexpand = (ncr->blt_control & (1 << 11)) != 0; + int32_t bpp = ncr->svga.bpp; + bool next = false; + + if (ncr->blt_stage == 0) { + uint8_t src = 0; + if (!(ncr->blt_control & (1 << 15))) { + // waiting for fifo write? + if (ncr->blt_fifo_size < 8) { + ncr->blt_fifo_write = 1; + return false; + } + if (ncr->blt_first_expand && colorexpand && ncr->blt_expand_offset) { + ncr->blt_fifo_size -= ncr->blt_expand_offset; + ncr->blt_fifo_data >>= ncr->blt_expand_offset; + ncr->blt_first_expand = 0; + if (ncr->blt_fifo_size < 8) { + ncr->blt_fifo_write = 1; + return false; + } + } + src = ncr->blt_fifo_data & 0xff; + ncr->blt_fifo_data >>= 8; + ncr->blt_fifo_size -= 8; + ncr->blt_fifo_write = 0; + } else { + src = blitter_read(ncr, ncr->blt_src); + } + + ncr->blt_srcdata = src; + ncr->blt_stage++; + } + + if (ncr->blt_stage == 1) { + + uint8_t skip = 0; + uint8_t srcdata = ncr->blt_srcdata; + if (colorexpand) { + int8_t offset = ncr->blt_expand_bit; + if (offset < 8) { + if (srcdata & (1 << offset)) { + srcdata = ncr->blt_c0 >> (ncr->blt_bpp * 8); + } else if (ncr->blt_control & (1 << 5)) { + /// transparent + skip = 1; + } else { + srcdata = ncr->blt_c1 >> (ncr->blt_bpp * 8); + } + } + } + if (!skip) { + ncr->blt_patdata = blitter_read(ncr, ncr->blt_pat); + ncr->blt_dstdata = blitter_read(ncr, ncr->blt_dst); + uint8_t out = blitter_rop(ncr->blt_rop, srcdata, ncr->blt_patdata, ncr->blt_dstdata); + blitter_write(ncr, ncr->blt_dst, out); + } + + ncr->blt_bpp++; + if (ncr->blt_bpp == bpp / 8) { + ncr->blt_bpp = 0; + int16_t dir = (ncr->blt_control & (1 << 7)) ? 1 : -1; + int16_t dx = (bpp / 8) * dir; + + if (colorexpand) { + ncr->blt_expand_bit--; + if (ncr->blt_expand_bit < 0) { + ncr->blt_expand_bit = 7; + ncr->blt_src += (1 << 3) * dir; + ncr->blt_stage = 0; + } else { + ncr->blt_stage = 1; + } + } else { + ncr->blt_src += dx << 3; + ncr->blt_stage = 0; + } + ncr->blt_dst += dx << 3; + + int16_t patsize = (ncr->blt_control & (1 << 4)) ? 16 : 8; + ncr->blt_patx++; + ncr->blt_pat += dx << 3; + if (ncr->blt_patx == patsize) { + ncr->blt_patx = 0; + ncr->blt_pat = ncr->blt_patbak; + } + + next = true; + + } else { + if (colorexpand) { + ncr->blt_stage = 1; + } else { + ncr->blt_stage = 0; + } + } + + } + return next; +} + +static void blitter_done(ncr_t *ncr) +{ + ncr->blt_status = 1; + ncr->blt_start &= ~1; +} + +static void blitter_run(ncr_t *ncr) +{ + for (;;) { + if (ncr->blt_status & 1) { + return; + } + if (ncr->blt_fifo_read > 0 || ncr->blt_fifo_write > 0) { + break; + } + if (blitter_proc(ncr)) { + ncr->blt_w++; + if (ncr->blt_w >= ncr->blt_width) { + ncr->blt_w = 0; + ncr->blt_first_expand = 1; + int bpp = ncr->svga.bpp / 8; + int dir = (ncr->blt_control & (1 << 6)) ? 1 : -1; + int dy = dir * ncr->svga.rowoffset * 8; + + ncr->blt_fifo_size = 0; + + if (!(ncr->blt_control & (1 << 12))) { + ncr->blt_dstbak += dy << 3; + ncr->blt_dst = ncr->blt_dstbak; + } + + if (!(ncr->blt_control & (1 << 13))) { + ncr->blt_srcbak += dy << 3; + ncr->blt_src = ncr->blt_srcbak; + } + + if (!(ncr->blt_control & (1 << 9))) { + int patsize = (ncr->blt_control & (1 << 4)) ? 16 : 8; + int patdx = (ncr->svga.bpp / 4) << 3; + ncr->blt_paty++; + ncr->blt_patbak += dir * patdx; + if (ncr->blt_paty == patsize) { + ncr->blt_paty = 0; + ncr->blt_patbak = ncr->blt_patbak2; + } + ncr->blt_pat = ncr->blt_patbak; + } + + ncr->blt_h++; + if (ncr->blt_h >= ncr->blt_height) { + blitter_done(ncr); + break; + } + } + } + } +} + +static void blitter_write_fifo(ncr_t *ncr, uint32_t v, int size) +{ + ncr->blt_fifo_write = -1; + ncr->blt_fifo_data <<= ncr->blt_fifo_size; + ncr->blt_fifo_data |= ((uint64_t)v) << ncr->blt_fifo_size; + ncr->blt_fifo_size += 32; + blitter_run(ncr); +} + + +static void blitter_start(ncr_t *ncr) +{ +#if 1 + pclog("C=%04x ROP=%02x W=%d H=%d S=%08x/%d P=%08x/%d D=%08x/%d F=%d E=%d DM=%d SM=%d DL=%d SL=%d TR=%d MW=%d\n", + ncr->blt_control, ncr->blt_rop, ncr->blt_width, ncr->blt_height, + ncr->blt_src >> 3, ncr->blt_src & 7, + ncr->blt_pat >> 3, ncr->blt_pat & 7, + ncr->blt_dst >> 3, ncr->blt_dst & 7, + (ncr->blt_control & (1 << 9)) != 0, + (ncr->blt_control & (1 << 11)) != 0, + (ncr->blt_control & (1 << 12)) != 0, + (ncr->blt_control & (1 << 13)) != 0, + (ncr->blt_control & (1 << 14)) != 0, + (ncr->blt_control & (1 << 15)) != 0, + (ncr->blt_control & (1 << 5)) != 0, + (ncr->blt_control & (1 << 3)) != 0); +#endif + ncr->blt_status = 0; + if (ncr->blt_start & 2) { + pclog("text blits not implemenented"); + blitter_done(ncr); + return; + } + ncr->blt_expand_offset = ncr->blt_src & 31; + ncr->blt_expand_bit = 7; + ncr->blt_first_expand = 1; + ncr->blt_srcbak = ncr->blt_src; + ncr->blt_dstbak = ncr->blt_dst; + ncr->blt_patbak = ncr->blt_pat; + ncr->blt_patbak2 = ncr->blt_pat; + ncr->blt_w = 0; + ncr->blt_h = 0; + ncr->blt_fifo_read = 0; + ncr->blt_fifo_write = 0; + ncr->blt_fifo_size = 0; + ncr->blt_fifo_data = 0; + ncr->blt_stage = 0; + ncr->blt_patx = 0; + ncr->blt_paty = 0; + ncr->blt_patdone = 0; + blitter_run(ncr); + //activate_debugger(); +} + +static void ncr_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + ncr_t *ncr = (ncr_t*)p; + int reg = addr & 0xff; + switch (reg) + { + case 0x09: // mode control + ncr->svga.seqregs[0x01e] = val; + ncr_updatemapping(ncr); + break; + case 0x30: // blitter start + ncr->blt_start = val; + if (val & 1) { + blitter_start(ncr); + } + break; + case 0x38: // pattern x rotation + ncr->blt_hprot = val; + break; + case 0x39: // pattern y rotation + ncr->blt_vprot = val; + break; + case 0x03a: // rop + ncr->blt_rop = val; + break; + } +} + +static void ncr_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + ncr_t *ncr = (ncr_t*)p; + int reg = (addr & 0xff) & ~1; + switch(reg) + { + case 0x00: // primary host offset + break; + case 0x04: // secondary host offset + break; + case 0x0c: // cursor x + ncr->svga.hwcursor.x = val & ((1 << 10) - 1); + break; + case 0x0e: // cursor y + ncr->svga.hwcursor.y = val & ((1 << 11) - 1); + break; + case 0x34: // blitter control + ncr->blt_control = val; + break; + case 0x3c: // blitter bitmap width + ncr->blt_width = val; + break; + case 0x3e: // blitter bitmap height + ncr->blt_height = val; + break; + case 0x40: // blitter destination + ncr->blt_dst &= 0xffff0000; + ncr->blt_dst |= val << 0; + break; + case 0x42: + ncr->blt_dst &= 0x0000ffff; + ncr->blt_dst |= val << 16; + break; + case 0x44: // blitter source + ncr->blt_src &= 0xffff0000; + ncr->blt_src |= val << 0; + break; + case 0x46: + ncr->blt_src &= 0x0000ffff; + ncr->blt_src |= val << 16; + break; + case 0x48: // blitter pattern + ncr->blt_pat &= 0xffff0000; + ncr->blt_pat |= val << 0; + break; + case 0x4a: + ncr->blt_pat &= 0x0000ffff; + ncr->blt_pat |= val << 16; + break; + case 0x4c: // foreground + ncr->blt_c0 &= 0xffff0000; + ncr->blt_c0 |= val << 0; + break; + case 0x4e: + ncr->blt_c0 &= 0x0000ffff; + ncr->blt_c0 |= val << 16; + break; + case 0x50: // foreground + ncr->blt_c1 &= 0xffff0000; + ncr->blt_c1 |= val << 0; + break; + case 0x52: + ncr->blt_c1 &= 0x0000ffff; + ncr->blt_c1 |= val << 16; + break; + default: + ncr_mmio_write(addr + 0, (uint8_t)val, p); + ncr_mmio_write(addr + 1, val >> 8, p); + break; + } + +} +static void ncr_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + ncr_t *ncr = (ncr_t*)p; + int reg = (addr & 0xff) & ~3; + ncr_mmio_write_w(addr + 0, val, p); + ncr_mmio_write_w(addr + 2, val >> 16, p); + +} + +static uint8_t ncr_mmio_read(uint32_t addr, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + int reg = addr & 0xff; + uint8_t val = 0; + switch(reg) + { + case 0x09: // mode control + val = ncr->svga.seqregs[0x1e]; + break; + case 0x30: + val = ncr->blt_start; + break; + case 0x32: // blt status + val = ncr->blt_status; + break; + default: + pclog("blitter read reg %02x\n", reg); + break; + + + } + + return val; +} + +static uint16_t ncr_mmio_readw(uint32_t addr, void *p) +{ + uint16_t v; + v = ncr_mmio_read(addr + 0, p); + v |= ncr_mmio_read(addr + 1, p) << 8; + return v; +} + +static uint32_t ncr_mmio_readl(uint32_t addr, void *p) +{ + uint32_t v; + v = ncr_mmio_read(addr + 0, p); + v |= ncr_mmio_read(addr + 2, p) << 16; + return v; +} + +static void ncr_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + ncr_t *ncr = (ncr_t *)svga->p; + svga_write_linear(addr, val, p); +} +static void ncr_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + ncr_t *ncr = (ncr_t *)svga->p; + svga_writew_linear(addr, val, p); +} +static void ncr_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + ncr_t *ncr = (ncr_t *)svga->p; + if (ncr->blt_fifo_write > 0) { + blitter_write_fifo(ncr, val, 2); + return; + } + svga_writel_linear(addr, val, p); +} + + +void ncr_updatebanking(ncr_t *ncr) +{ + svga_t *svga = &ncr->svga; + + svga->banked_mask = 0xffff; + ncr->bank[0] = (svga->seqregs[0x18] << 8) | svga->seqregs[0x19]; + if (svga->seqregs[0x1e] & 0x4) { + ncr->bank[1] = (svga->seqregs[0x1c] << 8) | svga->seqregs[0x1d]; + } else { + ncr->bank[1] = ncr->bank[0] + 0x8000; + } + if (svga->seqregs[0x1e] & 0x10) { + ncr->bank[0] <<= 6; + ncr->bank[1] <<= 6; + } + int mode = svga->seqregs[0x1e] >> 5; + if (mode != 2 && mode != 3 && mode != 6) { + pclog("unsupport banking mode %d\n", mode); + } + // Primary at A0000h-AFFFFh, Secondary at B0000h-BFFFFh. Both Read / Write. + if (mode == 2) { + ncr->bank[2] = ncr->bank[1]; + ncr->bank[3] = ncr->bank[1]; + ncr->bank[1] = ncr->bank[0]; + } else { + ncr->bank[2] = ncr->bank[0]; + ncr->bank[3] = ncr->bank[1]; + } + // Read and Write to Secondary only + if (mode == 3) { + ncr->bank[0] = ncr->bank[1]; + ncr->bank[2] = ncr->bank[3]; + } +} + +void ncr_updatemapping(ncr_t *ncr) +{ + svga_t *svga = &ncr->svga; + + ncr_updatebanking(ncr); + + mem_mapping_disablex(&svga->mapping); + mem_mapping_disablex(&ncr->mmio_mapping); + mem_mapping_disablex(&ncr->linear_mapping); + + if (ncr->chip == NCR_TYPE_32BLT) { + ncr->linear_size = 0x100000 << (svga->seqregs[0x1a] & 3); + if (ncr->linear_size > 0x400000) + ncr->linear_size = 0x400000; + ncr->linear_base = ((svga->seqregs[0x1a] >> 4) << 20) | (svga->seqregs[0x1b] << 24); + ncr->linear_base &= ~(ncr->linear_size - 1); + mem_mapping_set_addrx(&ncr->linear_mapping, ncr->linear_base, ncr->linear_size); + + if (svga->seqregs[0x30] & 1) { + ncr->mmio_base = (svga->seqregs[0x31] << 8) | (svga->seqregs[0x32] << 16) | (svga->seqregs[0x33] << 24); + ncr->mmio_size = 0x100; + mem_mapping_set_addrx(&ncr->mmio_mapping, ncr->mmio_base, ncr->mmio_size); + mem_mapping_enablex(&ncr->mmio_mapping); + } else { + mem_mapping_disablex(&ncr->mmio_mapping); + } + + } else { + + mem_mapping_set_addrx(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_enablex(&svga->mapping); +#if 0 + pclog("%08x %08x (%04x %04x %02x)\n", ncr->bank[0], ncr->bank[1], + (svga->seqregs[0x18] << 8) | svga->seqregs[0x19], (svga->seqregs[0x1c] << 8) | svga->seqregs[0x1d], + svga->seqregs[0x1e]); +#endif + } +} + +static inline uint32_t dword_remap(uint32_t in_addr) +{ + return in_addr; +} + +static void ncr_io_remove(ncr_t *ncr) +{ + io_removehandlerx(0x03c0, 0x0020, ncr_in, NULL, NULL, ncr_out, NULL, NULL, ncr); +} + +static void ncr_io_set(ncr_t *ncr) +{ + ncr_io_remove(ncr); + + io_sethandlerx(0x03c0, 0x0020, ncr_in, NULL, NULL, ncr_out, NULL, NULL, ncr); +} + +static void *ncr_init(char *bios_fn, int chip) +{ + ncr_t *ncr = (ncr_t*)calloc(sizeof(ncr_t), 1); + svga_t *svga = &ncr->svga; + int vram; + uint32_t vram_size; + + memset(ncr, 0, sizeof(ncr_t)); + + vram = device_get_config_int("memory"); + if (vram) + vram_size = vram << 20; + else + vram_size = 512 << 10; + ncr->vram_mask = vram_size - 1; + + rom_init(&ncr->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&ncr->svga, ncr, vram_size, + ncr_recalctimings, + ncr_in, ncr_out, + ncr_hwcursor_draw, + NULL); + + mem_mapping_addx(&ncr->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, ncr_write_linear, ncr_writew_linear, ncr_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &ncr->svga); + mem_mapping_set_handlerx(&ncr->svga.mapping, ncr_read, ncr_readw, ncr_readl, ncr_write, ncr_writew, ncr_writel); + mem_mapping_addx(&ncr->mmio_mapping, 0xa0000, 0x10000, ncr_mmio_read, ncr_mmio_readw, ncr_mmio_readl, ncr_mmio_write, ncr_mmio_write_w, ncr_mmio_write_l, NULL, MEM_MAPPING_EXTERNAL, ncr); + mem_mapping_set_px(&ncr->svga.mapping, ncr); + mem_mapping_disablex(&ncr->mmio_mapping); + + svga->decode_mask = (4 << 20) - 1; + switch (vram) + { + case 0: /*512kb*/ + svga->vram_mask = (1 << 19) - 1; + svga->vram_max = 4 << 20; + break; + case 1: /*1MB*/ + svga->vram_mask = (1 << 20) - 1; + svga->vram_max = 4 << 20; + break; + case 2: default: /*2MB*/ + svga->vram_mask = (2 << 20) - 1; + svga->vram_max = 4 << 20; + break; + case 4: /*4MB*/ + svga->vram_mask = (4 << 20) - 1; + svga->vram_max = 4 << 20; + break; + } + + svga->vblank_start = ncr_vblank_start; + ncr->vblank_irq = -1; + + ncr_io_set(ncr); + + ncr->chip = chip; + ncr->blt_status = 1; + + ncr_updatemapping(ncr); + + return ncr; +} + +void *ncr_retina_z2_init() +{ + ncr_t *ncr = (ncr_t *)ncr_init("ncr.bin", NCR_TYPE_22EP); + + //ncr->getclock = ncr_getclock; + //ncr->getclock_p = ncr; + ncr->svga.fb_only = 0; + svga_set_ramdac_type(&ncr->svga, RAMDAC_8BIT); + + return ncr; +} + +void *ncr_retina_z3_init() +{ + ncr_t *ncr = (ncr_t *)ncr_init("ncr.bin", NCR_TYPE_32BLT); + + //ncr->getclock = ncr_getclock; + //ncr->getclock_p = ncr; + ncr->svga.fb_only = -1; + + return ncr; +} + +void ncr_close(void *p) +{ + ncr_t *ncr = (ncr_t*)p; + + svga_close(&ncr->svga); + + free(ncr); +} + +void ncr_speed_changed(void *p) +{ + ncr_t *ncr = (ncr_t *)p; + + svga_recalctimings(&ncr->svga); +} + +void ncr_force_redraw(void *p) +{ + ncr_t *ncr = (ncr_t *)p; + + ncr->svga.fullchange = changeframecount; +} + +void ncr_add_status_info(char *s, int max_len, void *p) +{ + ncr_t *ncr = (ncr_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - ncr->status_time; + ncr->status_time = new_time; + + if (!status_diff) + status_diff = 1; + + svga_add_status_info(s, max_len, &ncr->svga); + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)ncr->blitter_time * 100.0) / timer_freq, ((double)ncr->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + ncr->blitter_time = 0; +} + +device_t ncr_retina_z2_device = +{ + "NCR 77C22E+", + 0, + ncr_retina_z2_init, + ncr_close, + NULL, + ncr_speed_changed, + ncr_force_redraw, + ncr_add_status_info, + NULL +}; + +device_t ncr_retina_z3_device = +{ + "NCR 77C32BLT", + 0, + ncr_retina_z3_init, + ncr_close, + NULL, + ncr_speed_changed, + ncr_force_redraw, + ncr_add_status_info, + NULL +}; diff --git a/pcem/vid_ncr.h b/pcem/vid_ncr.h new file mode 100644 index 00000000..13450ce8 --- /dev/null +++ b/pcem/vid_ncr.h @@ -0,0 +1,2 @@ +extern device_t ncr_retina_z2_device; +extern device_t ncr_retina_z3_device; -- 2.47.3