From: Toni Wilen Date: Sat, 24 Sep 2016 11:25:00 +0000 (+0300) Subject: Harlequin frame buffer. X-Git-Tag: 3400~80 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=28b9c18e3d827b2b5191f5fa07f562f75849b7ad;p=francis%2Fwinuae.git Harlequin frame buffer. --- diff --git a/framebufferboards.cpp b/framebufferboards.cpp new file mode 100644 index 00000000..d272a052 --- /dev/null +++ b/framebufferboards.cpp @@ -0,0 +1,500 @@ + +/* +* UAE - The Un*x Amiga Emulator +* +* Misc frame buffer boards +* +* - Harlequin +* +*/ +#include "sysconfig.h" +#include "sysdeps.h" + +#include "options.h" +#include "debug.h" +#include "memory.h" +#include "custom.h" +#include "picasso96.h" +#include "gfxboard.h" +#include "statusline.h" +#include "rommgr.h" +#include "framebufferboards.h" + +typedef uae_u32(REGPARAM3 *fb_get_func)(struct fb_struct *, uaecptr) REGPARAM; +typedef void (REGPARAM3 *fb_put_func)(struct fb_struct *, uaecptr, uae_u32) REGPARAM; + +extern addrbank generic_fb_bank; + +struct fb_struct +{ + int devnum; + uae_u32 configured; + uae_u32 io_start, io_end; + uae_u8 data[16]; + + bool enabled; + bool modechanged; + bool visible; + int width, height; + bool lace; + RGBFTYPE rgbtype; + + int fb_offset; + int fb_offset_limit; + int fb_vram_mask; + int fb_vram_size; + bool fb_modified; + uae_u8 *fb; + uae_u8 *surface; + bool isalpha; + bool ntsc; + bool genlock; + int model; + int irq; + + fb_get_func lget, wget, bget; + fb_put_func lput, wput, bput; +}; + +static struct fb_struct *fb_data[MAX_RTG_BOARDS]; + +static int fb_boards; +static struct fb_struct *fb_last; + + +static bool fb_get_surface(struct fb_struct *data) +{ + bool gotsurf = false; + if (picasso_on) { + if (data->surface == NULL) { + data->surface = gfx_lock_picasso(false, false); + gotsurf = true; + } + if (data->surface && gotsurf) { + if (!(currprefs.leds_on_screen & STATUSLINE_TARGET)) + picasso_statusline(data->surface); + } + } + return data->surface != NULL; +} +static void fb_free_surface(struct fb_struct *data) +{ + if (!data->surface) + return; + gfx_unlock_picasso(true); + data->surface = NULL; +} + +static void harlequin_offset(struct fb_struct *data) +{ + int offset = data->data[0] & 0x3f; + data->fb_offset = offset * 65536; +} + +static void harlequin_setmode(struct fb_struct *data) +{ + int mode = data->data[1] & 3; + switch (mode) + { + case 0: + case 3: + data->width = 910; + break; + case 1: + data->width = 832; + break; + case 2: + data->width = 740; + break; + } + data->lace = (data->data[1] & 8) != 0; + data->height = data->ntsc ? 486 : 576; +} + +static void REGPARAM2 harlequin_wput(struct fb_struct *data, uaecptr addr, uae_u32 w) +{ + addr &= 0x1ffff; + if (addr == 0) { + uae_u8 old0 = data->data[0]; + uae_u8 old1 = data->data[1]; + data->data[0] = (uae_u8)(w >> 8); + data->data[1] = (uae_u8)(w >> 0); + data->data[0] &= ~0x80; + data->data[0] |= data->genlock ? 0x00 : 0x80; + if ((data->data[0] & 0x40) != (old0 & 0x40)) + data->fb_modified = true; + if (data->data[1] != old1) + data->fb_modified = true; + harlequin_offset(data); + harlequin_setmode(data); + } else if (addr >= 0x10000) { + if (data->fb_offset >= data->fb_offset_limit) + return; + addr -= 0x10000; + if (!data->isalpha) { + if ((addr & 3) == 2) + w &= 0xff00; + if ((addr & 3) == 3) + w &= 0x00ff; + } + data->fb[data->fb_offset + addr + 0] = (uae_u8)(w >> 8); + data->fb[data->fb_offset + addr + 1] = (uae_u8)(w >> 0); + data->fb_modified = true; + } +} +static void REGPARAM2 harlequin_bput(struct fb_struct *data, uaecptr addr, uae_u32 b) +{ + addr &= 0x1ffff; + if (addr == 2) { + data->data[2] = b; + data->irq = 0; + } else if (addr >= 0x20 && addr < 0x30) { + write_log(_T("RAMDAC WRITE %0x = %02x\n"), addr, (uae_u8)b); + } else if (addr >= 0x10000) { + if (data->fb_offset >= data->fb_offset_limit) + return; + addr -= 0x10000; + if (!data->isalpha && (addr & 3) == 3) + b = 0; + data->fb[data->fb_offset + addr] = (uae_u8)b; + data->fb_modified = true; + } +} +static uae_u32 REGPARAM2 harlequin_wget(struct fb_struct *data, uaecptr addr) +{ + uae_u16 v = 0; + addr &= 0x1ffff; + if (addr == 0) { + v = (data->data[0] << 8) | (data->data[1] << 0); + } else if (addr >= 0x10000) { + if (data->fb_offset >= data->fb_offset_limit) + return 0; + addr -= 0x10000; + v = data->fb[data->fb_offset + addr + 0] << 8; + v |= data->fb[data->fb_offset + addr + 1] << 0; + } + return v; +} +static uae_u32 REGPARAM2 harlequin_bget(struct fb_struct *data, uaecptr addr) +{ + uae_u8 v = 0; + addr &= 0x1ffff; + if (addr == 0 || addr == 1 || addr == 2) { + v = data->data[addr]; + } else if (addr >= 0x20 && addr < 0x30) { + write_log(_T("RAMDAC READ %0x\n"), addr); + } else if (addr >= 0x10000) { + if (data->fb_offset >= data->fb_offset_limit) + return 0; + addr -= 0x10000; + v = data->fb[data->fb_offset + addr]; + } + return 0; +} + +static bool harlequin_init(struct autoconfig_info *aci) +{ + uae_u8 model = 100; + int vram = 0x200000; + bool isac = true; + bool ntsc = false; + + aci->label = _T("Harlequin"); + + struct boardromconfig *brc = get_device_rom(aci->prefs, ROMTYPE_HARLEQUIN, gfxboard_get_devnum(aci->prefs, aci->devnum), NULL); + if (brc) { + model = (brc->roms[0].device_settings & 3) + 100; + ntsc = (model & 1) != 0; + } + aci->autoconfig_bytes[1] = model; + + if (!aci->doinit) { + return true; + } + struct fb_struct *data = xcalloc(struct fb_struct, 1); + data->devnum = aci->devnum; + fb_data[data->devnum] = data; + + data->bget = harlequin_bget; + data->wget = harlequin_wget; + data->bput = harlequin_bput; + data->wput = harlequin_wput; + + if (brc) { + switch((brc->roms[0].device_settings >> 2) & 3) + { + case 0: // 1.5M + vram = 0x200000; + isac = false; + break; + case 1: // 2M + vram = 0x200000; + isac = true; + break; + case 2: // 3M + vram = 0x400000; + isac = false; + break; + case 3: // 4M + vram = 0x400000; + isac = true; + break; + } + data->genlock = ((brc->roms[0].device_settings >> 4) & 1) != 0; + } + + data->model = model; + data->ntsc = ntsc; + data->isalpha = isac; + data->fb_vram_size = vram; + data->fb_vram_mask = data->fb_vram_size - 1; + data->fb_offset_limit = vram; + data->fb = xcalloc(uae_u8, data->fb_vram_size); + + data->rgbtype = RGBFB_R8G8B8A8; + + harlequin_setmode(data); + + aci->addrbank = &generic_fb_bank; + aci->userdata = data; + + fb_boards++; + return true; +} +static void harlequin_free(void *userdata) +{ + struct fb_struct *data = (struct fb_struct*)userdata; + + fb_free_surface(data); + + xfree(data->fb); + data->fb = NULL; + + fb_data[data->devnum] = NULL; + xfree(data); +} + +static void fb_irq(struct fb_struct *data) +{ + if (!data->irq) + return; + if (data->irq == 2) + INTREQ_0(0x8000 | 0x0008); + else if (data->irq == 6) + INTREQ_0(0x8000 | 0x2000); +} + +static void harlequin_reset(void *userdata) +{ + struct fb_struct *data = (struct fb_struct*)userdata; + fb_boards = 0; + fb_last = NULL; +} + +static void harlequin_hsync(void *userdata) +{ + struct fb_struct *data = (struct fb_struct*)userdata; + fb_irq(data); +} + +static void harlequin_convert(struct fb_struct *data) +{ + bool r = (data->data[1] & 0x80) != 0; + bool g = (data->data[1] & 0x40) != 0; + bool b = (data->data[1] & 0x20) != 0; + int buf = (data->data[0] & 0x40) ? 1 : 0; + int offset = 0, laceoffset = 0; + int laceoffsetv = (data->width * data->height / 2) * 4; + + if (buf && data->fb_vram_size > 0x200000) + offset += data->fb_vram_size / 2; + + int sy = 0; + int w = picasso_vidinfo.width < data->width ? picasso_vidinfo.width : data->width; + int h = picasso_vidinfo.height < data->height ? picasso_vidinfo.height : data->height; + for (int y = 0; y < h; y++) { + uae_u8 *s = data->fb + offset + laceoffset + sy * data->width * 4; + if (r && g && b) { + fb_copyrow(s, data->surface, 0, 0, data->width, 4, y); + } else { + uae_u8 tmp[1000 * 4]; + uae_u8 *d = tmp; + for (int x = 0; x < w * 4; x += 4) { + d[x + 0] = r ? s[x + 0] : 0; + d[x + 1] = g ? s[x + 1] : 0; + d[x + 2] = b ? s[x + 2] : 0; + d[x + 3] = 0; + } + fb_copyrow(d, data->surface, 0, 0, data->width, 4, y); + } + if (data->lace) { + laceoffset = laceoffset ? 0 : laceoffsetv; + if (!laceoffset) + sy++; + } else { + sy++; + } + } +} + +static bool harlequin_vsync(void *userdata, struct gfxboard_mode *mode) +{ + struct fb_struct *data = (struct fb_struct*)userdata; + bool rendered = false; + + if (data->model >= 102) { + data->data[2] |= 0x80; + if (data->data[2] & 0x40) { + data->irq = 2; + fb_irq(data); + } + } + + if (data->visible) { + + mode->width = data->width; + mode->height = data->height; + mode->mode = data->rgbtype; + + if (fb_get_surface(data)) { + if (data->fb_modified || data->modechanged || mode->redraw_required) { + + data->fb_modified = false; + data->modechanged = false; + + harlequin_convert(data); + } + fb_free_surface(data); + rendered = true; + } + + } + + return rendered; +} + +static bool harlequin_toggle(void *userdata, int mode) +{ + struct fb_struct *data = (struct fb_struct*)userdata; + + if (!data->configured) + return false; + + if (!mode) { + if (!data->enabled) + return false; + data->enabled = false; + data->modechanged = false; + data->visible = false; + return true; + } else { + if (data->enabled) + return false; + data->enabled = true; + data->modechanged = true; + data->visible = true; + return true; + } + return false; +} + +static void harlequin_configured(void *userdata, uae_u32 address) +{ + struct fb_struct *data = (struct fb_struct*)userdata; + + data->configured = address; + data->io_start = address; + data->io_end = data->io_start + 0x20000; +} + +static struct fb_struct *getfbboard(uaecptr addr) +{ + if (fb_boards == 1) + return fb_data[0]; + if (fb_last && addr >= fb_last->io_start && addr io_end) + return fb_last; + for (int i = 0; i < MAX_RTG_BOARDS; i++) { + struct fb_struct *fb = fb_data[i]; + if (!fb) + continue; + if (!fb->configured) + continue; + if (addr >= fb->io_start && addr < fb->io_end) { + fb_last = fb; + return fb; + } + } + return NULL; +} + +static void REGPARAM2 fb_lput(uaecptr addr, uae_u32 w) +{ + struct fb_struct *data = getfbboard(addr); + if (data) { + data->wput(data, addr + 0, w >> 16); + data->wput(data, addr + 2, w & 65535); + } +} +static void REGPARAM2 fb_wput(uaecptr addr, uae_u32 w) +{ + struct fb_struct *data = getfbboard(addr); + if (data) { + data->wput(data, addr, w); + } +} +static void REGPARAM2 fb_bput(uaecptr addr, uae_u32 w) +{ + struct fb_struct *data = getfbboard(addr); + if (data) { + data->bput(data, addr, w); + } +} + +static uae_u32 REGPARAM2 fb_bget(uaecptr addr) +{ + uae_u32 v = 0; + struct fb_struct *data = getfbboard(addr); + if (data) { + v = data->bget(data, addr); + } + return v; +} +static uae_u32 REGPARAM2 fb_wget(uaecptr addr) +{ + uae_u32 v = 0; + struct fb_struct *data = getfbboard(addr); + if (data) { + v = data->wget(data, addr); + } + return v; +} +static uae_u32 REGPARAM2 fb_lget(uaecptr addr) +{ + uae_u32 v = 0; + struct fb_struct *data = getfbboard(addr); + if (data) { + v = data->wget(data, addr) << 16; + v |= data->wget(data, addr + 2); + } + return v; +} + +static addrbank generic_fb_bank +{ + fb_lget, fb_wget, fb_bget, + fb_lput, fb_wput, fb_bput, + default_xlate, default_check, NULL, NULL, _T("FRAMEBUFFER BOARD"), + fb_lget, fb_wget, + ABFLAG_IO, S_READ, S_WRITE +}; + +struct gfxboard_func harlequin_func +{ + harlequin_init, + harlequin_free, + harlequin_reset, + harlequin_hsync, + harlequin_vsync, + harlequin_toggle, + harlequin_configured +}; diff --git a/include/framebufferboards.h b/include/framebufferboards.h new file mode 100644 index 00000000..e69de29b