static void lan9118_writel(void *opaque, target_phys_addr_t offset,

                           uint64_t val, unsigned size)

{

    lan9118_state *s = (lan9118_state *)opaque;

    offset &= 0xff;



    

    if (offset >= 0x20 && offset < 0x40) {

        

        tx_fifo_push(s, val);

        return;

    }

    switch (offset) {

    case CSR_IRQ_CFG:

        

        val &= (IRQ_EN | IRQ_POL | IRQ_TYPE);

        s->irq_cfg = (s->irq_cfg & IRQ_INT) | val;

        break;

    case CSR_INT_STS:

        s->int_sts &= ~val;

        break;

    case CSR_INT_EN:

        s->int_en = val & ~RESERVED_INT;

        s->int_sts |= val & SW_INT;

        break;

    case CSR_FIFO_INT:

        DPRINTF("FIFO INT levels %08x\n", val);

        s->fifo_int = val;

        break;

    case CSR_RX_CFG:

        if (val & 0x8000) {

            

            s->rx_fifo_used = 0;

            s->rx_status_fifo_used = 0;

            s->rx_packet_size_tail = s->rx_packet_size_head;

            s->rx_packet_size[s->rx_packet_size_head] = 0;

        }

        s->rx_cfg = val & 0xcfff1ff0;

        break;

    case CSR_TX_CFG:

        if (val & 0x8000) {

            s->tx_status_fifo_used = 0;

        }

        if (val & 0x4000) {

            s->txp->state = TX_IDLE;

            s->txp->fifo_used = 0;

            s->txp->cmd_a = 0xffffffff;

        }

        s->tx_cfg = val & 6;

        break;

    case CSR_HW_CFG:

        if (val & 1) {

            

            lan9118_reset(&s->busdev.qdev);

        } else {

            s->hw_cfg = (val & 0x003f300) | (s->hw_cfg & 0x4);

        }

        break;

    case CSR_RX_DP_CTRL:

        if (val & 0x80000000) {

            

            s->rxp_pad = 0;

            s->rxp_offset = 0;

            if (s->rxp_size == 0) {

                

                rx_fifo_pop(s);

                s->rxp_pad = 0;

                s->rxp_offset = 0;

            }

            s->rx_fifo_head += s->rxp_size;

            if (s->rx_fifo_head >= s->rx_fifo_size) {

                s->rx_fifo_head -= s->rx_fifo_size;

            }

        }

        break;

    case CSR_PMT_CTRL:

        if (val & 0x400) {

            phy_reset(s);

        }

        s->pmt_ctrl &= ~0x34e;

        s->pmt_ctrl |= (val & 0x34e);

        break;

    case CSR_GPIO_CFG:

        

        s->gpio_cfg = val & 0x7777071f;

        break;

    case CSR_GPT_CFG:

        if ((s->gpt_cfg ^ val) & GPT_TIMER_EN) {

            if (val & GPT_TIMER_EN) {

                ptimer_set_count(s->timer, val & 0xffff);

                ptimer_run(s->timer, 0);

            } else {

                ptimer_stop(s->timer);

                ptimer_set_count(s->timer, 0xffff);

            }

        }

        s->gpt_cfg = val & (GPT_TIMER_EN | 0xffff);

        break;

    case CSR_WORD_SWAP:

        

        s->word_swap = val;

        break;

    case CSR_MAC_CSR_CMD:

        s->mac_cmd = val & 0x4000000f;

        if (val & 0x80000000) {

            if (val & 0x40000000) {

                s->mac_data = do_mac_read(s, val & 0xf);

                DPRINTF("MAC read %d = 0x%08x\n", val & 0xf, s->mac_data);

            } else {

                DPRINTF("MAC write %d = 0x%08x\n", val & 0xf, s->mac_data);

                do_mac_write(s, val & 0xf, s->mac_data);

            }

        }

        break;

    case CSR_MAC_CSR_DATA:

        s->mac_data = val;

        break;

    case CSR_AFC_CFG:

        s->afc_cfg = val & 0x00ffffff;

        break;

    case CSR_E2P_CMD:

        lan9118_eeprom_cmd(s, (val >> 28) & 7, val & 0x7f);

        break;

    case CSR_E2P_DATA:

        s->e2p_data = val & 0xff;

        break;



    default:

        hw_error("lan9118_write: Bad reg 0x%x = %x\n", (int)offset, (int)val);

        break;

    }

    lan9118_update(s);

}
