mirror of
https://github.com/LIV2/WinUAE.git
synced 2025-12-06 00:12:52 +00:00
506 lines
11 KiB
C++
506 lines
11 KiB
C++
|
|
/*
|
|
* 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"
|
|
#include "xwin.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;
|
|
int monitor_id;
|
|
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)
|
|
{
|
|
struct amigadisplay *ad = &adisplays[data->monitor_id];
|
|
if (ad->picasso_on) {
|
|
if (data->surface == NULL) {
|
|
data->surface = gfx_lock_picasso(data->monitor_id, false);
|
|
}
|
|
}
|
|
return data->surface != NULL;
|
|
}
|
|
static void fb_free_surface(struct fb_struct *data)
|
|
{
|
|
if (!data->surface)
|
|
return;
|
|
gfx_unlock_picasso(data->monitor_id, 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)
|
|
{
|
|
struct picasso_vidbuf_description *vidinfo = &picasso_vidinfo[data->monitor_id];
|
|
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 = vidinfo->width < data->width ? vidinfo->width : data->width;
|
|
int h = vidinfo->height < data->height ? 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(data->monitor_id, 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(data->monitor_id, 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;
|
|
mode->hlinedbl = 1;
|
|
mode->vlinedbl = 1;
|
|
|
|
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
|
|
};
|
|
|
|
static void harlequin_refresh(void *userdata)
|
|
{
|
|
}
|
|
|
|
struct gfxboard_func harlequin_func
|
|
{
|
|
harlequin_init,
|
|
harlequin_free,
|
|
harlequin_reset,
|
|
harlequin_hsync,
|
|
harlequin_vsync,
|
|
harlequin_refresh,
|
|
harlequin_toggle,
|
|
harlequin_configured
|
|
};
|