void vga_mem_writeb(VGACommonState *s, hwaddr addr, uint32_t val)

{

    int memory_map_mode, plane, write_mode, b, func_select, mask;

    uint32_t write_mask, bit_mask, set_mask;



#ifdef DEBUG_VGA_MEM

    printf("vga: [0x" TARGET_FMT_plx "] = 0x%02x\n", addr, val);

#endif

    /* convert to VGA memory offset */

    memory_map_mode = (s->gr[VGA_GFX_MISC] >> 2) & 3;

    addr &= 0x1ffff;

    switch(memory_map_mode) {

    case 0:

        break;

    case 1:

        if (addr >= 0x10000)

            return;

        addr += s->bank_offset;

        break;

    case 2:

        addr -= 0x10000;

        if (addr >= 0x8000)

            return;

        break;

    default:

    case 3:

        addr -= 0x18000;

        if (addr >= 0x8000)

            return;

        break;

    }



    if (s->sr[VGA_SEQ_MEMORY_MODE] & VGA_SR04_CHN_4M) {

        /* chain 4 mode : simplest access */

        plane = addr & 3;

        mask = (1 << plane);

        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {

            assert(addr < s->vram_size);

            s->vram_ptr[addr] = val;

#ifdef DEBUG_VGA_MEM

            printf("vga: chain4: [0x" TARGET_FMT_plx "]\n", addr);

#endif

            s->plane_updated |= mask; /* only used to detect font change */

            memory_region_set_dirty(&s->vram, addr, 1);

        }

    } else if (s->gr[VGA_GFX_MODE] & 0x10) {

        /* odd/even mode (aka text mode mapping) */

        plane = (s->gr[VGA_GFX_PLANE_READ] & 2) | (addr & 1);

        mask = (1 << plane);

        if (s->sr[VGA_SEQ_PLANE_WRITE] & mask) {

            addr = ((addr & ~1) << 1) | plane;

            if (addr >= s->vram_size) {

                return;

            }

            s->vram_ptr[addr] = val;

#ifdef DEBUG_VGA_MEM

            printf("vga: odd/even: [0x" TARGET_FMT_plx "]\n", addr);

#endif

            s->plane_updated |= mask; /* only used to detect font change */

            memory_region_set_dirty(&s->vram, addr, 1);

        }

    } else {

        /* standard VGA latched access */

        write_mode = s->gr[VGA_GFX_MODE] & 3;

        switch(write_mode) {

        default:

        case 0:

            /* rotate */

            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;

            val = ((val >> b) | (val << (8 - b))) & 0xff;

            val |= val << 8;

            val |= val << 16;



            /* apply set/reset mask */

            set_mask = mask16[s->gr[VGA_GFX_SR_ENABLE]];

            val = (val & ~set_mask) |

                (mask16[s->gr[VGA_GFX_SR_VALUE]] & set_mask);

            bit_mask = s->gr[VGA_GFX_BIT_MASK];

            break;

        case 1:

            val = s->latch;

            goto do_write;

        case 2:

            val = mask16[val & 0x0f];

            bit_mask = s->gr[VGA_GFX_BIT_MASK];

            break;

        case 3:

            /* rotate */

            b = s->gr[VGA_GFX_DATA_ROTATE] & 7;

            val = (val >> b) | (val << (8 - b));



            bit_mask = s->gr[VGA_GFX_BIT_MASK] & val;

            val = mask16[s->gr[VGA_GFX_SR_VALUE]];

            break;

        }



        /* apply logical operation */

        func_select = s->gr[VGA_GFX_DATA_ROTATE] >> 3;

        switch(func_select) {

        case 0:

        default:

            /* nothing to do */

            break;

        case 1:

            /* and */

            val &= s->latch;

            break;

        case 2:

            /* or */

            val |= s->latch;

            break;

        case 3:

            /* xor */

            val ^= s->latch;

            break;

        }



        /* apply bit mask */

        bit_mask |= bit_mask << 8;

        bit_mask |= bit_mask << 16;

        val = (val & bit_mask) | (s->latch & ~bit_mask);



    do_write:

        /* mask data according to sr[2] */

        mask = s->sr[VGA_SEQ_PLANE_WRITE];

        s->plane_updated |= mask; /* only used to detect font change */

        write_mask = mask16[mask];

        if (addr * sizeof(uint32_t) >= s->vram_size) {

            return;

        }

        ((uint32_t *)s->vram_ptr)[addr] =

            (((uint32_t *)s->vram_ptr)[addr] & ~write_mask) |

            (val & write_mask);

#ifdef DEBUG_VGA_MEM

        printf("vga: latch: [0x" TARGET_FMT_plx "] mask=0x%08x val=0x%08x\n",

               addr * 4, write_mask, val);

#endif

        memory_region_set_dirty(&s->vram, addr << 2, sizeof(uint32_t));

    }

}
