]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
Harlequin frame buffer.
authorToni Wilen <twilen@winuae.net>
Sat, 24 Sep 2016 11:25:00 +0000 (14:25 +0300)
committerToni Wilen <twilen@winuae.net>
Sat, 24 Sep 2016 11:25:00 +0000 (14:25 +0300)
framebufferboards.cpp [new file with mode: 0644]
include/framebufferboards.h [new file with mode: 0644]

diff --git a/framebufferboards.cpp b/framebufferboards.cpp
new file mode 100644 (file)
index 0000000..d272a05
--- /dev/null
@@ -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 <fb_last->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 (file)
index 0000000..e69de29