qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

blizzard.c (30026B)


      1 /*
      2  * Epson S1D13744/S1D13745 (Blizzard/Hailstorm/Tornado) LCD/TV controller.
      3  *
      4  * Copyright (C) 2008 Nokia Corporation
      5  * Written by Andrzej Zaborowski <andrew@openedhand.com>
      6  *
      7  * This program is free software; you can redistribute it and/or
      8  * modify it under the terms of the GNU General Public License as
      9  * published by the Free Software Foundation; either version 2 or
     10  * (at your option) version 3 of the License.
     11  *
     12  * This program is distributed in the hope that it will be useful,
     13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
     14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15  * GNU General Public License for more details.
     16  *
     17  * You should have received a copy of the GNU General Public License along
     18  * with this program; if not, see <http://www.gnu.org/licenses/>.
     19  */
     20 
     21 #include "qemu/osdep.h"
     22 #include "qemu/bitops.h"
     23 #include "ui/console.h"
     24 #include "hw/display/blizzard.h"
     25 #include "ui/pixel_ops.h"
     26 
     27 typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
     28 
     29 typedef struct {
     30     uint8_t reg;
     31     uint32_t addr;
     32     int swallow;
     33 
     34     int pll;
     35     int pll_range;
     36     int pll_ctrl;
     37     uint8_t pll_mode;
     38     uint8_t clksel;
     39     int memenable;
     40     int memrefresh;
     41     uint8_t timing[3];
     42     int priority;
     43 
     44     uint8_t lcd_config;
     45     int x;
     46     int y;
     47     int skipx;
     48     int skipy;
     49     uint8_t hndp;
     50     uint8_t vndp;
     51     uint8_t hsync;
     52     uint8_t vsync;
     53     uint8_t pclk;
     54     uint8_t u;
     55     uint8_t v;
     56     uint8_t yrc[2];
     57     int ix[2];
     58     int iy[2];
     59     int ox[2];
     60     int oy[2];
     61 
     62     int enable;
     63     int blank;
     64     int bpp;
     65     int invalidate;
     66     int mx[2];
     67     int my[2];
     68     uint8_t mode;
     69     uint8_t effect;
     70     uint8_t iformat;
     71     uint8_t source;
     72     QemuConsole *con;
     73     blizzard_fn_t *line_fn_tab[2];
     74     void *fb;
     75 
     76     uint8_t hssi_config[3];
     77     uint8_t tv_config;
     78     uint8_t tv_timing[4];
     79     uint8_t vbi;
     80     uint8_t tv_x;
     81     uint8_t tv_y;
     82     uint8_t tv_test;
     83     uint8_t tv_filter_config;
     84     uint8_t tv_filter_idx;
     85     uint8_t tv_filter_coeff[0x20];
     86     uint8_t border_r;
     87     uint8_t border_g;
     88     uint8_t border_b;
     89     uint8_t gamma_config;
     90     uint8_t gamma_idx;
     91     uint8_t gamma_lut[0x100];
     92     uint8_t matrix_ena;
     93     uint8_t matrix_coeff[0x12];
     94     uint8_t matrix_r;
     95     uint8_t matrix_g;
     96     uint8_t matrix_b;
     97     uint8_t pm;
     98     uint8_t status;
     99     uint8_t rgbgpio_dir;
    100     uint8_t rgbgpio;
    101     uint8_t gpio_dir;
    102     uint8_t gpio;
    103     uint8_t gpio_edge[2];
    104     uint8_t gpio_irq;
    105     uint8_t gpio_pdown;
    106 
    107     struct {
    108         int x;
    109         int y;
    110         int dx;
    111         int dy;
    112         int len;
    113         int buflen;
    114         void *buf;
    115         void *data;
    116         uint16_t *ptr;
    117         int angle;
    118         int pitch;
    119         blizzard_fn_t line_fn;
    120     } data;
    121 } BlizzardState;
    122 
    123 /* Bytes(!) per pixel */
    124 static const int blizzard_iformat_bpp[0x10] = {
    125     0,
    126     2,  /* RGB 5:6:5*/
    127     3,  /* RGB 6:6:6 mode 1 */
    128     3,  /* RGB 8:8:8 mode 1 */
    129     0, 0,
    130     4,  /* RGB 6:6:6 mode 2 */
    131     4,  /* RGB 8:8:8 mode 2 */
    132     0,  /* YUV 4:2:2 */
    133     0,  /* YUV 4:2:0 */
    134     0, 0, 0, 0, 0, 0,
    135 };
    136 
    137 static void blizzard_window(BlizzardState *s)
    138 {
    139     DisplaySurface *surface = qemu_console_surface(s->con);
    140     uint8_t *src, *dst;
    141     int bypp[2];
    142     int bypl[3];
    143     int y;
    144     blizzard_fn_t fn = s->data.line_fn;
    145 
    146     if (!fn)
    147         return;
    148     if (s->mx[0] > s->data.x)
    149         s->mx[0] = s->data.x;
    150     if (s->my[0] > s->data.y)
    151         s->my[0] = s->data.y;
    152     if (s->mx[1] < s->data.x + s->data.dx)
    153         s->mx[1] = s->data.x + s->data.dx;
    154     if (s->my[1] < s->data.y + s->data.dy)
    155         s->my[1] = s->data.y + s->data.dy;
    156 
    157     bypp[0] = s->bpp;
    158     bypp[1] = surface_bytes_per_pixel(surface);
    159     bypl[0] = bypp[0] * s->data.pitch;
    160     bypl[1] = bypp[1] * s->x;
    161     bypl[2] = bypp[0] * s->data.dx;
    162 
    163     src = s->data.data;
    164     dst = s->fb + bypl[1] * s->data.y + bypp[1] * s->data.x;
    165     for (y = s->data.dy; y > 0; y --, src += bypl[0], dst += bypl[1])
    166         fn(dst, src, bypl[2]);
    167 }
    168 
    169 static int blizzard_transfer_setup(BlizzardState *s)
    170 {
    171     if (s->source > 3 || !s->bpp ||
    172                     s->ix[1] < s->ix[0] || s->iy[1] < s->iy[0])
    173         return 0;
    174 
    175     s->data.angle = s->effect & 3;
    176     s->data.line_fn = s->line_fn_tab[!!s->data.angle][s->iformat];
    177     s->data.x = s->ix[0];
    178     s->data.y = s->iy[0];
    179     s->data.dx = s->ix[1] - s->ix[0] + 1;
    180     s->data.dy = s->iy[1] - s->iy[0] + 1;
    181     s->data.len = s->bpp * s->data.dx * s->data.dy;
    182     s->data.pitch = s->data.dx;
    183     if (s->data.len > s->data.buflen) {
    184         s->data.buf = g_realloc(s->data.buf, s->data.len);
    185         s->data.buflen = s->data.len;
    186     }
    187     s->data.ptr = s->data.buf;
    188     s->data.data = s->data.buf;
    189     s->data.len /= 2;
    190     return 1;
    191 }
    192 
    193 static void blizzard_reset(BlizzardState *s)
    194 {
    195     s->reg = 0;
    196     s->swallow = 0;
    197 
    198     s->pll = 9;
    199     s->pll_range = 1;
    200     s->pll_ctrl = 0x14;
    201     s->pll_mode = 0x32;
    202     s->clksel = 0x00;
    203     s->memenable = 0;
    204     s->memrefresh = 0x25c;
    205     s->timing[0] = 0x3f;
    206     s->timing[1] = 0x13;
    207     s->timing[2] = 0x21;
    208     s->priority = 0;
    209 
    210     s->lcd_config = 0x74;
    211     s->x = 8;
    212     s->y = 1;
    213     s->skipx = 0;
    214     s->skipy = 0;
    215     s->hndp = 3;
    216     s->vndp = 2;
    217     s->hsync = 1;
    218     s->vsync = 1;
    219     s->pclk = 0x80;
    220 
    221     s->ix[0] = 0;
    222     s->ix[1] = 0;
    223     s->iy[0] = 0;
    224     s->iy[1] = 0;
    225     s->ox[0] = 0;
    226     s->ox[1] = 0;
    227     s->oy[0] = 0;
    228     s->oy[1] = 0;
    229 
    230     s->yrc[0] = 0x00;
    231     s->yrc[1] = 0x30;
    232     s->u = 0;
    233     s->v = 0;
    234 
    235     s->iformat = 3;
    236     s->source = 0;
    237     s->bpp = blizzard_iformat_bpp[s->iformat];
    238 
    239     s->hssi_config[0] = 0x00;
    240     s->hssi_config[1] = 0x00;
    241     s->hssi_config[2] = 0x01;
    242     s->tv_config = 0x00;
    243     s->tv_timing[0] = 0x00;
    244     s->tv_timing[1] = 0x00;
    245     s->tv_timing[2] = 0x00;
    246     s->tv_timing[3] = 0x00;
    247     s->vbi = 0x10;
    248     s->tv_x = 0x14;
    249     s->tv_y = 0x03;
    250     s->tv_test = 0x00;
    251     s->tv_filter_config = 0x80;
    252     s->tv_filter_idx = 0x00;
    253     s->border_r = 0x10;
    254     s->border_g = 0x80;
    255     s->border_b = 0x80;
    256     s->gamma_config = 0x00;
    257     s->gamma_idx = 0x00;
    258     s->matrix_ena = 0x00;
    259     memset(&s->matrix_coeff, 0, sizeof(s->matrix_coeff));
    260     s->matrix_r = 0x00;
    261     s->matrix_g = 0x00;
    262     s->matrix_b = 0x00;
    263     s->pm = 0x02;
    264     s->status = 0x00;
    265     s->rgbgpio_dir = 0x00;
    266     s->gpio_dir = 0x00;
    267     s->gpio_edge[0] = 0x00;
    268     s->gpio_edge[1] = 0x00;
    269     s->gpio_irq = 0x00;
    270     s->gpio_pdown = 0xff;
    271 }
    272 
    273 static inline void blizzard_invalidate_display(void *opaque) {
    274     BlizzardState *s = (BlizzardState *) opaque;
    275 
    276     s->invalidate = 1;
    277 }
    278 
    279 static uint16_t blizzard_reg_read(void *opaque, uint8_t reg)
    280 {
    281     BlizzardState *s = (BlizzardState *) opaque;
    282 
    283     switch (reg) {
    284     case 0x00:  /* Revision Code */
    285         return 0xa5;
    286 
    287     case 0x02:  /* Configuration Readback */
    288         return 0x83;    /* Macrovision OK, CNF[2:0] = 3 */
    289 
    290     case 0x04:  /* PLL M-Divider */
    291         return (s->pll - 1) | (1 << 7);
    292     case 0x06:  /* PLL Lock Range Control */
    293         return s->pll_range;
    294     case 0x08:  /* PLL Lock Synthesis Control 0 */
    295         return s->pll_ctrl & 0xff;
    296     case 0x0a:  /* PLL Lock Synthesis Control 1 */
    297         return s->pll_ctrl >> 8;
    298     case 0x0c:  /* PLL Mode Control 0 */
    299         return s->pll_mode;
    300 
    301     case 0x0e:  /* Clock-Source Select */
    302         return s->clksel;
    303 
    304     case 0x10:  /* Memory Controller Activate */
    305     case 0x14:  /* Memory Controller Bank 0 Status Flag */
    306         return s->memenable;
    307 
    308     case 0x18:  /* Auto-Refresh Interval Setting 0 */
    309         return s->memrefresh & 0xff;
    310     case 0x1a:  /* Auto-Refresh Interval Setting 1 */
    311         return s->memrefresh >> 8;
    312 
    313     case 0x1c:  /* Power-On Sequence Timing Control */
    314         return s->timing[0];
    315     case 0x1e:  /* Timing Control 0 */
    316         return s->timing[1];
    317     case 0x20:  /* Timing Control 1 */
    318         return s->timing[2];
    319 
    320     case 0x24:  /* Arbitration Priority Control */
    321         return s->priority;
    322 
    323     case 0x28:  /* LCD Panel Configuration */
    324         return s->lcd_config;
    325 
    326     case 0x2a:  /* LCD Horizontal Display Width */
    327         return s->x >> 3;
    328     case 0x2c:  /* LCD Horizontal Non-display Period */
    329         return s->hndp;
    330     case 0x2e:  /* LCD Vertical Display Height 0 */
    331         return s->y & 0xff;
    332     case 0x30:  /* LCD Vertical Display Height 1 */
    333         return s->y >> 8;
    334     case 0x32:  /* LCD Vertical Non-display Period */
    335         return s->vndp;
    336     case 0x34:  /* LCD HS Pulse-width */
    337         return s->hsync;
    338     case 0x36:  /* LCd HS Pulse Start Position */
    339         return s->skipx >> 3;
    340     case 0x38:  /* LCD VS Pulse-width */
    341         return s->vsync;
    342     case 0x3a:  /* LCD VS Pulse Start Position */
    343         return s->skipy;
    344 
    345     case 0x3c:  /* PCLK Polarity */
    346         return s->pclk;
    347 
    348     case 0x3e:  /* High-speed Serial Interface Tx Configuration Port 0 */
    349         return s->hssi_config[0];
    350     case 0x40:  /* High-speed Serial Interface Tx Configuration Port 1 */
    351         return s->hssi_config[1];
    352     case 0x42:  /* High-speed Serial Interface Tx Mode */
    353         return s->hssi_config[2];
    354     case 0x44:  /* TV Display Configuration */
    355         return s->tv_config;
    356     case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits */
    357         return s->tv_timing[(reg - 0x46) >> 1];
    358     case 0x4e:  /* VBI: Closed Caption / XDS Control / Status */
    359         return s->vbi;
    360     case 0x50:  /* TV Horizontal Start Position */
    361         return s->tv_x;
    362     case 0x52:  /* TV Vertical Start Position */
    363         return s->tv_y;
    364     case 0x54:  /* TV Test Pattern Setting */
    365         return s->tv_test;
    366     case 0x56:  /* TV Filter Setting */
    367         return s->tv_filter_config;
    368     case 0x58:  /* TV Filter Coefficient Index */
    369         return s->tv_filter_idx;
    370     case 0x5a:  /* TV Filter Coefficient Data */
    371         if (s->tv_filter_idx < 0x20)
    372             return s->tv_filter_coeff[s->tv_filter_idx ++];
    373         return 0;
    374 
    375     case 0x60:  /* Input YUV/RGB Translate Mode 0 */
    376         return s->yrc[0];
    377     case 0x62:  /* Input YUV/RGB Translate Mode 1 */
    378         return s->yrc[1];
    379     case 0x64:  /* U Data Fix */
    380         return s->u;
    381     case 0x66:  /* V Data Fix */
    382         return s->v;
    383 
    384     case 0x68:  /* Display Mode */
    385         return s->mode;
    386 
    387     case 0x6a:  /* Special Effects */
    388         return s->effect;
    389 
    390     case 0x6c:  /* Input Window X Start Position 0 */
    391         return s->ix[0] & 0xff;
    392     case 0x6e:  /* Input Window X Start Position 1 */
    393         return s->ix[0] >> 3;
    394     case 0x70:  /* Input Window Y Start Position 0 */
    395         return s->ix[0] & 0xff;
    396     case 0x72:  /* Input Window Y Start Position 1 */
    397         return s->ix[0] >> 3;
    398     case 0x74:  /* Input Window X End Position 0 */
    399         return s->ix[1] & 0xff;
    400     case 0x76:  /* Input Window X End Position 1 */
    401         return s->ix[1] >> 3;
    402     case 0x78:  /* Input Window Y End Position 0 */
    403         return s->ix[1] & 0xff;
    404     case 0x7a:  /* Input Window Y End Position 1 */
    405         return s->ix[1] >> 3;
    406     case 0x7c:  /* Output Window X Start Position 0 */
    407         return s->ox[0] & 0xff;
    408     case 0x7e:  /* Output Window X Start Position 1 */
    409         return s->ox[0] >> 3;
    410     case 0x80:  /* Output Window Y Start Position 0 */
    411         return s->oy[0] & 0xff;
    412     case 0x82:  /* Output Window Y Start Position 1 */
    413         return s->oy[0] >> 3;
    414     case 0x84:  /* Output Window X End Position 0 */
    415         return s->ox[1] & 0xff;
    416     case 0x86:  /* Output Window X End Position 1 */
    417         return s->ox[1] >> 3;
    418     case 0x88:  /* Output Window Y End Position 0 */
    419         return s->oy[1] & 0xff;
    420     case 0x8a:  /* Output Window Y End Position 1 */
    421         return s->oy[1] >> 3;
    422 
    423     case 0x8c:  /* Input Data Format */
    424         return s->iformat;
    425     case 0x8e:  /* Data Source Select */
    426         return s->source;
    427     case 0x90:  /* Display Memory Data Port */
    428         return 0;
    429 
    430     case 0xa8:  /* Border Color 0 */
    431         return s->border_r;
    432     case 0xaa:  /* Border Color 1 */
    433         return s->border_g;
    434     case 0xac:  /* Border Color 2 */
    435         return s->border_b;
    436 
    437     case 0xb4:  /* Gamma Correction Enable */
    438         return s->gamma_config;
    439     case 0xb6:  /* Gamma Correction Table Index */
    440         return s->gamma_idx;
    441     case 0xb8:  /* Gamma Correction Table Data */
    442         return s->gamma_lut[s->gamma_idx ++];
    443 
    444     case 0xba:  /* 3x3 Matrix Enable */
    445         return s->matrix_ena;
    446     case 0xbc ... 0xde: /* Coefficient Registers */
    447         return s->matrix_coeff[(reg - 0xbc) >> 1];
    448     case 0xe0:  /* 3x3 Matrix Red Offset */
    449         return s->matrix_r;
    450     case 0xe2:  /* 3x3 Matrix Green Offset */
    451         return s->matrix_g;
    452     case 0xe4:  /* 3x3 Matrix Blue Offset */
    453         return s->matrix_b;
    454 
    455     case 0xe6:  /* Power-save */
    456         return s->pm;
    457     case 0xe8:  /* Non-display Period Control / Status */
    458         return s->status | (1 << 5);
    459     case 0xea:  /* RGB Interface Control */
    460         return s->rgbgpio_dir;
    461     case 0xec:  /* RGB Interface Status */
    462         return s->rgbgpio;
    463     case 0xee:  /* General-purpose IO Pins Configuration */
    464         return s->gpio_dir;
    465     case 0xf0:  /* General-purpose IO Pins Status / Control */
    466         return s->gpio;
    467     case 0xf2:  /* GPIO Positive Edge Interrupt Trigger */
    468         return s->gpio_edge[0];
    469     case 0xf4:  /* GPIO Negative Edge Interrupt Trigger */
    470         return s->gpio_edge[1];
    471     case 0xf6:  /* GPIO Interrupt Status */
    472         return s->gpio_irq;
    473     case 0xf8:  /* GPIO Pull-down Control */
    474         return s->gpio_pdown;
    475 
    476     default:
    477         fprintf(stderr, "%s: unknown register %02x\n", __func__, reg);
    478         return 0;
    479     }
    480 }
    481 
    482 static void blizzard_reg_write(void *opaque, uint8_t reg, uint16_t value)
    483 {
    484     BlizzardState *s = (BlizzardState *) opaque;
    485 
    486     switch (reg) {
    487     case 0x04:  /* PLL M-Divider */
    488         s->pll = (value & 0x3f) + 1;
    489         break;
    490     case 0x06:  /* PLL Lock Range Control */
    491         s->pll_range = value & 3;
    492         break;
    493     case 0x08:  /* PLL Lock Synthesis Control 0 */
    494         s->pll_ctrl &= 0xf00;
    495         s->pll_ctrl |= (value << 0) & 0x0ff;
    496         break;
    497     case 0x0a:  /* PLL Lock Synthesis Control 1 */
    498         s->pll_ctrl &= 0x0ff;
    499         s->pll_ctrl |= (value << 8) & 0xf00;
    500         break;
    501     case 0x0c:  /* PLL Mode Control 0 */
    502         s->pll_mode = value & 0x77;
    503         if ((value & 3) == 0 || (value & 3) == 3)
    504             fprintf(stderr, "%s: wrong PLL Control bits (%i)\n",
    505                     __func__, value & 3);
    506         break;
    507 
    508     case 0x0e:  /* Clock-Source Select */
    509         s->clksel = value & 0xff;
    510         break;
    511 
    512     case 0x10:  /* Memory Controller Activate */
    513         s->memenable = value & 1;
    514         break;
    515     case 0x14:  /* Memory Controller Bank 0 Status Flag */
    516         break;
    517 
    518     case 0x18:  /* Auto-Refresh Interval Setting 0 */
    519         s->memrefresh &= 0xf00;
    520         s->memrefresh |= (value << 0) & 0x0ff;
    521         break;
    522     case 0x1a:  /* Auto-Refresh Interval Setting 1 */
    523         s->memrefresh &= 0x0ff;
    524         s->memrefresh |= (value << 8) & 0xf00;
    525         break;
    526 
    527     case 0x1c:  /* Power-On Sequence Timing Control */
    528         s->timing[0] = value & 0x7f;
    529         break;
    530     case 0x1e:  /* Timing Control 0 */
    531         s->timing[1] = value & 0x17;
    532         break;
    533     case 0x20:  /* Timing Control 1 */
    534         s->timing[2] = value & 0x35;
    535         break;
    536 
    537     case 0x24:  /* Arbitration Priority Control */
    538         s->priority = value & 1;
    539         break;
    540 
    541     case 0x28:  /* LCD Panel Configuration */
    542         s->lcd_config = value & 0xff;
    543         if (value & (1 << 7))
    544             fprintf(stderr, "%s: data swap not supported!\n", __func__);
    545         break;
    546 
    547     case 0x2a:  /* LCD Horizontal Display Width */
    548         s->x = value << 3;
    549         break;
    550     case 0x2c:  /* LCD Horizontal Non-display Period */
    551         s->hndp = value & 0xff;
    552         break;
    553     case 0x2e:  /* LCD Vertical Display Height 0 */
    554         s->y &= 0x300;
    555         s->y |= (value << 0) & 0x0ff;
    556         break;
    557     case 0x30:  /* LCD Vertical Display Height 1 */
    558         s->y &= 0x0ff;
    559         s->y |= (value << 8) & 0x300;
    560         break;
    561     case 0x32:  /* LCD Vertical Non-display Period */
    562         s->vndp = value & 0xff;
    563         break;
    564     case 0x34:  /* LCD HS Pulse-width */
    565         s->hsync = value & 0xff;
    566         break;
    567     case 0x36:  /* LCD HS Pulse Start Position */
    568         s->skipx = value & 0xff;
    569         break;
    570     case 0x38:  /* LCD VS Pulse-width */
    571         s->vsync = value & 0xbf;
    572         break;
    573     case 0x3a:  /* LCD VS Pulse Start Position */
    574         s->skipy = value & 0xff;
    575         break;
    576 
    577     case 0x3c:  /* PCLK Polarity */
    578         s->pclk = value & 0x82;
    579         /* Affects calculation of s->hndp, s->hsync and s->skipx.  */
    580         break;
    581 
    582     case 0x3e:  /* High-speed Serial Interface Tx Configuration Port 0 */
    583         s->hssi_config[0] = value;
    584         break;
    585     case 0x40:  /* High-speed Serial Interface Tx Configuration Port 1 */
    586         s->hssi_config[1] = value;
    587         if (((value >> 4) & 3) == 3)
    588             fprintf(stderr, "%s: Illegal active-data-links value\n",
    589                             __func__);
    590         break;
    591     case 0x42:  /* High-speed Serial Interface Tx Mode */
    592         s->hssi_config[2] = value & 0xbd;
    593         break;
    594 
    595     case 0x44:  /* TV Display Configuration */
    596         s->tv_config = value & 0xfe;
    597         break;
    598     case 0x46 ... 0x4c: /* TV Vertical Blanking Interval Data bits 0 */
    599         s->tv_timing[(reg - 0x46) >> 1] = value;
    600         break;
    601     case 0x4e:  /* VBI: Closed Caption / XDS Control / Status */
    602         s->vbi = value;
    603         break;
    604     case 0x50:  /* TV Horizontal Start Position */
    605         s->tv_x = value;
    606         break;
    607     case 0x52:  /* TV Vertical Start Position */
    608         s->tv_y = value & 0x7f;
    609         break;
    610     case 0x54:  /* TV Test Pattern Setting */
    611         s->tv_test = value;
    612         break;
    613     case 0x56:  /* TV Filter Setting */
    614         s->tv_filter_config = value & 0xbf;
    615         break;
    616     case 0x58:  /* TV Filter Coefficient Index */
    617         s->tv_filter_idx = value & 0x1f;
    618         break;
    619     case 0x5a:  /* TV Filter Coefficient Data */
    620         if (s->tv_filter_idx < 0x20)
    621             s->tv_filter_coeff[s->tv_filter_idx ++] = value;
    622         break;
    623 
    624     case 0x60:  /* Input YUV/RGB Translate Mode 0 */
    625         s->yrc[0] = value & 0xb0;
    626         break;
    627     case 0x62:  /* Input YUV/RGB Translate Mode 1 */
    628         s->yrc[1] = value & 0x30;
    629         break;
    630     case 0x64:  /* U Data Fix */
    631         s->u = value & 0xff;
    632         break;
    633     case 0x66:  /* V Data Fix */
    634         s->v = value & 0xff;
    635         break;
    636 
    637     case 0x68:  /* Display Mode */
    638         if ((s->mode ^ value) & 3)
    639             s->invalidate = 1;
    640         s->mode = value & 0xb7;
    641         s->enable = value & 1;
    642         s->blank = (value >> 1) & 1;
    643         if (value & (1 << 4))
    644             fprintf(stderr, "%s: Macrovision enable attempt!\n", __func__);
    645         break;
    646 
    647     case 0x6a:  /* Special Effects */
    648         s->effect = value & 0xfb;
    649         break;
    650 
    651     case 0x6c:  /* Input Window X Start Position 0 */
    652         s->ix[0] &= 0x300;
    653         s->ix[0] |= (value << 0) & 0x0ff;
    654         break;
    655     case 0x6e:  /* Input Window X Start Position 1 */
    656         s->ix[0] &= 0x0ff;
    657         s->ix[0] |= (value << 8) & 0x300;
    658         break;
    659     case 0x70:  /* Input Window Y Start Position 0 */
    660         s->iy[0] &= 0x300;
    661         s->iy[0] |= (value << 0) & 0x0ff;
    662         break;
    663     case 0x72:  /* Input Window Y Start Position 1 */
    664         s->iy[0] &= 0x0ff;
    665         s->iy[0] |= (value << 8) & 0x300;
    666         break;
    667     case 0x74:  /* Input Window X End Position 0 */
    668         s->ix[1] &= 0x300;
    669         s->ix[1] |= (value << 0) & 0x0ff;
    670         break;
    671     case 0x76:  /* Input Window X End Position 1 */
    672         s->ix[1] &= 0x0ff;
    673         s->ix[1] |= (value << 8) & 0x300;
    674         break;
    675     case 0x78:  /* Input Window Y End Position 0 */
    676         s->iy[1] &= 0x300;
    677         s->iy[1] |= (value << 0) & 0x0ff;
    678         break;
    679     case 0x7a:  /* Input Window Y End Position 1 */
    680         s->iy[1] &= 0x0ff;
    681         s->iy[1] |= (value << 8) & 0x300;
    682         break;
    683     case 0x7c:  /* Output Window X Start Position 0 */
    684         s->ox[0] &= 0x300;
    685         s->ox[0] |= (value << 0) & 0x0ff;
    686         break;
    687     case 0x7e:  /* Output Window X Start Position 1 */
    688         s->ox[0] &= 0x0ff;
    689         s->ox[0] |= (value << 8) & 0x300;
    690         break;
    691     case 0x80:  /* Output Window Y Start Position 0 */
    692         s->oy[0] &= 0x300;
    693         s->oy[0] |= (value << 0) & 0x0ff;
    694         break;
    695     case 0x82:  /* Output Window Y Start Position 1 */
    696         s->oy[0] &= 0x0ff;
    697         s->oy[0] |= (value << 8) & 0x300;
    698         break;
    699     case 0x84:  /* Output Window X End Position 0 */
    700         s->ox[1] &= 0x300;
    701         s->ox[1] |= (value << 0) & 0x0ff;
    702         break;
    703     case 0x86:  /* Output Window X End Position 1 */
    704         s->ox[1] &= 0x0ff;
    705         s->ox[1] |= (value << 8) & 0x300;
    706         break;
    707     case 0x88:  /* Output Window Y End Position 0 */
    708         s->oy[1] &= 0x300;
    709         s->oy[1] |= (value << 0) & 0x0ff;
    710         break;
    711     case 0x8a:  /* Output Window Y End Position 1 */
    712         s->oy[1] &= 0x0ff;
    713         s->oy[1] |= (value << 8) & 0x300;
    714         break;
    715 
    716     case 0x8c:  /* Input Data Format */
    717         s->iformat = value & 0xf;
    718         s->bpp = blizzard_iformat_bpp[s->iformat];
    719         if (!s->bpp)
    720             fprintf(stderr, "%s: Illegal or unsupported input format %x\n",
    721                             __func__, s->iformat);
    722         break;
    723     case 0x8e:  /* Data Source Select */
    724         s->source = value & 7;
    725         /* Currently all windows will be "destructive overlays".  */
    726         if ((!(s->effect & (1 << 3)) && (s->ix[0] != s->ox[0] ||
    727                                         s->iy[0] != s->oy[0] ||
    728                                         s->ix[1] != s->ox[1] ||
    729                                         s->iy[1] != s->oy[1])) ||
    730                         !((s->ix[1] - s->ix[0]) & (s->iy[1] - s->iy[0]) &
    731                           (s->ox[1] - s->ox[0]) & (s->oy[1] - s->oy[0]) & 1))
    732             fprintf(stderr, "%s: Illegal input/output window positions\n",
    733                             __func__);
    734 
    735         blizzard_transfer_setup(s);
    736         break;
    737 
    738     case 0x90:  /* Display Memory Data Port */
    739         if (!s->data.len && !blizzard_transfer_setup(s))
    740             break;
    741 
    742         *s->data.ptr ++ = value;
    743         if (-- s->data.len == 0)
    744             blizzard_window(s);
    745         break;
    746 
    747     case 0xa8:  /* Border Color 0 */
    748         s->border_r = value;
    749         break;
    750     case 0xaa:  /* Border Color 1 */
    751         s->border_g = value;
    752         break;
    753     case 0xac:  /* Border Color 2 */
    754         s->border_b = value;
    755         break;
    756 
    757     case 0xb4:  /* Gamma Correction Enable */
    758         s->gamma_config = value & 0x87;
    759         break;
    760     case 0xb6:  /* Gamma Correction Table Index */
    761         s->gamma_idx = value;
    762         break;
    763     case 0xb8:  /* Gamma Correction Table Data */
    764         s->gamma_lut[s->gamma_idx ++] = value;
    765         break;
    766 
    767     case 0xba:  /* 3x3 Matrix Enable */
    768         s->matrix_ena = value & 1;
    769         break;
    770     case 0xbc ... 0xde: /* Coefficient Registers */
    771         s->matrix_coeff[(reg - 0xbc) >> 1] = value & ((reg & 2) ? 0x80 : 0xff);
    772         break;
    773     case 0xe0:  /* 3x3 Matrix Red Offset */
    774         s->matrix_r = value;
    775         break;
    776     case 0xe2:  /* 3x3 Matrix Green Offset */
    777         s->matrix_g = value;
    778         break;
    779     case 0xe4:  /* 3x3 Matrix Blue Offset */
    780         s->matrix_b = value;
    781         break;
    782 
    783     case 0xe6:  /* Power-save */
    784         s->pm = value & 0x83;
    785         if (value & s->mode & 1)
    786             fprintf(stderr, "%s: The display must be disabled before entering "
    787                             "Standby Mode\n", __func__);
    788         break;
    789     case 0xe8:  /* Non-display Period Control / Status */
    790         s->status = value & 0x1b;
    791         break;
    792     case 0xea:  /* RGB Interface Control */
    793         s->rgbgpio_dir = value & 0x8f;
    794         break;
    795     case 0xec:  /* RGB Interface Status */
    796         s->rgbgpio = value & 0xcf;
    797         break;
    798     case 0xee:  /* General-purpose IO Pins Configuration */
    799         s->gpio_dir = value;
    800         break;
    801     case 0xf0:  /* General-purpose IO Pins Status / Control */
    802         s->gpio = value;
    803         break;
    804     case 0xf2:  /* GPIO Positive Edge Interrupt Trigger */
    805         s->gpio_edge[0] = value;
    806         break;
    807     case 0xf4:  /* GPIO Negative Edge Interrupt Trigger */
    808         s->gpio_edge[1] = value;
    809         break;
    810     case 0xf6:  /* GPIO Interrupt Status */
    811         s->gpio_irq &= value;
    812         break;
    813     case 0xf8:  /* GPIO Pull-down Control */
    814         s->gpio_pdown = value;
    815         break;
    816 
    817     default:
    818         fprintf(stderr, "%s: unknown register %02x\n", __func__, reg);
    819         break;
    820     }
    821 }
    822 
    823 uint16_t s1d13745_read(void *opaque, int dc)
    824 {
    825     BlizzardState *s = (BlizzardState *) opaque;
    826     uint16_t value = blizzard_reg_read(s, s->reg);
    827 
    828     if (s->swallow -- > 0)
    829         return 0;
    830     if (dc)
    831         s->reg ++;
    832 
    833     return value;
    834 }
    835 
    836 void s1d13745_write(void *opaque, int dc, uint16_t value)
    837 {
    838     BlizzardState *s = (BlizzardState *) opaque;
    839 
    840     if (s->swallow -- > 0)
    841         return;
    842     if (dc) {
    843         blizzard_reg_write(s, s->reg, value);
    844 
    845         if (s->reg != 0x90 && s->reg != 0x5a && s->reg != 0xb8)
    846             s->reg += 2;
    847     } else
    848         s->reg = value & 0xff;
    849 }
    850 
    851 void s1d13745_write_block(void *opaque, int dc,
    852                 void *buf, size_t len, int pitch)
    853 {
    854     BlizzardState *s = (BlizzardState *) opaque;
    855 
    856     while (len > 0) {
    857         if (s->reg == 0x90 && dc &&
    858                         (s->data.len || blizzard_transfer_setup(s)) &&
    859                         len >= (s->data.len << 1)) {
    860             len -= s->data.len << 1;
    861             s->data.len = 0;
    862             s->data.data = buf;
    863             if (pitch)
    864                 s->data.pitch = pitch;
    865             blizzard_window(s);
    866             s->data.data = s->data.buf;
    867             continue;
    868         }
    869 
    870         s1d13745_write(opaque, dc, *(uint16_t *) buf);
    871         len -= 2;
    872         buf += 2;
    873     }
    874 }
    875 
    876 static void blizzard_update_display(void *opaque)
    877 {
    878     BlizzardState *s = (BlizzardState *) opaque;
    879     DisplaySurface *surface = qemu_console_surface(s->con);
    880     int y, bypp, bypl, bwidth;
    881     uint8_t *src, *dst;
    882 
    883     if (!s->enable)
    884         return;
    885 
    886     if (s->x != surface_width(surface) || s->y != surface_height(surface)) {
    887         s->invalidate = 1;
    888         qemu_console_resize(s->con, s->x, s->y);
    889         surface = qemu_console_surface(s->con);
    890     }
    891 
    892     if (s->invalidate) {
    893         s->invalidate = 0;
    894 
    895         if (s->blank) {
    896             bypp = surface_bytes_per_pixel(surface);
    897             memset(surface_data(surface), 0, bypp * s->x * s->y);
    898             return;
    899         }
    900 
    901         s->mx[0] = 0;
    902         s->mx[1] = s->x;
    903         s->my[0] = 0;
    904         s->my[1] = s->y;
    905     }
    906 
    907     if (s->mx[1] <= s->mx[0])
    908         return;
    909 
    910     bypp = surface_bytes_per_pixel(surface);
    911     bypl = bypp * s->x;
    912     bwidth = bypp * (s->mx[1] - s->mx[0]);
    913     y = s->my[0];
    914     src = s->fb + bypl * y + bypp * s->mx[0];
    915     dst = surface_data(surface) + bypl * y + bypp * s->mx[0];
    916     for (; y < s->my[1]; y ++, src += bypl, dst += bypl)
    917         memcpy(dst, src, bwidth);
    918 
    919     dpy_gfx_update(s->con, s->mx[0], s->my[0],
    920                    s->mx[1] - s->mx[0], y - s->my[0]);
    921 
    922     s->mx[0] = s->x;
    923     s->mx[1] = 0;
    924     s->my[0] = s->y;
    925     s->my[1] = 0;
    926 }
    927 
    928 static void blizzard_draw_line16_32(uint32_t *dest,
    929                                     const uint16_t *src, unsigned int width)
    930 {
    931     uint16_t data;
    932     unsigned int r, g, b;
    933     const uint16_t *end = (const void *) src + width;
    934     while (src < end) {
    935         data = *src ++;
    936         b = extract16(data, 0, 5) << 3;
    937         g = extract16(data, 5, 6) << 2;
    938         r = extract16(data, 11, 5) << 3;
    939         *dest++ = rgb_to_pixel32(r, g, b);
    940     }
    941 }
    942 
    943 static void blizzard_draw_line24mode1_32(uint32_t *dest,
    944                                          const uint8_t *src, unsigned int width)
    945 {
    946     /* TODO: check if SDL 24-bit planes are not in the same format and
    947      * if so, use memcpy */
    948     unsigned int r[2], g[2], b[2];
    949     const uint8_t *end = src + width;
    950     while (src < end) {
    951         g[0] = *src ++;
    952         r[0] = *src ++;
    953         r[1] = *src ++;
    954         b[0] = *src ++;
    955         *dest++ = rgb_to_pixel32(r[0], g[0], b[0]);
    956         b[1] = *src ++;
    957         g[1] = *src ++;
    958         *dest++ = rgb_to_pixel32(r[1], g[1], b[1]);
    959     }
    960 }
    961 
    962 static void blizzard_draw_line24mode2_32(uint32_t *dest,
    963                                          const uint8_t *src, unsigned int width)
    964 {
    965     unsigned int r, g, b;
    966     const uint8_t *end = src + width;
    967     while (src < end) {
    968         r = *src ++;
    969         src ++;
    970         b = *src ++;
    971         g = *src ++;
    972         *dest++ = rgb_to_pixel32(r, g, b);
    973     }
    974 }
    975 
    976 /* No rotation */
    977 static blizzard_fn_t blizzard_draw_fn_32[0x10] = {
    978     NULL,
    979     /* RGB 5:6:5*/
    980     (blizzard_fn_t) blizzard_draw_line16_32,
    981     /* RGB 6:6:6 mode 1 */
    982     (blizzard_fn_t) blizzard_draw_line24mode1_32,
    983     /* RGB 8:8:8 mode 1 */
    984     (blizzard_fn_t) blizzard_draw_line24mode1_32,
    985     NULL, NULL,
    986     /* RGB 6:6:6 mode 2 */
    987     (blizzard_fn_t) blizzard_draw_line24mode2_32,
    988     /* RGB 8:8:8 mode 2 */
    989     (blizzard_fn_t) blizzard_draw_line24mode2_32,
    990     /* YUV 4:2:2 */
    991     NULL,
    992     /* YUV 4:2:0 */
    993     NULL,
    994     NULL, NULL, NULL, NULL, NULL, NULL,
    995 };
    996 
    997 /* 90deg, 180deg and 270deg rotation */
    998 static blizzard_fn_t blizzard_draw_fn_r_32[0x10] = {
    999     /* TODO */
   1000     [0 ... 0xf] = NULL,
   1001 };
   1002 
   1003 static const GraphicHwOps blizzard_ops = {
   1004     .invalidate  = blizzard_invalidate_display,
   1005     .gfx_update  = blizzard_update_display,
   1006 };
   1007 
   1008 void *s1d13745_init(qemu_irq gpio_int)
   1009 {
   1010     BlizzardState *s = g_malloc0(sizeof(*s));
   1011     DisplaySurface *surface;
   1012 
   1013     s->fb = g_malloc(0x180000);
   1014 
   1015     s->con = graphic_console_init(NULL, 0, &blizzard_ops, s);
   1016     surface = qemu_console_surface(s->con);
   1017 
   1018     assert(surface_bits_per_pixel(surface) == 32);
   1019 
   1020     s->line_fn_tab[0] = blizzard_draw_fn_32;
   1021     s->line_fn_tab[1] = blizzard_draw_fn_r_32;
   1022 
   1023     blizzard_reset(s);
   1024 
   1025     return s;
   1026 }