macfb: implement mode sense to allow display type to be detected

The MacOS toolbox ROM uses the monitor sense to detect the display type and then
offer a fixed set of resolutions and colour depths accordingly. Implement the
monitor sense using information found in Apple Technical Note HW26: "Macintosh
Quadra Built-In Video" along with some local experiments.

Since the default configuration is 640 x 480 with 8-bit colour then hardcode
the sense register to return MACFB_DISPLAY_VGA for now.

Signed-off-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>
Reviewed-by: Laurent Vivier <laurent@vivier.eu>
Message-Id: <20211007221253.29024-8-mark.cave-ayland@ilande.co.uk>
Signed-off-by: Laurent Vivier <laurent@vivier.eu>
This commit is contained in:
Mark Cave-Ayland 2021-10-07 23:12:47 +01:00 committed by Laurent Vivier
parent 4ec27073fd
commit e6108b9636
3 changed files with 137 additions and 2 deletions

View File

@ -28,8 +28,66 @@
#define MACFB_PAGE_SIZE 4096
#define MACFB_VRAM_SIZE (4 * MiB)
#define DAFB_RESET 0x200
#define DAFB_LUT 0x213
#define DAFB_MODE_SENSE 0x1c
#define DAFB_RESET 0x200
#define DAFB_LUT 0x213
/*
* Quadra sense codes taken from Apple Technical Note HW26:
* "Macintosh Quadra Built-In Video". The sense codes and
* extended sense codes have different meanings:
*
* Sense:
* bit 2: SENSE2 (pin 10)
* bit 1: SENSE1 (pin 7)
* bit 0: SENSE0 (pin 4)
*
* 0 = pin tied to ground
* 1 = pin unconnected
*
* Extended Sense:
* bit 2: pins 4-10
* bit 1: pins 10-7
* bit 0: pins 7-4
*
* 0 = pins tied together
* 1 = pins unconnected
*
* Reads from the sense register appear to be active low, i.e. a 1 indicates
* that the pin is tied to ground, a 0 indicates the pin is disconnected.
*
* Writes to the sense register appear to activate pulldowns i.e. a 1 enables
* a pulldown on a particular pin.
*
* The MacOS toolbox appears to use a series of reads and writes to first
* determine if extended sense is to be used, and then check which pins are
* tied together in order to determine the display type.
*/
typedef struct MacFbSense {
uint8_t type;
uint8_t sense;
uint8_t ext_sense;
} MacFbSense;
static MacFbSense macfb_sense_table[] = {
{ MACFB_DISPLAY_APPLE_21_COLOR, 0x0, 0 },
{ MACFB_DISPLAY_APPLE_PORTRAIT, 0x1, 0 },
{ MACFB_DISPLAY_APPLE_12_RGB, 0x2, 0 },
{ MACFB_DISPLAY_APPLE_2PAGE_MONO, 0x3, 0 },
{ MACFB_DISPLAY_NTSC_UNDERSCAN, 0x4, 0 },
{ MACFB_DISPLAY_NTSC_OVERSCAN, 0x4, 0 },
{ MACFB_DISPLAY_APPLE_12_MONO, 0x6, 0 },
{ MACFB_DISPLAY_APPLE_13_RGB, 0x6, 0 },
{ MACFB_DISPLAY_16_COLOR, 0x7, 0x3 },
{ MACFB_DISPLAY_PAL1_UNDERSCAN, 0x7, 0x0 },
{ MACFB_DISPLAY_PAL1_OVERSCAN, 0x7, 0x0 },
{ MACFB_DISPLAY_PAL2_UNDERSCAN, 0x7, 0x6 },
{ MACFB_DISPLAY_PAL2_OVERSCAN, 0x7, 0x6 },
{ MACFB_DISPLAY_VGA, 0x7, 0x5 },
{ MACFB_DISPLAY_SVGA, 0x7, 0x5 },
};
typedef void macfb_draw_line_func(MacfbState *s, uint8_t *d, uint32_t addr,
@ -253,6 +311,50 @@ static void macfb_invalidate_display(void *opaque)
memory_region_set_dirty(&s->mem_vram, 0, MACFB_VRAM_SIZE);
}
static uint32_t macfb_sense_read(MacfbState *s)
{
MacFbSense *macfb_sense;
uint8_t sense;
macfb_sense = &macfb_sense_table[MACFB_DISPLAY_VGA];
if (macfb_sense->sense == 0x7) {
/* Extended sense */
sense = 0;
if (!(macfb_sense->ext_sense & 1)) {
/* Pins 7-4 together */
if (~s->sense & 3) {
sense = (~s->sense & 7) | 3;
}
}
if (!(macfb_sense->ext_sense & 2)) {
/* Pins 10-7 together */
if (~s->sense & 6) {
sense = (~s->sense & 7) | 6;
}
}
if (!(macfb_sense->ext_sense & 4)) {
/* Pins 4-10 together */
if (~s->sense & 5) {
sense = (~s->sense & 7) | 5;
}
}
} else {
/* Normal sense */
sense = (~macfb_sense->sense & 7) | (~s->sense & 7);
}
trace_macfb_sense_read(sense);
return sense;
}
static void macfb_sense_write(MacfbState *s, uint32_t val)
{
s->sense = val;
trace_macfb_sense_write(val);
return;
}
static void macfb_update_display(void *opaque)
{
MacfbState *s = opaque;
@ -290,8 +392,15 @@ static uint64_t macfb_ctrl_read(void *opaque,
hwaddr addr,
unsigned int size)
{
MacfbState *s = opaque;
uint64_t val = 0;
switch (addr) {
case DAFB_MODE_SENSE:
val = macfb_sense_read(s);
break;
}
trace_macfb_ctrl_read(addr, val, size);
return val;
}
@ -303,6 +412,9 @@ static void macfb_ctrl_write(void *opaque,
{
MacfbState *s = opaque;
switch (addr) {
case DAFB_MODE_SENSE:
macfb_sense_write(s, val);
break;
case DAFB_RESET:
s->palette_current = 0;
break;
@ -342,6 +454,7 @@ static const VMStateDescription vmstate_macfb = {
.fields = (VMStateField[]) {
VMSTATE_UINT8_ARRAY(color_palette, MacfbState, 256 * 3),
VMSTATE_UINT32(palette_current, MacfbState),
VMSTATE_UINT32(sense, MacfbState),
VMSTATE_END_OF_LIST()
}
};

View File

@ -171,3 +171,5 @@ sm501_2d_engine_write(uint32_t addr, uint32_t val) "addr=0x%x, val=0x%x"
# macfb.c
macfb_ctrl_read(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%"PRIx64 " value 0x%"PRIx64 " size %u"
macfb_ctrl_write(uint64_t addr, uint64_t value, unsigned int size) "addr 0x%"PRIx64 " value 0x%"PRIx64 " size %u"
macfb_sense_read(uint32_t value) "video sense: 0x%"PRIx32
macfb_sense_write(uint32_t value) "video sense: 0x%"PRIx32

View File

@ -17,6 +17,24 @@
#include "ui/console.h"
#include "qom/object.h"
typedef enum {
MACFB_DISPLAY_APPLE_21_COLOR = 0,
MACFB_DISPLAY_APPLE_PORTRAIT = 1,
MACFB_DISPLAY_APPLE_12_RGB = 2,
MACFB_DISPLAY_APPLE_2PAGE_MONO = 3,
MACFB_DISPLAY_NTSC_UNDERSCAN = 4,
MACFB_DISPLAY_NTSC_OVERSCAN = 5,
MACFB_DISPLAY_APPLE_12_MONO = 6,
MACFB_DISPLAY_APPLE_13_RGB = 7,
MACFB_DISPLAY_16_COLOR = 8,
MACFB_DISPLAY_PAL1_UNDERSCAN = 9,
MACFB_DISPLAY_PAL1_OVERSCAN = 10,
MACFB_DISPLAY_PAL2_UNDERSCAN = 11,
MACFB_DISPLAY_PAL2_OVERSCAN = 12,
MACFB_DISPLAY_VGA = 13,
MACFB_DISPLAY_SVGA = 14,
} MacfbDisplayType;
typedef struct MacfbState {
MemoryRegion mem_vram;
MemoryRegion mem_ctrl;
@ -28,6 +46,8 @@ typedef struct MacfbState {
uint8_t color_palette[256 * 3];
uint32_t width, height; /* in pixels */
uint8_t depth;
uint32_t sense;
} MacfbState;
#define TYPE_MACFB "sysbus-macfb"