cachepc-qemu

Fork of AMDESE/qemu with changes for cachepc side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-qemu
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

blizzard.c (29870B)


      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
     27typedef void (*blizzard_fn_t)(uint8_t *, const uint8_t *, unsigned int);
     28
     29typedef 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 */
    124static 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
    137static 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
    169static 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
    193static 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
    273static inline void blizzard_invalidate_display(void *opaque) {
    274    BlizzardState *s = (BlizzardState *) opaque;
    275
    276    s->invalidate = 1;
    277}
    278
    279static 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
    482static 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
    823uint16_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
    836void 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
    851void 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
    876static 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
    928static 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
    943static 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
    962static 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 */
    977static 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 */
    998static blizzard_fn_t blizzard_draw_fn_r_32[0x10] = {
    999    /* TODO */
   1000    [0 ... 0xf] = NULL,
   1001};
   1002
   1003static const GraphicHwOps blizzard_ops = {
   1004    .invalidate  = blizzard_invalidate_display,
   1005    .gfx_update  = blizzard_update_display,
   1006};
   1007
   1008void *s1d13745_init(qemu_irq gpio_int)
   1009{
   1010    BlizzardState *s = (BlizzardState *) 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}