diff options
-rw-r--r-- | hw/musicpal.c | 149 |
1 files changed, 90 insertions, 59 deletions
diff --git a/hw/musicpal.c b/hw/musicpal.c index 8eb13160aa..9fb6c61090 100644 --- a/hw/musicpal.c +++ b/hw/musicpal.c @@ -72,30 +72,6 @@ static uint32_t gpio_isr; static uint32_t gpio_out_state; static ram_addr_t sram_off; -/* Address conversion helpers */ -static void *target2host_addr(uint32_t addr) -{ - if (addr < MP_SRAM_BASE) { - if (addr >= MP_RAM_DEFAULT_SIZE) - return NULL; - return (void *)(phys_ram_base + addr); - } else { - if (addr >= MP_SRAM_BASE + MP_SRAM_SIZE) - return NULL; - return (void *)(phys_ram_base + sram_off + addr - MP_SRAM_BASE); - } -} - -static uint32_t host2target_addr(void *addr) -{ - if (addr < ((void *)phys_ram_base) + sram_off) - return (unsigned long)addr - (unsigned long)phys_ram_base; - else - return (unsigned long)addr - (unsigned long)phys_ram_base - - sram_off + MP_SRAM_BASE; -} - - typedef enum i2c_state { STOPPED = 0, INITIALIZING, @@ -253,7 +229,7 @@ typedef struct musicpal_audio_state { uint32_t status; uint32_t irq_enable; unsigned long phys_buf; - int8_t *target_buffer; + uint32_t target_buffer; unsigned int threshold; unsigned int play_pos; unsigned int last_free; @@ -265,6 +241,7 @@ static void audio_callback(void *opaque, int free_out, int free_in) { musicpal_audio_state *s = opaque; int16_t *codec_buffer; + int8_t buf[4096]; int8_t *mem_buffer; int pos, block_size; @@ -281,7 +258,12 @@ static void audio_callback(void *opaque, int free_out, int free_in) if (free_out - s->last_free < block_size) return; - mem_buffer = s->target_buffer + s->play_pos; + if (block_size > 4096) + return; + + cpu_physical_memory_read(s->target_buffer + s->play_pos, (void *)buf, + block_size); + mem_buffer = buf; if (s->playback_mode & MP_AUDIO_16BIT_SAMPLE) { if (s->playback_mode & MP_AUDIO_MONO) { codec_buffer = wm8750_dac_buffer(s->wm, block_size >> 1); @@ -399,7 +381,7 @@ static void musicpal_audio_write(void *opaque, target_phys_addr_t offset, case MP_AUDIO_TX_START_LO: s->phys_buf = (s->phys_buf & 0xFFFF0000) | (value & 0xFFFF); - s->target_buffer = target2host_addr(s->phys_buf); + s->target_buffer = s->phys_buf; s->play_pos = 0; s->last_free = 0; break; @@ -410,7 +392,7 @@ static void musicpal_audio_write(void *opaque, target_phys_addr_t offset, case MP_AUDIO_TX_START_HI: s->phys_buf = (s->phys_buf & 0xFFFF) | (value << 16); - s->target_buffer = target2host_addr(s->phys_buf); + s->target_buffer = s->phys_buf; s->play_pos = 0; s->last_free = 0; break; @@ -555,13 +537,33 @@ typedef struct mv88w8618_eth_state { uint32_t icr; uint32_t imr; int vlan_header; - mv88w8618_tx_desc *tx_queue[2]; - mv88w8618_rx_desc *rx_queue[4]; - mv88w8618_rx_desc *frx_queue[4]; - mv88w8618_rx_desc *cur_rx[4]; + uint32_t tx_queue[2]; + uint32_t rx_queue[4]; + uint32_t frx_queue[4]; + uint32_t cur_rx[4]; VLANClientState *vc; } mv88w8618_eth_state; +static void eth_rx_desc_put(uint32_t addr, mv88w8618_rx_desc *desc) +{ + cpu_to_le32s(&desc->cmdstat); + cpu_to_le16s(&desc->bytes); + cpu_to_le16s(&desc->buffer_size); + cpu_to_le32s(&desc->buffer); + cpu_to_le32s(&desc->next); + cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc)); +} + +static void eth_rx_desc_get(uint32_t addr, mv88w8618_rx_desc *desc) +{ + cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc)); + le32_to_cpus(&desc->cmdstat); + le16_to_cpus(&desc->bytes); + le16_to_cpus(&desc->buffer_size); + le32_to_cpus(&desc->buffer); + le32_to_cpus(&desc->next); +} + static int eth_can_receive(void *opaque) { return 1; @@ -570,47 +572,76 @@ static int eth_can_receive(void *opaque) static void eth_receive(void *opaque, const uint8_t *buf, int size) { mv88w8618_eth_state *s = opaque; - mv88w8618_rx_desc *desc; + uint32_t desc_addr; + mv88w8618_rx_desc desc; int i; for (i = 0; i < 4; i++) { - desc = s->cur_rx[i]; - if (!desc) + desc_addr = s->cur_rx[i]; + if (!desc_addr) continue; do { - if (le32_to_cpu(desc->cmdstat) & MP_ETH_RX_OWN && - le16_to_cpu(desc->buffer_size) >= size) { - memcpy(target2host_addr(le32_to_cpu(desc->buffer) + - s->vlan_header), - buf, size); - desc->bytes = cpu_to_le16(size + s->vlan_header); - desc->cmdstat &= cpu_to_le32(~MP_ETH_RX_OWN); - s->cur_rx[i] = target2host_addr(le32_to_cpu(desc->next)); + eth_rx_desc_get(desc_addr, &desc); + if ((desc.cmdstat & MP_ETH_RX_OWN) && desc.buffer_size >= size) { + cpu_physical_memory_write(desc.buffer + s->vlan_header, + buf, size); + desc.bytes = size + s->vlan_header; + desc.cmdstat &= ~MP_ETH_RX_OWN; + s->cur_rx[i] = desc.next; s->icr |= MP_ETH_IRQ_RX; if (s->icr & s->imr) qemu_irq_raise(s->irq); + eth_rx_desc_put(desc_addr, &desc); return; } - desc = target2host_addr(le32_to_cpu(desc->next)); - } while (desc != s->rx_queue[i]); + desc_addr = desc.next; + } while (desc_addr != s->rx_queue[i]); } } +static void eth_tx_desc_put(uint32_t addr, mv88w8618_tx_desc *desc) +{ + cpu_to_le32s(&desc->cmdstat); + cpu_to_le16s(&desc->res); + cpu_to_le16s(&desc->bytes); + cpu_to_le32s(&desc->buffer); + cpu_to_le32s(&desc->next); + cpu_physical_memory_write(addr, (void *)desc, sizeof(*desc)); +} + +static void eth_tx_desc_get(uint32_t addr, mv88w8618_tx_desc *desc) +{ + cpu_physical_memory_read(addr, (void *)desc, sizeof(*desc)); + le32_to_cpus(&desc->cmdstat); + le16_to_cpus(&desc->res); + le16_to_cpus(&desc->bytes); + le32_to_cpus(&desc->buffer); + le32_to_cpus(&desc->next); +} + static void eth_send(mv88w8618_eth_state *s, int queue_index) { - mv88w8618_tx_desc *desc = s->tx_queue[queue_index]; + uint32_t desc_addr = s->tx_queue[queue_index]; + mv88w8618_tx_desc desc; + uint8_t buf[2048]; + int len; + do { - if (le32_to_cpu(desc->cmdstat) & MP_ETH_TX_OWN) { - qemu_send_packet(s->vc, - target2host_addr(le32_to_cpu(desc->buffer)), - le16_to_cpu(desc->bytes)); - desc->cmdstat &= cpu_to_le32(~MP_ETH_TX_OWN); + eth_tx_desc_get(desc_addr, &desc); + if (desc.cmdstat & MP_ETH_TX_OWN) { + len = desc.bytes; + if (len < 2048) { + cpu_physical_memory_read(desc.buffer, buf, len); + qemu_send_packet(s->vc, buf, len); + } + desc.cmdstat &= ~MP_ETH_TX_OWN; s->icr |= 1 << (MP_ETH_IRQ_TXLO_BIT - queue_index); + eth_tx_desc_put(desc_addr, &desc); } - desc = target2host_addr(le32_to_cpu(desc->next)); - } while (desc != s->tx_queue[queue_index]); + desc_addr = desc.next; + } while (desc_addr != s->tx_queue[queue_index]); } static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset) @@ -641,13 +672,13 @@ static uint32_t mv88w8618_eth_read(void *opaque, target_phys_addr_t offset) return s->imr; case MP_ETH_FRDP0 ... MP_ETH_FRDP3: - return host2target_addr(s->frx_queue[(offset - MP_ETH_FRDP0)/4]); + return s->frx_queue[(offset - MP_ETH_FRDP0)/4]; case MP_ETH_CRDP0 ... MP_ETH_CRDP3: - return host2target_addr(s->rx_queue[(offset - MP_ETH_CRDP0)/4]); + return s->rx_queue[(offset - MP_ETH_CRDP0)/4]; case MP_ETH_CTDP0 ... MP_ETH_CTDP3: - return host2target_addr(s->tx_queue[(offset - MP_ETH_CTDP0)/4]); + return s->tx_queue[(offset - MP_ETH_CTDP0)/4]; default: return 0; @@ -688,16 +719,16 @@ static void mv88w8618_eth_write(void *opaque, target_phys_addr_t offset, break; case MP_ETH_FRDP0 ... MP_ETH_FRDP3: - s->frx_queue[(offset - MP_ETH_FRDP0)/4] = target2host_addr(value); + s->frx_queue[(offset - MP_ETH_FRDP0)/4] = value; break; case MP_ETH_CRDP0 ... MP_ETH_CRDP3: s->rx_queue[(offset - MP_ETH_CRDP0)/4] = - s->cur_rx[(offset - MP_ETH_CRDP0)/4] = target2host_addr(value); + s->cur_rx[(offset - MP_ETH_CRDP0)/4] = value; break; case MP_ETH_CTDP0 ... MP_ETH_CTDP3: - s->tx_queue[(offset - MP_ETH_CTDP0)/4] = target2host_addr(value); + s->tx_queue[(offset - MP_ETH_CTDP0)/4] = value; break; } } |