=== added file 'hw/dm9000.c' --- hw/dm9000.c 1970-01-01 00:00:00 +0000 +++ hw/dm9000.c 2007-04-17 09:46:17 +0000 @@ -0,0 +1,623 @@ +/* hw/dm9000.c + * + * DM9000 Ethernet interface + * + * Copyright Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#include +#include "vl.h" +#include "hw/irq.h" + +/* Comment this out if you don't want register debug on stderr */ +//#define DM9000_DEBUG + +/* Comment this out if you don't want a packet dump */ +//#define DM9000_DUMP_FILENAME "/tmp/dm9k_dump" + +#ifdef DM9000_DEBUG +#define DM9000_DBF(X...) fprintf(stderr, X) +#else +#define DM9000_DBF(X...) if(0) fprintf(stderr, X) +#endif + +#define DM9000_REG_NCR 0x00 +#define DM9000_REG_NSR 0x01 +#define DM9000_REG_TCR 0x02 +#define DM9000_REG_TSR1 0x03 +#define DM9000_REG_TSR2 0x04 +#define DM9000_REG_RCR 0x05 +#define DM9000_REG_RSR 0x06 +#define DM9000_REG_ROCR 0x07 +#define DM9000_REG_BPTR 0x08 +#define DM9000_REG_FCTR 0x09 +#define DM9000_REG_FCR 0x0A +#define DM9000_REG_EPCR 0x0B +#define DM9000_REG_EPAR 0x0C +#define DM9000_REG_EPDRL 0x0D +#define DM9000_REG_EPDRH 0x0E +#define DM9000_REG_WCR 0x0F +#define DM9000_REG_PAR0 0x10 +#define DM9000_REG_PAR1 0x11 +#define DM9000_REG_PAR2 0x12 +#define DM9000_REG_PAR3 0x13 +#define DM9000_REG_PAR4 0x14 +#define DM9000_REG_PAR5 0x15 +#define DM9000_REG_MAR0 0x16 +#define DM9000_REG_MAR1 0x17 +#define DM9000_REG_MAR2 0x18 +#define DM9000_REG_MAR3 0x19 +#define DM9000_REG_MAR4 0x1A +#define DM9000_REG_MAR5 0x1B +#define DM9000_REG_MAR6 0x1C +#define DM9000_REG_MAR7 0x1D +#define DM9000_REG_GPCR 0x1E +#define DM9000_REG_GPR 0x1F +#define DM9000_REG_TRPAL 0x22 +#define DM9000_REG_TRPAH 0x23 +#define DM9000_REG_RWPAL 0x24 +#define DM9000_REG_RWPAH 0x25 +#define DM9000_REG_VIDL 0x28 +#define DM9000_REG_VIDH 0x29 +#define DM9000_REG_PIDL 0x2A +#define DM9000_REG_PIDH 0x2B +#define DM9000_REG_CHIPR 0x2C +#define DM9000_REG_SMCR 0x2F +#define DM9000_REG_MRCMDX 0xF0 +#define DM9000_REG_MRCMD 0xF2 +#define DM9000_REG_MRRL 0xF4 +#define DM9000_REG_MRRH 0xF5 +#define DM9000_REG_MWCMDX 0xF6 +#define DM9000_REG_MWCMD 0xF8 +#define DM9000_REG_MWRL 0xFA +#define DM9000_REG_MWRH 0xFB +#define DM9000_REG_TXPLL 0xFC +#define DM9000_REG_TXPLH 0xFD +#define DM9000_REG_ISR 0xFE +#define DM9000_REG_IMR 0xFF + +#define DM9000_NCR_RESET 0x01 +#define DM9000_NSR_TX1END 0x04 +#define DM9000_NSR_TX2END 0x08 +#define DM9000_TCR_TXREQ 0x01 + +#define DM9000_IMR_AUTOWRAP 0x80 + +#define DM9000_MII_READ 0x0C +#define DM9000_MII_WRITE 0x0A + +#define DM9000_MII_REG_BMCR 0x00 +#define DM9000_MII_REG_STATUS 0x01 +#define DM9000_MII_REG_PHYID1 0x02 +#define DM9000_MII_REG_PHYID2 0x03 +#define DM9000_MII_REG_ANAR 0x04 +#define DM9000_MII_REG_ANLPAR 0x05 +#define DM9000_MII_REG_ANER 0x06 +#define DM9000_MII_REG_DSCR 0x10 +#define DM9000_MII_REG_DSCSR 0x11 +#define DM9000_MII_REG_10BTCSR 0x12 + + +typedef struct { + uint32_t addr; /* address port */ + uint32_t data; /* data port */ + VLANClientState *vc; + qemu_irq irq; + uint8_t macaddr[6]; + uint8_t address; /* The internal magial address */ + uint8_t packet_buffer[16 * 1024]; + uint16_t dm9k_mrr, dm9k_mwr; /* Read and write address registers */ + uint16_t dm9k_txpl; /* TX packet length */ + uint16_t dm9k_trpa, dm9k_rwpa; /* TX Read ptr address, RX write ptr address */ + uint8_t dm9k_imr, dm9k_isr; /* Interrupt mask register and status register*/ + uint8_t dm9k_ncr, dm9k_nsr; /* Network control register, network status register */ + uint8_t dm9k_wcr; /* Wakeup control */ + uint8_t dm9k_tcr; /* Transmission control register */ + uint8_t packet_copy_buffer[3 * 1024]; /* packet copy buffer */ + unsigned int packet_index:1; /* 0 == packet I, 1 == packet II */ + + /* Internal MII PHY state */ + uint8_t dm9k_epcr; /* EEPROM/PHY control register */ + uint8_t dm9k_epar; /* EEPROM/PHY address register */ + uint16_t dm9k_epdr; /* EEPROM/PHY data register */ + /* MII Regs */ + uint16_t dm9k_mii_bmcr; + uint16_t dm9k_mii_anar; + uint16_t dm9k_mii_dscr; + +} dm9000_state; + + +#ifdef DM9000_DUMP_FILENAME +#include +static uint8_t pcap_header[24] = { + 0xA1, 0xB2, 0xC3, 0xD4, /* TCPDUMP Magic */ + 0x00, 0x02, 0x00, 0x04, /* Major 2, Minor 4 */ + 0x00, 0x00, 0x00, 0x00, /* Timezone offset */ + 0x00, 0x00, 0x00, 0x01, /* Accuracy of timestamps */ + 0x00, 0x00, 0x0C, 0x00, /* Snaplen 3KiB */ + 0x00, 0x00, 0x00, 0x01, /* Ethernet frames */ +}; +static uint8_t nulls[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +static void dm9k_dump_packet(uint8_t *buf, uint32_t size) +{ + FILE* dm9k_fileh = fopen(DM9000_DUMP_FILENAME, "ab+"); + unsigned long bsize = htonl(size); + DM9000_DBF("Dumping packet at %08x (%d bytes)\n", buf, size); + fseek(dm9k_fileh, 0, SEEK_END); + if(ftell(dm9k_fileh)==0) fwrite(pcap_header, 1, 24, dm9k_fileh); + fwrite(nulls, 1, 8, dm9k_fileh); + fwrite(&bsize, 1, 4, dm9k_fileh); + fwrite(&bsize, 1, 4, dm9k_fileh); + fwrite(buf, 1, size, dm9k_fileh); + fclose(dm9k_fileh); +} +#else +#define dm9k_dump_packet(X...) do { } while(0) +#endif + +static void dm9000_raise_irq(dm9000_state *state) +{ + int level = ((state->dm9k_isr & state->dm9k_imr) & 0x03) != 0; + DM9000_DBF("DM9000: Set IRQ level %d\n", level); + qemu_set_irq(state->irq, level); +} + +static void dm9000_soft_reset_mii(dm9000_state *state) +{ + state->dm9k_mii_bmcr = 0x3100; /* 100Mbps, AUTONEG, FULL DUPLEX */ + state->dm9k_mii_anar = 0x01E1; + state->dm9k_mii_dscr = 0x0410; +} + +static void dm9000_soft_reset(dm9000_state *state) +{ + DM9000_DBF("DM9000: Soft Reset\n"); + state->dm9k_mrr = state->dm9k_mwr = state->dm9k_txpl = state->dm9k_trpa = 0x0000; + state->dm9k_rwpa = 0x0C04; + state->dm9k_imr = 0; + state->dm9k_isr = 0; /* 16 bit mode, no interrupts asserted */ + state->dm9k_tcr = 0; + state->packet_index = 0; + memset(state->packet_buffer, 0, 16*1024); + memset(state->packet_copy_buffer, 0, 3*1024); + /* These registers have some bits "unaffected by software reset" */ + /* Clear the reset bits */ + state->dm9k_ncr &= 0xA0; + state->dm9k_nsr &= 0xD0; + /* Claim full duplex */ + state->dm9k_ncr |= 1<<3; + /* Set link status to 1 */ + state->dm9k_nsr |= 1<<6; + /* dm9k_wcr is unaffected or reserved, never reset */ + /* MII control regs */ + state->dm9k_epcr = 0x00; + state->dm9k_epar = 0x40; + /* reset the MII */ + dm9000_soft_reset_mii(state); + dm9000_raise_irq(state); /* Clear any potentially pending IRQ */ +} + +static void dm9000_hard_reset(dm9000_state *state) +{ + state->dm9k_ncr = 0x00; + state->dm9k_nsr = 0x00; + state->dm9k_wcr = 0x00; + dm9000_soft_reset(state); +} + +static void dm9000_do_transmit(dm9000_state *state) +{ + uint16_t idx, cnt, tptr; + idx = state->dm9k_trpa; + cnt = state->dm9k_txpl; + tptr = 0; + if( cnt > 3*1024 ) cnt = 3*1024; /* HARD CAP AT 3KiB */ + DM9000_DBF("TX_Packet: %d bytes from %04x\n", cnt, idx); + while(cnt--) { + state->packet_copy_buffer[tptr++] = state->packet_buffer[idx++]; + if( idx == 0x0C00 ) idx = 0; + } + /* DM9KNOTE: Assumes 16bit wiring */ + idx = (idx+1) & ~1; /* Round up to nearest 16bit boundary */ + if( idx == 0x0C00 ) idx = 0; + state->dm9k_trpa = idx; + dm9k_dump_packet(state->packet_copy_buffer, state->dm9k_txpl); + /* We have the copy buffer, now we do the transmit */ + qemu_send_packet(state->vc, state->packet_copy_buffer, state->dm9k_txpl); + /* Clear the "please xmit" bit */ + state->dm9k_tcr &= ~DM9000_TCR_TXREQ; + /* Set the TXEND bit */ + state->dm9k_nsr |= 1<<(2+state->packet_index); + DM9000_DBF("TX: NSR=%02x PI=%d\n", state->dm9k_nsr, state->packet_index); + /* Claim a TX complete IRQ */ + state->dm9k_isr |= 0x02; /* Packet transmitted latch */ + /* And flip the next-packet bit */ + state->packet_index = !state->packet_index; + dm9000_raise_irq(state); +} + +static void dm9000_mii_read(dm9000_state *state) +{ + int mii_reg = (state->dm9k_epar) & 0x3f; + uint16_t ret = 0; + switch(mii_reg) { + case DM9000_MII_REG_BMCR: + ret = state->dm9k_mii_bmcr; + break; + case DM9000_MII_REG_STATUS: + ret = 0x782D; /* No 100/T4, Can 100/FD, Can 100/HD, Can 10/FD, Can 10/HD, + * No Preamble suppression, Autoneg complete, No remote fault, + * Can autoneg, link up, no jabber, extended capability */ + break; + case DM9000_MII_REG_PHYID1: + ret = 0x0181; + break; + case DM9000_MII_REG_PHYID2: + ret = 0xB8C0; + break; + case DM9000_MII_REG_ANAR: + ret = state->dm9k_mii_anar; + break; + case DM9000_MII_REG_ANLPAR: + ret = 0x0400; + break; + case DM9000_MII_REG_ANER: + ret = 0x0001; + break; + case DM9000_MII_REG_DSCR: + ret = state->dm9k_mii_dscr; + break; + case DM9000_MII_REG_DSCSR: + ret = 0xF008; + break; + case DM9000_MII_REG_10BTCSR: + ret = 0x7800; + } + state->dm9k_epdr = ret; + DM9000_DBF("DM9000:MIIPHY: Read of MII reg %d gives %04x\n", mii_reg, state->dm9k_epdr); +} + +static void dm9000_mii_write(dm9000_state *state) +{ + int mii_reg = (state->dm9k_epar) & 0x3f; + DM9000_DBF("DM9000:MIIPHY: Write of MII reg %d value %04x\n", mii_reg, state->dm9k_epdr); + switch(mii_reg) { + case DM9000_MII_REG_BMCR: + state->dm9k_mii_bmcr = (state->dm9k_epdr &~0x8000); + if( state->dm9k_epdr & 0x8000 ) dm9000_soft_reset_mii(state); + break; + case DM9000_MII_REG_ANAR: + state->dm9k_mii_anar = state->dm9k_epdr; + break; + case DM9000_MII_REG_DSCR: + state->dm9k_mii_dscr = state->dm9k_epdr & ~0x0008; + break; + } +} + +static void dm9000_write(void *opaque, target_phys_addr_t address, + uint32_t value) +{ + dm9000_state *state = (dm9000_state *)opaque; +#ifdef DM9000_DEBUG + int suppress_debug = 0; +#endif + + if (address == state->addr) { + if( (value != DM9000_REG_MRCMD) && + (value != DM9000_REG_MWCMD) ) + DM9000_DBF("DM9000: Address set to 0x%02x\n", value); + state->address = value; + return; + } + + switch(state->address) { + case DM9000_REG_NCR: + state->dm9k_ncr = value & 0xDF; + if (state->dm9k_ncr & DM9000_NCR_RESET) + dm9000_soft_reset(state); + break; + case DM9000_REG_NSR: + state->dm9k_nsr &= ~(value & 0x2C); + break; + case DM9000_REG_TCR: + state->dm9k_tcr = value & 0xFF; + if( value & DM9000_TCR_TXREQ ) dm9000_do_transmit(state); + break; + case DM9000_REG_EPCR: + state->dm9k_epcr = value & 0xFF; + if( value & DM9000_MII_READ ) + dm9000_mii_read(state); + else if( value & DM9000_MII_WRITE ) + dm9000_mii_write(state); + break; + case DM9000_REG_EPAR: + state->dm9k_epar = value & 0xFF; + break; + case DM9000_REG_EPDRL: + state->dm9k_epdr &= 0xFF00; + state->dm9k_epdr |= value & 0xFF; + break; + case DM9000_REG_EPDRH: + state->dm9k_epdr &= 0xFF; + state->dm9k_epdr |= (value & 0xFF) << 8; + break; + case DM9000_REG_PAR0: + case DM9000_REG_PAR1: + case DM9000_REG_PAR2: + case DM9000_REG_PAR3: + case DM9000_REG_PAR4: + case DM9000_REG_PAR5: + state->macaddr[state->address - DM9000_REG_PAR0] = value & 0xFF; + break; + case DM9000_REG_MRRL: + state->dm9k_mrr &= 0xFF00; + state->dm9k_mrr |= value & 0xFF; + break; + case DM9000_REG_MRRH: + state->dm9k_mrr &= 0xFF; + state->dm9k_mrr |= (value & 0xFF) << 8; + break; + case DM9000_REG_MWCMDX: + case DM9000_REG_MWCMD: + /* DM9KNOTE: This assumes a 16bit wide wiring */ + state->packet_buffer[state->dm9k_mwr] = value & 0xFF; + state->packet_buffer[state->dm9k_mwr+1] = (value >> 8) & 0xFF; + if( state->address == DM9000_REG_MWCMD ) { + state->dm9k_mwr += 2; + if( state->dm9k_imr & DM9000_IMR_AUTOWRAP ) + if( state->dm9k_mwr >= 0x0C00 ) + state->dm9k_mwr -= 0x0C00; + } +#ifdef DM9000_DEBUG + suppress_debug = 1; +#endif + break; + case DM9000_REG_MWRL: + state->dm9k_mwr &= 0xFF00; + state->dm9k_mwr |= value & 0xFF; + break; + case DM9000_REG_MWRH: + state->dm9k_mwr &= 0xFF; + state->dm9k_mwr |= (value & 0xFF) << 8; + break; + case DM9000_REG_TXPLL: + state->dm9k_txpl &= 0xFF00; + state->dm9k_txpl |= value & 0xFF; + break; + case DM9000_REG_TXPLH: + state->dm9k_txpl &= 0xFF; + state->dm9k_txpl |= (value & 0xFF) << 8; + break; + case DM9000_REG_ISR: + state->dm9k_isr &= ~(value & 0x0F); + dm9000_raise_irq(state); + break; + case DM9000_REG_IMR: + if( !(state->dm9k_imr & DM9000_IMR_AUTOWRAP) && + (value & DM9000_IMR_AUTOWRAP) ) + state->dm9k_mrr = 0x0C00 | (state->dm9k_mrr & 0xFF); + state->dm9k_imr = value & 0xFF; + dm9000_raise_irq(state); + break; + } +#ifdef DM9000_DEBUG + if(!suppress_debug) DM9000_DBF("DM9000: Write value %04x\n", value); +#endif +} + +static uint32_t dm9000_read(void *opaque, target_phys_addr_t address) +{ + dm9000_state *state = (dm9000_state *)opaque; + uint32_t ret = 0; +#ifdef DM9000_DEBUG + int suppress_debug = 0; +#endif + + if (address == state->addr) + return state->address; + switch(state->address) { + case DM9000_REG_NCR: + ret = state->dm9k_ncr; + break; + case DM9000_REG_NSR: + ret = state->dm9k_nsr; + /* Note, TX1END and TX2END are *CLEAR ON READ* */ + state->dm9k_nsr &= ~(DM9000_NSR_TX1END | DM9000_NSR_TX2END); + break; + case DM9000_REG_TCR: + ret = state->dm9k_tcr; + break; + case DM9000_REG_TSR1: + case DM9000_REG_TSR2: + ret = 0x00; /* No error, yay! */ + break; + case DM9000_REG_EPCR: + ret = state->dm9k_epcr; + break; + case DM9000_REG_EPAR: + ret = state->dm9k_epar; + break; + case DM9000_REG_EPDRL: + ret = state->dm9k_epdr & 0xFF; + break; + case DM9000_REG_EPDRH: + ret = (state->dm9k_epdr >> 8) & 0xFF; + break; + case DM9000_REG_PAR0: + case DM9000_REG_PAR1: + case DM9000_REG_PAR2: + case DM9000_REG_PAR3: + case DM9000_REG_PAR4: + case DM9000_REG_PAR5: + ret = state->macaddr[state->address - DM9000_REG_PAR0]; + break; + case DM9000_REG_TRPAL: + ret = state->dm9k_trpa & 0xFF; + break; + case DM9000_REG_TRPAH: + ret = state->dm9k_trpa >> 8; + break; + case DM9000_REG_RWPAL: + ret = state->dm9k_rwpa & 0xFF; + break; + case DM9000_REG_RWPAH: + ret = state->dm9k_rwpa >> 8; + break; + case DM9000_REG_VIDL: + ret = 0x46; + break; + case DM9000_REG_VIDH: + ret = 0x0A; + break; + case DM9000_REG_PIDL: + ret = 0x00; + break; + case DM9000_REG_PIDH: + ret = 0x90; + break; + case DM9000_REG_CHIPR: + ret = 0x00; + break; + case DM9000_REG_MRCMDX: + case DM9000_REG_MRCMD: + /* DM9KNOTE: This assumes a 16bit wide wiring */ + ret = state->packet_buffer[state->dm9k_mrr]; + ret |= state->packet_buffer[state->dm9k_mrr+1] << 8; + if( state->address == DM9000_REG_MRCMD ) { + state->dm9k_mrr += 2; + if( state->dm9k_mrr >= (16*1024) ) state->dm9k_mrr -= (16*1024); + if( state->dm9k_imr & DM9000_IMR_AUTOWRAP ) + if( state->dm9k_mrr < 0x0C00 ) + state->dm9k_mrr += 0x0C00; + } +#ifdef DM9000_DEBUG + if (state->address==DM9000_REG_MRCMD) + suppress_debug = 1; +#endif + break; + case DM9000_REG_MRRL: + ret = state->dm9k_mrr & 0xFF; + break; + case DM9000_REG_MRRH: + ret = state->dm9k_mrr >> 8; + break; + case DM9000_REG_MWRL: + ret = state->dm9k_mwr & 0xFF; + break; + case DM9000_REG_MWRH: + ret = state->dm9k_mwr >> 8; + break; + case DM9000_REG_TXPLL: + ret = state->dm9k_txpl & 0xFF; + break; + case DM9000_REG_TXPLH: + ret = state->dm9k_txpl >> 8; + break; + case DM9000_REG_ISR: + ret = state->dm9k_isr; + break; + case DM9000_REG_IMR: + ret = state->dm9k_imr; + break; + default: + ret = 0; + } + +#ifdef DM9000_DEBUG + if(!suppress_debug) DM9000_DBF("DM9000: Read gives: %04x\n", ret); +#endif + return ret; +} + + + +static int dm9000_can_receive(void *opaque) +{ + dm9000_state *state = (dm9000_state *)opaque; + uint16_t rx_space; + if( state->dm9k_rwpa < state->dm9k_mrr ) + rx_space = state->dm9k_mrr - state->dm9k_rwpa; + else + rx_space = (13*1024) - (state->dm9k_rwpa - state->dm9k_mrr); + DM9000_DBF("DM9000:RX_Packet: Asked about RX, rwpa=%d mrr=%d => space is %d bytes\n", + state->dm9k_rwpa, state->dm9k_mrr, rx_space); + if (rx_space > 2048) return 1; + return 0; +} + +static void dm9000_receive(void *opaque, const uint8_t *buf, int size) +{ + dm9000_state *state = (dm9000_state *)opaque; + uint16_t rxptr = state->dm9k_rwpa; + uint8_t magic_padding = 4; + if( size > 2048 ) return; /* La La La, I can't hear you */ + /* Fill out the magical header structure */ + DM9000_DBF("DM9000:RX_Packet: %d bytes into buffer at %04x\n", size, rxptr); + dm9k_dump_packet(buf, size); + if( size < 64 ) magic_padding += (64 - size); + DM9000_DBF("DM9000:RX_Packet: Magical padding is %d bytes\n", magic_padding); + size += magic_padding; /* The magical CRC bollocks */ + state->packet_buffer[state->dm9k_rwpa-4] = 0x01; /* Packet read */ + state->packet_buffer[state->dm9k_rwpa-3] = 0x00; /* Status OK */ + state->packet_buffer[state->dm9k_rwpa-2] = size & 0xFF; /* Size LOW */ + state->packet_buffer[state->dm9k_rwpa-1] = (size & 0xFF00)>>8; /* Size HIGH */ + size += 4; /* The magical next header (which we zero for fun) */ + while(size--) { + if( size > (magic_padding + 3) ) + state->packet_buffer[rxptr++] = *buf++; + else + state->packet_buffer[rxptr++] = 0x00; /* Clear to the next header */ + /* DM9KNOTE: Assumes 16 bit wired config */ + if (size == 4) rxptr = (rxptr+1) & ~1; /* At end of packet, realign */ + if( rxptr >= (16*1024) ) rxptr -= (16*1024); + if( rxptr < 0x0C00 ) rxptr += 0x0C00; + } + state->dm9k_rwpa = rxptr; + state->dm9k_isr |= 0x01; /* RX interrupt, yay */ + dm9000_raise_irq(state); +} + + +static CPUReadMemoryFunc *dm9000_readfn[] = { + dm9000_read, + dm9000_read, + dm9000_read +}; + +static CPUWriteMemoryFunc *dm9000_writefn[] = { + dm9000_write, + dm9000_write, + dm9000_write +}; + +/* initialises a dm9000 ethernet controller + * The dm9k has a single 16bit wide address and data port through which all + * operations are multiplexed, there is a single IRQ + */ +void dm9000_init(NICInfo *nd, target_phys_addr_t base_addr, + uint32_t addr_offset, uint32_t data_offset, + qemu_irq irq) +{ + dm9000_state *state; + int iomemtype; + + state = (dm9000_state *)qemu_mallocz(sizeof(dm9000_state)); + iomemtype = cpu_register_io_memory(0, dm9000_readfn, + dm9000_writefn, state); + cpu_register_physical_memory(base_addr, MAX(addr_offset, data_offset) + 4, iomemtype); + state->addr = base_addr + addr_offset; + state->data = base_addr + data_offset; + state->irq = irq; + memcpy(state->macaddr, nd->macaddr, 6); + + dm9000_hard_reset(state); + + state->vc = qemu_new_vlan_client(nd->vlan, dm9000_receive, + dm9000_can_receive, state); + +} === added file 'hw/s3c2410x.c' --- hw/s3c2410x.c 1970-01-01 00:00:00 +0000 +++ hw/s3c2410x.c 2007-04-17 09:14:20 +0000 @@ -0,0 +1,59 @@ +/* hw/s3c2410x.c + * + * Samsung S3C2410X emulation + * + * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#include "vl.h" +#include "s3c2410x.h" + +CPUState *s3c_env; +qemu_irq *s3c_irqs; +qemu_irq *s3c_eirqs; + +/* Initialise a Samsung S3C2410X and all its internal peripherals */ +CPUState * +s3c2410x_init(int ram_size) +{ + CPUState *env; + qemu_irq *interrupts, *irq; + /* Prepare the ARM 920T */ + s3c_env = env = cpu_init(); + cpu_arm_set_model(env, "arm920t"); + /* S3C2410X memory is always at the same physical location */ + S3C2410X_DBF("RAM\n"); + cpu_register_physical_memory(CPU_S3C2410X_RAM, ram_size, IO_MEM_RAM); + /* We get a memc */ + S3C2410X_DBF("memc\n"); + s3c2410x_memc_init(); + /* And some interrupts (coo) */ + S3C2410X_DBF("interrupts\n"); + s3c_irqs = interrupts = irq = s3c2410x_irq_init(env); + /* The clock control allows for idling the CPU */ + s3c2410x_clkcon_init(env); + /* And some GPIO */ + S3C2410X_DBF("gpio\n"); + s3c_eirqs = s3c2410x_gpio_init(s3c_irqs); + /* RTC for time */ + s3c2410x_rtc_init(); + /* And some IIC */ + s3c2410x_iic_init(interrupts[27]); + /* And some timers */ + s3c2410x_timers_init(interrupts[14]); + /* Serial ports */ + S3C2410X_DBF("serial\n"); + s3c2410x_serial_init(0, irq[33], irq[32], irq[33+64], irq[32+64]); /* Subsrc interrupts 1 and 0 edge and level */ + s3c2410x_serial_init(1, irq[36], irq[35], irq[36+64], irq[35+64]); /* Subsrc interrupts 4 and 3 edge and level */ + s3c2410x_serial_init(2, irq[39], irq[38], irq[39+64], irq[38+64]); /* Subsrc interrupts 7 and 6 edge and level */ + + /* S3C2410X SRAM */ + cpu_register_physical_memory(CPU_S3C2410X_SRAM, 4096, ram_size | IO_MEM_RAM); + /* A two port OHCI controller on IRQ 26 */ + usb_ohci_init_pxa(CPU_S3C2410X_OHCI, 2, -1, interrupts[26]); + return env; +} + === added file 'hw/s3c2410x.h' --- hw/s3c2410x.h 1970-01-01 00:00:00 +0000 +++ hw/s3c2410x.h 2007-04-17 09:10:53 +0000 @@ -0,0 +1,374 @@ +/* s3c2410x/regs.h + * + * Samsung s3c2410x cpu register definitions + * + * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2. + */ + +#ifndef S3C2410X_H +#define S3C2410X_H 1 + +#include "hw/irq.h" + +/* S3C2410X SoC IDs */ + +#define CPU_S3C2410X_IDENT_S3C2410X 0x32410000 +#define CPU_S3C2410X_IDENT_S3C2410A 0x32410002 + +/* all defines are prefixed with CPU_S3C2410X_ */ + +#define CPU_S3C2410X_REG(x) (0x48000000 + (x)) + +#define CPU_S3C2410X_CS0 (0x00000000) +#define CPU_S3C2410X_CS1 (0x08000000) +#define CPU_S3C2410X_CS2 (0x10000000) +#define CPU_S3C2410X_CS3 (0x18000000) +#define CPU_S3C2410X_CS4 (0x20000000) +#define CPU_S3C2410X_CS5 (0x28000000) +#define CPU_S3C2410X_RAM (0x30000000) +#define CPU_S3C2410X_SRAM (0x40000000) +#define CPU_S3C2410X_OHCI (0x49000000) + +/* Clock control */ +#define CPU_S3C2410X_CLKCON 0x4C000000 +/* Lock time RW */ +#define CPU_S3C2410X_REG_LOCKTIME 0 +/* MPLL Control RW */ +#define CPU_S3C2410X_REG_MPLLCON 1 +/* UPLL Control RW */ +#define CPU_S3C2410X_REG_UPLLCON 2 +/* Clock Generator Control RW */ +#define CPU_S3C2410X_REG_CLKCON 3 +/* Slow Clock Control RW */ +#define CPU_S3C2410X_REG_CLKSLOW 4 +/* Clock divider control RW */ +#define CPU_S3C2410X_REG_CLKDIVN 5 +/* CLKCON IDLE */ +#define CPU_S3C2410X_REG_CLKCON_IDLE (1<<2) + +/* bus width, and wait state control */ +#define CPU_S3C2410X_BWSCON CPU_S3C2410X_REG(0x0000) + +/* bank zero config - note, pinstrapped from OM pins! */ +#define CPU_S3C2410X_BWSCON_DW0_16 (1<<1) +#define CPU_S3C2410X_BWSCON_DW0_32 (2<<1) + +/* bank one configs */ +#define CPU_S3C2410X_BWSCON_DW1_8 (0<<4) +#define CPU_S3C2410X_BWSCON_DW1_16 (1<<4) +#define CPU_S3C2410X_BWSCON_DW1_32 (2<<4) +#define CPU_S3C2410X_BWSCON_WS1 (1<<6) +#define CPU_S3C2410X_BWSCON_ST1 (1<<7) + +/* bank 2 configurations */ +#define CPU_S3C2410X_BWSCON_DW2_8 (0<<8) +#define CPU_S3C2410X_BWSCON_DW2_16 (1<<8) +#define CPU_S3C2410X_BWSCON_DW2_32 (2<<8) +#define CPU_S3C2410X_BWSCON_WS2 (1<<10) +#define CPU_S3C2410X_BWSCON_ST2 (1<<11) + +/* bank 3 configurations */ +#define CPU_S3C2410X_BWSCON_DW3_8 (0<<12) +#define CPU_S3C2410X_BWSCON_DW3_16 (1<<12) +#define CPU_S3C2410X_BWSCON_DW3_32 (2<<12) +#define CPU_S3C2410X_BWSCON_WS3 (1<<14) +#define CPU_S3C2410X_BWSCON_ST3 (1<<15) + +/* bank 4 configurations */ +#define CPU_S3C2410X_BWSCON_DW4_8 (0<<16) +#define CPU_S3C2410X_BWSCON_DW4_16 (1<<16) +#define CPU_S3C2410X_BWSCON_DW4_32 (2<<16) +#define CPU_S3C2410X_BWSCON_WS4 (1<<18) +#define CPU_S3C2410X_BWSCON_ST4 (1<<19) + +/* bank 5 configurations */ +#define CPU_S3C2410X_BWSCON_DW5_8 (0<<20) +#define CPU_S3C2410X_BWSCON_DW5_16 (1<<20) +#define CPU_S3C2410X_BWSCON_DW5_32 (2<<20) +#define CPU_S3C2410X_BWSCON_WS5 (1<<22) +#define CPU_S3C2410X_BWSCON_ST5 (1<<23) + +/* bank 6 configurations */ +#define CPU_S3C2410X_BWSCON_DW6_8 (0<<24) +#define CPU_S3C2410X_BWSCON_DW6_16 (1<<24) +#define CPU_S3C2410X_BWSCON_DW6_32 (2<<24) +#define CPU_S3C2410X_BWSCON_WS6 (1<<26) +#define CPU_S3C2410X_BWSCON_ST6 (1<<27) + +/* bank 7 configurations */ +#define CPU_S3C2410X_BWSCON_DW7_8 (0<<28) +#define CPU_S3C2410X_BWSCON_DW7_16 (1<<28) +#define CPU_S3C2410X_BWSCON_DW7_32 (2<<28) +#define CPU_S3C2410X_BWSCON_WS7 (1<<30) +#define CPU_S3C2410X_BWSCON_ST7 (1<<31) + + +/* memory set (rom, ram) */ +#define CPU_S3C2410X_BANKCON0 CPU_S3C2410X_REG(0x0004) +#define CPU_S3C2410X_BANKCON1 CPU_S3C2410X_REG(0x0008) +#define CPU_S3C2410X_BANKCON2 CPU_S3C2410X_REG(0x000C) +#define CPU_S3C2410X_BANKCON3 CPU_S3C2410X_REG(0x0010) +#define CPU_S3C2410X_BANKCON4 CPU_S3C2410X_REG(0x0014) +#define CPU_S3C2410X_BANKCON5 CPU_S3C2410X_REG(0x0018) +#define CPU_S3C2410X_BANKCON6 CPU_S3C2410X_REG(0x001C) +#define CPU_S3C2410X_BANKCON7 CPU_S3C2410X_REG(0x0020) + +/* bank configuration registers */ + +#define CPU_S3C2410X_BANKCON_PMCnorm (0x00) +#define CPU_S3C2410X_BANKCON_PMC4 (0x01) +#define CPU_S3C2410X_BANKCON_PMC8 (0x02) +#define CPU_S3C2410X_BANKCON_PMC16 (0x03) + +/* bank configurations for banks 0..7, note banks + * 6 and 7 have differnt configurations depending on + * the memory type bits! */ + +#define CPU_S3C2410X_BANKCON_Tacp2 (0x0 << 2) +#define CPU_S3C2410X_BANKCON_Tacp3 (0x1 << 2) +#define CPU_S3C2410X_BANKCON_Tacp4 (0x2 << 2) +#define CPU_S3C2410X_BANKCON_Tacp6 (0x3 << 2) + +#define CPU_S3C2410X_BANKCON_Tcah0 (0x0 << 4) +#define CPU_S3C2410X_BANKCON_Tcah1 (0x1 << 4) +#define CPU_S3C2410X_BANKCON_Tcah2 (0x2 << 4) +#define CPU_S3C2410X_BANKCON_Tcah4 (0x3 << 4) + +#define CPU_S3C2410X_BANKCON_Tcoh0 (0x0 << 6) +#define CPU_S3C2410X_BANKCON_Tcoh1 (0x1 << 6) +#define CPU_S3C2410X_BANKCON_Tcoh2 (0x2 << 6) +#define CPU_S3C2410X_BANKCON_Tcoh4 (0x3 << 6) + +#define CPU_S3C2410X_BANKCON_Tacc1 (0x0 << 8) +#define CPU_S3C2410X_BANKCON_Tacc2 (0x1 << 8) +#define CPU_S3C2410X_BANKCON_Tacc3 (0x2 << 8) +#define CPU_S3C2410X_BANKCON_Tacc4 (0x3 << 8) +#define CPU_S3C2410X_BANKCON_Tacc6 (0x4 << 8) +#define CPU_S3C2410X_BANKCON_Tacc8 (0x5 << 8) +#define CPU_S3C2410X_BANKCON_Tacc10 (0x6 << 8) +#define CPU_S3C2410X_BANKCON_Tacc14 (0x7 << 8) + +#define CPU_S3C2410X_BANKCON_Tcos0 (0x0 << 11) +#define CPU_S3C2410X_BANKCON_Tcos1 (0x1 << 11) +#define CPU_S3C2410X_BANKCON_Tcos2 (0x2 << 11) +#define CPU_S3C2410X_BANKCON_Tcos4 (0x3 << 11) + +#define CPU_S3C2410X_BANKCON_Tacs0 (0x0 << 13) +#define CPU_S3C2410X_BANKCON_Tacs1 (0x1 << 13) +#define CPU_S3C2410X_BANKCON_Tacs2 (0x2 << 13) +#define CPU_S3C2410X_BANKCON_Tacs4 (0x3 << 13) + +#define CPU_S3C2410X_BANKCON_SRAM (0x0 << 15) +#define CPU_S3C2410X_BANKCON_SDRAM (0x3 << 15) + +/* next bits only for SDRAM in 6,7 */ +#define CPU_S3C2410X_BANKCON_Trdc2 (0x00 << 2) +#define CPU_S3C2410X_BANKCON_Trdc3 (0x01 << 2) +#define CPU_S3C2410X_BANKCON_Trdc4 (0x02 << 2) + +/* control column address select */ +#define CPU_S3C2410X_BANKCON_SCANb8 (0x00 << 0) +#define CPU_S3C2410X_BANKCON_SCANb9 (0x01 << 0) +#define CPU_S3C2410X_BANKCON_SCANb10 (0x02 << 0) + +#define CPU_S3C2410X_REFRESH CPU_S3C2410X_REG(0x0024) +#define CPU_S3C2410X_BANKSIZE CPU_S3C2410X_REG(0x0028) +#define CPU_S3C2410X_MRSRB6 CPU_S3C2410X_REG(0x002C) +#define CPU_S3C2410X_MRSRB7 CPU_S3C2410X_REG(0x0030) + +/* mode select register(s) */ + +#define CPU_S3C2410X_MRSRB_CL1 (0x00 << 4) +#define CPU_S3C2410X_MRSRB_CL2 (0x02 << 4) +#define CPU_S3C2410X_MRSRB_CL3 (0x03 << 4) + +/* bank size register */ +#define CPU_S3C2410X_BANKSIZE_128M (0x2 << 0) +#define CPU_S3C2410X_BANKSIZE_64M (0x1 << 0) +#define CPU_S3C2410X_BANKSIZE_32M (0x0 << 0) +#define CPU_S3C2410X_BANKSIZE_16M (0x7 << 0) +#define CPU_S3C2410X_BANKSIZE_8M (0x6 << 0) +#define CPU_S3C2410X_BANKSIZE_4M (0x5 << 0) +#define CPU_S3C2410X_BANKSIZE_2M (0x4 << 0) + +/* interrupt controller */ + +#define CPU_S3C2410X_SRCPND CPU_S3C2410X_REG(0x02000000) +#define CPU_S3C2410X_INTMOD CPU_S3C2410X_REG(0x02000004) +#define CPU_S3C2410X_INTMSK CPU_S3C2410X_REG(0x02000008) +#define CPU_S3C2410X_PRIORITY CPU_S3C2410X_REG(0x0200000C) +#define CPU_S3C2410X_INTPND CPU_S3C2410X_REG(0x02000010) +#define CPU_S3C2410X_INTOFFSET CPU_S3C2410X_REG(0x02000014) +#define CPU_S3C2410X_SUBSRCPND CPU_S3C2410X_REG(0x02000018) +#define CPU_S3C2410X_INTSUBMSK CPU_S3C2410X_REG(0x0200001C) + +/* serial ports */ + +#define CPU_S3C2410X_SERIAL_BASE(port) (0x50000000 + (port * 0x4000)) +/* Line control RW WORD */ +#define CPU_S3C2410X_SERIAL_ULCON 0x00 +/* General control RW WORD */ +#define CPU_S3C2410X_SERIAL_UCON 0x04 +/* Fifo control RW WORD */ +#define CPU_S3C2410X_SERIAL_UFCON 0x08 +/* Modem control RW WORD */ +#define CPU_S3C2410X_SERIAL_UMCON 0x0C +/* TX/RX Status RO WORD */ +#define CPU_S3C2410X_SERIAL_UTRSTAT 0x10 +/* Receive Error Status RO WORD */ +#define CPU_S3C2410X_SERIAL_UERSTAT 0x14 +/* FiFo Status RO WORD */ +#define CPU_S3C2410X_SERIAL_UFSTAT 0x18 +/* Modem Status RO WORD */ +#define CPU_S3C2410X_SERIAL_UMSTAT 0x1C +/* TX buffer WR BYTE */ +#define CPU_S3C2410X_SERIAL_UTXH 0x20 +/* RX buffer RO BYTE */ +#define CPU_S3C2410X_SERIAL_URXH 0x24 +/* BAUD Divisor RW WORD */ +#define CPU_S3C2410X_SERIAL_UBRDIV 0x28 + +/* LCD */ +#define CPU_S3C2410X_LCD_BASE 0x4D000000 + +/* IIC */ +#define CPU_S3C2410X_IIC_BASE 0x54000000 + +/* Watchdog */ +#define CPU_S3C2410X_WDOG_BASE 0x53000000 + +/* NAND */ +#define CPU_S3C2410X_NAND_BASE 0x4E000000 + +/* GPIO */ +#define CPU_S3C2410X_GPIO_BASE 0x56000000 + +/* Interrupt controller */ +#define CPU_S3C2410X_IRQ_BASE 0x4A000000 +/* IRQ request status RW WORD */ +#define CPU_S3C2410X_IRQ_SRCPND 0 +/* Interrupt mode control WR WORD */ +#define CPU_S3C2410X_IRQ_INTMOD 1 +/* Interrupt mask control RW WORD */ +#define CPU_S3C2410X_IRQ_INTMSK 2 +/* IRQ priority control WR WORD */ +#define CPU_S3C2410X_IRQ_PRIORITY 3 +/* Interrupt request status RW WORD */ +#define CPU_S3C2410X_IRQ_INTPND 4 +/* Interrupt request source offset RO WORD */ +#define CPU_S3C2410X_IRQ_OFFSET 5 +/* Sub-source pending RW WORD */ +#define CPU_S3C2410X_IRQ_SUBSRCPND 6 +/* Interrupt sub-mask RW WORD */ +#define CPU_S3C2410X_IRQ_INTSUBMSK 7 + +/* Timers */ + +#define CPU_S3C2410X_TIMERS_BASE 0x51000000 +/* Timer configuration 0 */ +#define CPU_S3C2410X_TIMERS_TCFG0 0 +/* Timer configuration 1 */ +#define CPU_S3C2410X_TIMERS_TCFG1 1 +/* Timer control */ +#define CPU_S3C2410X_TIMERS_TCON 2 +/* Timer count buffer 0 */ +#define CPU_S3C2410X_TIMERS_TCNTB0 3 +/* Timer compare buffer 0 */ +#define CPU_S3C2410X_TIMERS_TCMPB0 4 +/* Timer count observation 0 */ +#define CPU_S3C2410X_TIMERS_TCNTO0 5 +/* Timer count buffer 1 */ +#define CPU_S3C2410X_TIMERS_TCNTB1 6 +/* Timer compare buffer 1 */ +#define CPU_S3C2410X_TIMERS_TCMPB1 7 +/* Timer count observation 1 */ +#define CPU_S3C2410X_TIMERS_TCNTO1 8 +/* Timer count buffer 2 */ +#define CPU_S3C2410X_TIMERS_TCNTB2 9 +/* Timer compare buffer 2 */ +#define CPU_S3C2410X_TIMERS_TCMPB2 10 +/* Timer count observation 2 */ +#define CPU_S3C2410X_TIMERS_TCNTO2 11 +/* Timer count buffer 3 */ +#define CPU_S3C2410X_TIMERS_TCNTB3 12 +/* Timer compare buffer 3 */ +#define CPU_S3C2410X_TIMERS_TCMPB3 13 +/* Timer count observation 3 */ +#define CPU_S3C2410X_TIMERS_TCNTO3 14 +/* Timer count buffer 4 */ +#define CPU_S3C2410X_TIMERS_TCNTB4 15 +/* Timer count observation 4 */ +#define CPU_S3C2410X_TIMERS_TCNTO4 16 + +/* Real time clock */ +#define CPU_S3C2410X_RTC_BASE 0x57000040 +/* RTC Control RW Byte */ +#define CPU_S3C3410X_REG_RTCCON 0 +/* Tick time count RW Byte */ +#define CPU_S3C2410X_REG_TICNT 1 +/* RTC Alarm Control RW Byte */ +#define CPU_S3C2410X_REG_RTCALM 4 +/* Alarm second */ +#define CPU_S3C2410X_REG_ALMSEC 5 +/* Alarm minute */ +#define CPU_S3C2410X_REG_ALMMIN 6 +/* Alarm hour */ +#define CPU_S3C2410X_REG_ALMHOUR 7 +/* Alarm day */ +#define CPU_S3C2410X_REG_ALMDATE 8 +/* Alarm month */ +#define CPU_S3C2410X_REG_ALMMON 9 +/* Alarm year */ +#define CPU_S3C2410X_REG_ALMYEAR 10 +/* RTC Round Reset */ +#define CPU_S3C2410X_REG_RTCRST 11 +/* BCD Second */ +#define CPU_S3C2410X_REG_BCDSEC 12 +/* BCD Minute */ +#define CPU_S3C2410X_REG_BCDMIN 13 +/* BCD Hour */ +#define CPU_S3C2410X_REG_BCDHOUR 14 +/* BCD Day */ +#define CPU_S3C2410X_REG_BCDDATE 15 +/* BCD Day of week */ +#define CPU_S3C2410X_REG_BCDDAY 16 +/* BCD Month */ +#define CPU_S3C2410X_REG_BCDMON 17 +/* BCD Year */ +#define CPU_S3C2410X_REG_BCDYEAR 18 + +/* IRQ state */ +extern qemu_irq *s3c_irqs; + +/* Functions */ +CPUState *s3c2410x_init(int ram_size); + +void s3c2410x_memc_init(void); +qemu_irq *s3c2410x_irq_init(CPUState *env); +qemu_irq *s3c2410x_gpio_init(qemu_irq *real_irqs); +void s3c2410x_serial_init(int port, qemu_irq tx_irq, qemu_irq rx_irq, qemu_irq tx_level, qemu_irq rx_level); +void s3c2410x_clkcon_init(CPUState *ce); +void s3c2410x_timers_init(qemu_irq timer4_irq); +void s3c2410x_iic_init(qemu_irq iic_irq); +void s3c2410x_rtc_init(void); +void s3c2410x_lcd_init(void); + +int s3c2410_nand_load(const char *fname, + unsigned int id1, unsigned id2, + unsigned int oob); + +#ifdef DEBUG_S3C2410X_INLINE +#define S3C2410X_DBF_STREAM stdout +#else +#define S3C2410X_DBF_STREAM stderr +#endif +#if defined(DEBUG_S3C2410X) || 0 +#define S3C2410X_DBF(X...) fprintf(S3C2410X_DBF_STREAM,"S3C2410X:" X) +#else +#define S3C2410X_DBF(X...) if(0) (fprintf)(S3C2410X_DBF_STREAM, X) +#endif + +#endif /* S3C2410X_H */ === added file 'hw/s3c2410x_clkcon.c' --- hw/s3c2410x_clkcon.c 1970-01-01 00:00:00 +0000 +++ hw/s3c2410x_clkcon.c 2007-04-16 21:51:37 +0000 @@ -0,0 +1,79 @@ +/* hw/s3c2410x_clkcon.c + * + * Samsung S3C2410X emulation + * + * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#include "vl.h" +#include "s3c2410x.h" + +CPUState *env; + +static uint32_t s3c2410x_clkcon_reg[6]; +#define CR(X) s3c2410x_clkcon_reg[X] + +static void +s3c2410x_clkcon_write_f(void *opaque_ignored, target_phys_addr_t addr_, uint32_t value) +{ + int addr = (addr_ & 0x1F) >> 2; + int idle_rising_edge = 0; + if (addr < 0 || addr > 5) addr = 5; + + S3C2410X_DBF("Write CLKCON[%02x] = %08x\n", addr_&0xFF, value); + + if( addr == CPU_S3C2410X_REG_CLKCON ) { + if( !(s3c2410x_clkcon_reg[addr] & CPU_S3C2410X_REG_CLKCON_IDLE) && + (value & CPU_S3C2410X_REG_CLKCON_IDLE) ) idle_rising_edge = 1; + } + s3c2410x_clkcon_reg[addr] = value; + if( idle_rising_edge ) { + S3C2410X_DBF("CLKCON: Idling CPU\n"); + env->exception_index = EXCP_HLT; + env->halted = 1; + cpu_loop_exit(); + } +} + +static uint32_t +s3c2410x_clkcon_read_f(void *opaque_ignored, target_phys_addr_t addr_) +{ + int addr = (addr_ & 0x1F) >> 2; + if (addr < 0 || addr > 5) addr = 5; + S3C2410X_DBF("Read CLKCON[%d]\n", addr); + return s3c2410x_clkcon_reg[addr]; +} + +static CPUReadMemoryFunc *s3c2410x_clkcon_read[] = { + &s3c2410x_clkcon_read_f, + &s3c2410x_clkcon_read_f, + &s3c2410x_clkcon_read_f, +}; + +static CPUWriteMemoryFunc *s3c2410x_clkcon_write[] = { + &s3c2410x_clkcon_write_f, + &s3c2410x_clkcon_write_f, + &s3c2410x_clkcon_write_f, +}; + + +void +s3c2410x_clkcon_init(CPUState *ce) +{ + int tag; + + tag = cpu_register_io_memory(0, s3c2410x_clkcon_read, s3c2410x_clkcon_write, 0); + cpu_register_physical_memory(CPU_S3C2410X_CLKCON, 6*4, tag); + + CR(0) = 0x00FFFFFF; + CR(1) = 0x0005C080; + CR(2) = 0x00028080; + CR(3) = 0x0007FFF0; + CR(4) = 0x00000004; + CR(5) = 0x00000000; + + env = ce; +} === added file 'hw/s3c2410x_gpio.c' --- hw/s3c2410x_gpio.c 1970-01-01 00:00:00 +0000 +++ hw/s3c2410x_gpio.c 2007-04-16 22:15:41 +0000 @@ -0,0 +1,161 @@ +/* hw/s3c2410x_gpio.c + * + * Samsung S3C2410X emulation + * + * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#include "vl.h" +#include "s3c2410x.h" +#include "hw/irq.h" + +static uint32_t s3c2410x_gpio_reg[47]; + +#define EINT_MASK (0xA4) +#define EINT_PEND (0xA8) +#define GPR(P) s3c2410x_gpio_reg[P>>2] + +static void +s3c2410x_gpio_propogate_eint(qemu_irq *real_irqs) +{ + uint32_t ints, i; + S3C2410X_DBF("EINT: Propogating to IRQ\n"); + ints = GPR(EINT_PEND) & ~GPR(EINT_MASK); + /* EINT0 - EINT3 are INT0 - INT3 */ + for(i=0; i < 4; ++i) + qemu_set_irq(real_irqs[i], (ints&(1<> (bit*2)) & 0x3) == 0x01) + mask |= 1 << bit; + } + + S3C2410X_DBF("Con %08x => mask %08x\n", con, mask); + return mask; +} + +static void +s3c2410x_gpio_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value) +{ + qemu_irq *real_irqs = (qemu_irq *)opaque; + int addr = (addr_ >> 2) & 0x3f; + if (addr < 0 || addr > 47) addr = 47; + + if (addr == (EINT_MASK>>2)) value &= ~0xf; /* cannot mask EINT0-EINT3 */ + S3C2410X_DBF("Write GPIO[%02x] = %08x\n",addr<<2, value); + if (addr == (EINT_PEND>>2)) + s3c2410x_gpio_reg[addr] &= ~value; + else { + if (addr < (0x80/4) && (addr_ & 0xf) == 0x04) { + uint32_t mask = gpio_con_to_mask(s3c2410x_gpio_reg[addr-1]); + + value &= mask; + + s3c2410x_gpio_reg[addr] &= ~mask; + s3c2410x_gpio_reg[addr] |= value; + } else + s3c2410x_gpio_reg[addr] = value; + } + + if ((addr == (EINT_MASK)>>2) || (addr == (EINT_PEND)>>2)) { + /* A write to the EINT regs leads us to determine the interrupts to propagate */ + s3c2410x_gpio_propogate_eint(real_irqs); + } +} + +static uint32_t +s3c2410x_gpio_read_f(void *opaque_ignored, target_phys_addr_t addr_) +{ + int addr = (addr_ >> 2) & 0x3f; + if (addr_ == 0x560000b0) return CPU_S3C2410X_IDENT_S3C2410A; + if (addr < 0 || addr > 47) addr = 47; + /* If IIC pins are wired to GPE, and GPE is on input mode, pretend the IIC is pulled high */ + if (addr == 0x44>>2) { + /* GPEDAT read. */ + uint32_t ret = s3c2410x_gpio_reg[addr]; + if ((s3c2410x_gpio_reg[15] & 3<<28) == 0) ret |= 1 << 14; + if ((s3c2410x_gpio_reg[15] & 3<<30) == 0) ret |= 1 << 15; + S3C2410X_DBF("GPIO read of GPE, returning 0x%08x\n", ret); + return ret; + } + S3C2410X_DBF("Read GPIO[%02x] => 0x%08x\n",addr<<2, s3c2410x_gpio_reg[addr]); + return s3c2410x_gpio_reg[addr]; +} + + +static CPUReadMemoryFunc *s3c2410x_gpio_read[] = { + &s3c2410x_gpio_read_f, + &s3c2410x_gpio_read_f, + &s3c2410x_gpio_read_f, +}; + +static CPUWriteMemoryFunc *s3c2410x_gpio_write[] = { + &s3c2410x_gpio_write_f, + &s3c2410x_gpio_write_f, + &s3c2410x_gpio_write_f, +}; + +static void +s3c2410x_gpio_irq_handler(void *opaque, int n, int level) +{ + qemu_irq *real_irqs = (qemu_irq *)opaque; + if (level) + GPR(EINT_PEND) |= (1<> 2] = 0xff; + break; + + default: + s3c2410x_iic_reg[addr >> 2] = value; + } +} + +static const char * +decode_iicstat_mode(uint32_t mode) +{ + switch (mode & S3C2410_IICSTAT_MODEMASK) { + case S3C2410_IICSTAT_MASTER_RX: + return "MasterRX"; + case S3C2410_IICSTAT_MASTER_TX: + return "MasterTX"; + case S3C2410_IICSTAT_SLAVE_RX: + return "SlaveRX"; + case S3C2410_IICSTAT_SLAVE_TX: + return "SlaveTX"; + } + + return ""; +} + +static uint32_t +s3c2410x_iic_read_f(void *opaque_ignored, target_phys_addr_t addr_) +{ + int addr = (addr_ & 0xf); + uint32_t val; + + if (addr < 0 || addr > 12) addr = 12; + + val = s3c2410x_iic_reg[addr >> 2]; + + S3C2410X_DBF("Read IIC[%02x] => %02x\n", addr, val); + + switch (addr) { + case S3C2410_IICCON: + S3C2410X_DBF("Read: IICCON: AckEn %d, TxDiv %d, IrqEn %d, IrqPend %d, Scale %d\n", + (val & S3C2410_IICCON_ACKEN) ? 1 : 0, + (val & S3C2410_IICCON_TXDIV_512) ? 512 : 16, + (val & S3C2410_IICCON_IRQEN) ? 1 : 0, + (val & S3C2410_IICCON_IRQPEND) ? 1 : 0, + (val & S3C2410_IICCON_SCALEMASK)); + break; + + case S3C2410_IICSTAT: + S3C2410X_DBF("Read: IICSTAT: Mode %s, BusBusy %d, TxRxEn %d, Arb %d, Slave %d, Addr0 %d, LBit %d\n", + decode_iicstat_mode(val), + (val & S3C2410_IICSTAT_BUSBUSY) ? 1 : 0, + (val & S3C2410_IICSTAT_TXRXEN) ? 1 : 0, + (val & S3C2410_IICSTAT_ARBITR) ? 1 : 0, + (val & S3C2410_IICSTAT_ASSLAVE) ? 1 : 0, + (val & S3C2410_IICSTAT_ADDR0) ? 1 : 0, + (val & S3C2410_IICSTAT_LASTBIT)); + } + + return val; +} + + +static CPUReadMemoryFunc *s3c2410x_iic_read[] = { + &s3c2410x_iic_read_f, + &s3c2410x_iic_read_f, + &s3c2410x_iic_read_f, +}; + +static CPUWriteMemoryFunc *s3c2410x_iic_write[] = { + &s3c2410x_iic_write_f, + &s3c2410x_iic_write_f, + &s3c2410x_iic_write_f, +}; + + +void +s3c2410x_iic_init(qemu_irq iic_irq) +{ + /* Samsung S3C2410X IIC registration. */ + int tag = cpu_register_io_memory(0, s3c2410x_iic_read, s3c2410x_iic_write, iic_irq); + cpu_register_physical_memory(CPU_S3C2410X_IIC_BASE, 4*4, tag); + s3c2410x_iic_reg[0] = 0; + s3c2410x_iic_reg[1] = 0; + s3c2410x_iic_reg[2] = 0; + s3c2410x_iic_reg[3] = 0; + +} === added file 'hw/s3c2410x_irq.c' --- hw/s3c2410x_irq.c 1970-01-01 00:00:00 +0000 +++ hw/s3c2410x_irq.c 2007-04-17 09:15:29 +0000 @@ -0,0 +1,183 @@ +/* hw/s3c2410x_irq.c + * + * Samsung S3C2410X emulation + * + * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#include "vl.h" +#include "s3c2410x.h" + +static uint32_t s3c2410x_irq_main_level, s3c2410x_irq_subsrc_level; +static uint32_t s3c2410x_irq_reg[8]; +#define IR(X) s3c2410x_irq_reg[X] + +static void +__s3c2410x_percolate_interrupt(CPUState *cpu_env) +{ + /* Take the status of the srcpnd register, percolate it through, raise to CPU if necessary */ + uint32_t ints = (s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] & + ~s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTMSK]); + int fsb = ffs(ints); + + /* TODO: Priority encoder could go here */ + if (ints & s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTMOD]) { + /* Detected a FIQ */ + S3C2410X_DBF("IRQ: Setting FIQ on CPU\n"); + cpu_interrupt(cpu_env, CPU_INTERRUPT_FIQ); + return; + } else { + /* No FIQ here today */ + cpu_reset_interrupt(cpu_env, CPU_INTERRUPT_FIQ); + } + /* No FIQ, do we have an IRQ */ + if (fsb) { + if ((s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTPND] == 0) || + (s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTPND] > 1<<(fsb-1))) { + /* Current INTPND is lower priority than fsb of ints (or empty) */ + s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTPND] = 1<<(fsb-1); + s3c2410x_irq_reg[CPU_S3C2410X_IRQ_OFFSET] = fsb-1; + } + } else { + /* No FSB, thus no IRQ, thus nothing to see yet */ + } + + if (s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTPND] != 0) { + S3C2410X_DBF("IRQ: Setting IRQ on CPU\n"); + cpu_interrupt(cpu_env, CPU_INTERRUPT_HARD); + } else { + cpu_reset_interrupt(cpu_env, CPU_INTERRUPT_HARD); + } +} + +static void +s3c2410x_percolate_subsrc_interrupt(CPUState *cpu_env) +{ + uint32_t ints; + + s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= s3c2410x_irq_main_level; + s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] |= s3c2410x_irq_subsrc_level; + + ints = (s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] & + ~s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTSUBMSK]); + + /* If UART0 has asserted, raise that */ + S3C2410X_DBF("SUBSRCPND 0x%08x\n", s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND]); + S3C2410X_DBF("INTSUBMSK 0x%08x\n", s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTSUBMSK]); + S3C2410X_DBF(" => Pending Subsource interrupts: %08x\n", ints); + if( ints & 0x7 ) { + S3C2410X_DBF("IRQ: Percolating UART0 subsource\n"); + s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<28); + } + /* Ditto UART1 */ + if( ints & 0x7<<3 ) s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<23); + /* Ditto UART2 */ + if( ints & 0x7<<6 ) s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<15); + /* And percolate it through */ + __s3c2410x_percolate_interrupt(cpu_env); +} + +static void +s3c2410x_irq_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value) +{ + CPUState *env = (CPUState *)opaque; + int addr = (addr_ >> 2) & 7; + S3C2410X_DBF("Write IRQ[%02x] = %08x\n",addr<<2, value); + if (addr == CPU_S3C2410X_IRQ_SRCPND || + addr == CPU_S3C2410X_IRQ_INTPND || + addr == CPU_S3C2410X_IRQ_SUBSRCPND) { + s3c2410x_irq_reg[addr] &= ~value; + } else { + s3c2410x_irq_reg[addr] = value; + } + + /* Start at the subsrc irqs and percolate from there */ + s3c2410x_percolate_subsrc_interrupt(env); +} + +static uint32_t +s3c2410x_irq_read_f(void *opaque_ignored, target_phys_addr_t addr_) +{ + int addr = (addr_ >> 2) & 0x7; + S3C2410X_DBF("Read IRQ[%02x] => 0x%08x\n",addr<<2, s3c2410x_irq_reg[addr]); + return s3c2410x_irq_reg[addr]; +} + + +static CPUReadMemoryFunc *s3c2410x_irq_read[] = { + &s3c2410x_irq_read_f, + &s3c2410x_irq_read_f, + &s3c2410x_irq_read_f, +}; + +static CPUWriteMemoryFunc *s3c2410x_irq_write[] = { + &s3c2410x_irq_write_f, + &s3c2410x_irq_write_f, + &s3c2410x_irq_write_f, +}; + +static void +s3c2410x_irq_set_interrupt_level(CPUState *env, int irq_num, int level, int set_level) +{ + S3C2410X_DBF("IRQ: Set level for %d to %d\n", irq_num, level); + if( level ) { + if (set_level) s3c2410x_irq_main_level |= 1<> 2; + if (addr < 0 || addr > 12) addr = 12; + S3C2410X_DBF("Write MEMC[%d] = %08x\n", addr, value); + s3c2410x_memc_reg[addr] = value; +} + +static uint32_t +s3c2410x_memc_read_f(void *opaque_ignored, target_phys_addr_t addr_) +{ + int addr = (addr_ & 0x3f) >> 2; + if (addr < 0 || addr > 12) addr = 12; + S3C2410X_DBF("Read MEMC[%d]\n", addr); + return s3c2410x_memc_reg[addr]; +} + +static CPUReadMemoryFunc *s3c2410x_memc_read[] = { + &s3c2410x_memc_read_f, + &s3c2410x_memc_read_f, + &s3c2410x_memc_read_f, +}; + +static CPUWriteMemoryFunc *s3c2410x_memc_write[] = { + &s3c2410x_memc_write_f, + &s3c2410x_memc_write_f, + &s3c2410x_memc_write_f, +}; + + +void +s3c2410x_memc_init(void) +{ + /* Memory controller is all about SDRAM control, thus we just drop + * some RAM in there and assume life will be ok. + * It is 13 registers, each 4 bytes. + * + * However because of the bizarro mechanisms in qemu for RAM, we do + * it as MMIO which means a tag and then a memory range. + */ + int tag; + tag = cpu_register_io_memory(0, s3c2410x_memc_read, s3c2410x_memc_write, 0); + cpu_register_physical_memory(CPU_S3C2410X_BWSCON, 13*4, tag); + + for(tag = 0; tag < 13; tag++) s3c2410x_memc_reg[tag] = 0; + +} === added file 'hw/s3c2410x_rtc.c' --- hw/s3c2410x_rtc.c 1970-01-01 00:00:00 +0000 +++ hw/s3c2410x_rtc.c 2007-04-16 21:51:37 +0000 @@ -0,0 +1,85 @@ +/* hw/s3c2410x_rtc.c + * + * Samsung S3C2410X emulation + * + * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#include "vl.h" +#include "s3c2410x.h" + +static uint8_t s3c2410x_rtc_reg[19]; + +static inline int to_bcd(int a) +{ + return ((a/10)<<4) | (a%10); +} + +static void +s3c2410x_rtc_write_f(void *opaque_ignored, target_phys_addr_t addr_, uint32_t value) +{ + int addr = (addr_ - CPU_S3C2410X_RTC_BASE) >> 2; + if (addr < 0 || addr > 18) addr = 18; + S3C2410X_DBF("Write RTC[%d] = %08x\n", addr, value); + s3c2410x_rtc_reg[addr] = value; +} + +static uint32_t +s3c2410x_rtc_read_f(void *opaque_ignored, target_phys_addr_t addr_) +{ + int addr = (addr_ - CPU_S3C2410X_RTC_BASE) >> 2; + struct tm *tm; + time_t ti; + if (addr < 0 || addr > 18) addr = 18; + S3C2410X_DBF("Read RTC[%d]\n", addr); + if( addr >= CPU_S3C2410X_REG_BCDSEC && + addr <= CPU_S3C2410X_REG_BCDYEAR ) { + time(&ti); + if( rtc_utc ) + tm = gmtime(&ti); + else + tm = localtime(&ti); + switch(addr) { + case CPU_S3C2410X_REG_BCDSEC: + return to_bcd(tm->tm_sec); + case CPU_S3C2410X_REG_BCDMIN: + return to_bcd(tm->tm_min); + case CPU_S3C2410X_REG_BCDHOUR: + return to_bcd(tm->tm_hour); + case CPU_S3C2410X_REG_BCDDATE: + return to_bcd(tm->tm_mday); + case CPU_S3C2410X_REG_BCDDAY: + return to_bcd(tm->tm_wday+1); + case CPU_S3C2410X_REG_BCDMON: + return to_bcd(tm->tm_mon+1); + case CPU_S3C2410X_REG_BCDYEAR: + return to_bcd(tm->tm_year-100); + } + } + return s3c2410x_rtc_reg[addr]; +} + +static CPUReadMemoryFunc *s3c2410x_rtc_read[] = { + &s3c2410x_rtc_read_f, + &s3c2410x_rtc_read_f, + &s3c2410x_rtc_read_f, +}; + +static CPUWriteMemoryFunc *s3c2410x_rtc_write[] = { + &s3c2410x_rtc_write_f, + &s3c2410x_rtc_write_f, + &s3c2410x_rtc_write_f, +}; + + +void +s3c2410x_rtc_init(void) +{ + int tag; + tag = cpu_register_io_memory(0, s3c2410x_rtc_read, s3c2410x_rtc_write, 0); + cpu_register_physical_memory(CPU_S3C2410X_RTC_BASE, 19*4, tag); + for(tag=0; tag < 18; ++tag) s3c2410x_rtc_reg[tag] = 0; +} === added file 'hw/s3c2410x_serial.c' --- hw/s3c2410x_serial.c 1970-01-01 00:00:00 +0000 +++ hw/s3c2410x_serial.c 2007-04-17 09:12:47 +0000 @@ -0,0 +1,220 @@ +/* hw/s3c2410x_serial.c + * + * Samsung S3C2410X Serial block + * + * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#define S3C2410X_DEBUG + +#include "vl.h" +#include "s3c2410x.h" + +typedef struct { + uint32_t ulcon, ucon, ufcon, umcon, ubrdiv; + unsigned char rx_byte; + /* Byte is available to be read */ + unsigned int rx_available : 1; + CharDriverState *chr; + int port; + qemu_irq tx_irq; + qemu_irq rx_irq; + qemu_irq tx_level; + qemu_irq rx_level; +} s3c2410x_serial_dev; + +static void +s3c2410x_serial_write_f(void *opaque, target_phys_addr_t addr, uint32_t value) +{ + s3c2410x_serial_dev *s = opaque; + int reg = addr & 0x3f; + if (reg != CPU_S3C2410X_SERIAL_UTXH) + S3C2410X_DBF("Serial[%d] Write of %08x to %08x (reg %d)\n", s->port, value, addr, reg); + switch(reg) { + case CPU_S3C2410X_SERIAL_ULCON: + s->ulcon = value; + break; + case CPU_S3C2410X_SERIAL_UCON: + s->ucon = value; + if( s->ucon & 1<<9 ) { + S3C2410X_DBF("Serial[%d] setting TX level interrupt due to ucon write\n", s->port); + qemu_set_irq(s->tx_level, 1); + } else { + S3C2410X_DBF("Serial[%d] clearing TX level interrupt due to ucon write\n", s->port); + qemu_set_irq(s->tx_level, 0); + } + if( !(s->ucon & 1<<8) ) { + S3C2410X_DBF("Serial[%d] clearing RX level interrupt (if any) due to ucon write\n", s->port); + qemu_set_irq(s->rx_level, 0); + } + break; + case CPU_S3C2410X_SERIAL_UFCON: + s->ufcon = value; + break; + case CPU_S3C2410X_SERIAL_UMCON: + s->umcon = value; + break; + case CPU_S3C2410X_SERIAL_UTRSTAT: + break; + case CPU_S3C2410X_SERIAL_UERSTAT: + break; + case CPU_S3C2410X_SERIAL_UFSTAT: + break; + case CPU_S3C2410X_SERIAL_UMSTAT: + break; + case CPU_S3C2410X_SERIAL_UTXH: { + unsigned char ch = value & 0xff; + if (s->chr && ((s->ucon & 1<<5)==0)) + qemu_chr_write(s->chr, &ch, 1); + else { + s->rx_byte = ch; + s->rx_available = 1; + if( s->ucon & 1<<8 ) { + S3C2410X_DBF("Serial[%d] Setting RX level interrupt due to loopback write\n", s->port); + qemu_set_irq(s->rx_level, 1); + } else { + S3C2410X_DBF("Serial[%d] Pulsing RX interrupt due to loopback write\n", s->port); + qemu_set_irq(s->rx_irq, 1); + } + } + if( s->ucon & 1<<9 ) { + S3C2410X_DBF("Serial[%d] Setting TX level interrupt due to byte write\n", s->port); + qemu_set_irq(s->tx_level, 1); + } else { + S3C2410X_DBF("Serial[%d] Pulsing TX interrupt due to byte write\n", s->port); + qemu_set_irq(s->tx_irq, 1); + } + break; + } + case CPU_S3C2410X_SERIAL_URXH: + break; + case CPU_S3C2410X_SERIAL_UBRDIV: + s->ubrdiv = value; + break; + default: + break; + }; +} + +static uint32_t +s3c2410x_serial_read_f(void *opaque, target_phys_addr_t addr) +{ + s3c2410x_serial_dev *s = opaque; + int reg = addr & 0x3f; + if (reg != CPU_S3C2410X_SERIAL_URXH && + reg != CPU_S3C2410X_SERIAL_UFCON && + reg != CPU_S3C2410X_SERIAL_UFSTAT) + S3C2410X_DBF("Serial[%d] Read of %08x (reg %d)\n", s->port, addr, reg); + switch(reg) { + case CPU_S3C2410X_SERIAL_ULCON: + return s->ulcon; + case CPU_S3C2410X_SERIAL_UCON: + return s->ucon; + case CPU_S3C2410X_SERIAL_UFCON: + return s->ufcon & ~0x8; /* bit 3 is reserved, must be zero */ + case CPU_S3C2410X_SERIAL_UMCON: + return s->umcon & 0x11; /* Rest are reserved, must be zero */ + case CPU_S3C2410X_SERIAL_UTRSTAT: + return 6 | s->rx_available; /* TX always clear, RX when available */ + case CPU_S3C2410X_SERIAL_UERSTAT: + return 0; /* Later, break detect comes in here */ + case CPU_S3C2410X_SERIAL_UFSTAT: + return s->rx_available; /* TXFIFO, always empty, RXFIFO 0 or 1 bytes */ + case CPU_S3C2410X_SERIAL_UMSTAT: + return 0; + case CPU_S3C2410X_SERIAL_UTXH: + return 0; + case CPU_S3C2410X_SERIAL_URXH: + s->rx_available = 0; + if( s->ucon & 1<<8 ) { + S3C2410X_DBF("Serial[%d] clearing RX level interrupt due to byte read\n", s->port); + qemu_set_irq(s->rx_level, 0); + } + return s->rx_byte; + case CPU_S3C2410X_SERIAL_UBRDIV: + return s->ubrdiv; + default: + return 0; + }; +} + +static CPUReadMemoryFunc *s3c2410x_serial_read[] = { + &s3c2410x_serial_read_f, + &s3c2410x_serial_read_f, + &s3c2410x_serial_read_f, +}; + +static CPUWriteMemoryFunc *s3c2410x_serial_write[] = { + &s3c2410x_serial_write_f, + &s3c2410x_serial_write_f, + &s3c2410x_serial_write_f, +}; + + +static void s3c2410x_serial_event(void *opaque, int event) +{ + /* Disabled currently. * + s3c2410x_serial_dev *s = opaque; + if (event == CHR_EVENT_BREAK) + serial_receive_break(s); + /* */ +} + +static int +s3c2410x_serial_can_receive(void *opaque) +{ + s3c2410x_serial_dev *s = opaque; + /* If there's no byte to be read, we can receive a new one */ + return !s->rx_available; +} + +static void +s3c2410x_serial_receive(void *opaque, const uint8_t *buf, int size) +{ + s3c2410x_serial_dev *s = opaque; + s->rx_byte = buf[0]; + s->rx_available = 1; + if( s->ucon & 1<<8 ) { + S3C2410X_DBF("Serial[%d] setting RX level interrupt due to incoming char %02x\n", s->port, buf[0]); + qemu_set_irq(s->rx_level, 1); + } else { + S3C2410X_DBF("Serial[%d] pulse receive interrupt %d for %02x\n", s->port, 1<<(s->port*3), buf[0]); + qemu_set_irq(s->rx_irq, 1); /* Is there something we can do here to ensure it's just a pulse ? */ + } +} + +void +s3c2410x_serial_init(int port, qemu_irq tx_irq, qemu_irq rx_irq, qemu_irq tx_level, qemu_irq rx_level) +{ + /* Initialise a serial port at the given port address */ + s3c2410x_serial_dev *s; + int serial_io_magic; + + s = qemu_mallocz(sizeof(s3c2410x_serial_dev)); + if (!s) return; + s->chr = serial_hds[port]; + s->ulcon = 0; + s->ucon = 0; + s->ufcon = 0; + s->umcon = 0; + s->ubrdiv = 0; + s->port = port; + s->rx_available = 0; + s->tx_irq = tx_irq; + s->rx_irq = rx_irq; + s->tx_level = tx_level; + s->rx_level = rx_level; + /* Prepare our MMIO tag */ + serial_io_magic = cpu_register_io_memory(0, s3c2410x_serial_read, s3c2410x_serial_write, s); + /* Register the region with the tag */ + cpu_register_physical_memory(CPU_S3C2410X_SERIAL_BASE(port), 44, serial_io_magic); + if (s->chr) { + /* Add ourselves to the character device's IO handlers, if the port is there */ + + qemu_chr_add_handlers(s->chr, s3c2410x_serial_can_receive, + s3c2410x_serial_receive, s3c2410x_serial_event, s); + } +} === added file 'hw/s3c2410x_timers.c' --- hw/s3c2410x_timers.c 1970-01-01 00:00:00 +0000 +++ hw/s3c2410x_timers.c 2007-04-16 22:14:39 +0000 @@ -0,0 +1,117 @@ +/* hw/s3c2410x_timers.c + * + * Samsung S3C2410X emulation + * + * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2 + */ + +#include "vl.h" +#include "s3c2410x.h" + +static uint32_t s3c2410x_timers_reg[17]; +QEMUTimer *timer4; +static uint32_t timer4_reload_value; +static int64_t timer4_last_ticked; + +/* + +QEMU_TIMER_BASE is ticks per second for the qemu clocks +TCLK1 (assumed input for timer4) is 12 MHz +Thus, period in ticks of timer4 is: + +(timer4_period * QEMU_TIMER_BASE) / 12000000 + + */ + +#define MEGA 1000000 +#define HERTZ 1 + +#define TCLK1 (12 * MEGA * HERTZ) + +static void +s3c2410x_schedule_timer4(void) +{ + s3c2410x_timers_reg[CPU_S3C2410X_TIMERS_TCNTB4] = timer4_reload_value; + timer4_last_ticked = qemu_get_clock(vm_clock); + qemu_mod_timer(timer4, timer4_last_ticked + ((timer4_reload_value*ticks_per_sec)/TCLK1)); +} + +static void +s3c2410x_timer4_tick(void *opaque) +{ + qemu_irq timer4_irq = (qemu_irq)opaque; + S3C2410X_DBF("Timer4 goes TICK!\n"); + qemu_set_irq(timer4_irq, 1); + if (s3c2410x_timers_reg[CPU_S3C2410X_TIMERS_TCON] && (1<<22)) { + s3c2410x_schedule_timer4(); + } +} + +static void +s3c2410x_timers_write_f(void *opaque_ignored, target_phys_addr_t addr_, uint32_t value) +{ + int addr = (addr_ >> 2) & 0x1f; + S3C2410X_DBF("Write TIMERS[%02x] = %08x\n",addr<<2, value); + s3c2410x_timers_reg[addr] = value; + if( addr == CPU_S3C2410X_TIMERS_TCON ) { + /* If Timer4's manual update is set, copy in the reload value */ + if( value & (1 << 21) ) + timer4_reload_value = s3c2410x_timers_reg[CPU_S3C2410X_TIMERS_TCNTB4]; + /* If Timer4's manual update is unset, and the timer is running, start it */ + if( !(value & (1 << 21)) && value & (1 << 20)) { + s3c2410x_schedule_timer4(); + } + } +} + +static uint32_t +s3c2410x_timers_read_f(void *opaque_ignored, target_phys_addr_t addr_) +{ + int addr = (addr_ >> 2) & 0x1f; + S3C2410X_DBF("Read TIMERS[%02x]\n",addr<<2); + if( addr == CPU_S3C2410X_TIMERS_TCNTO4 ) { + return timer4_reload_value - (((qemu_get_clock(vm_clock)-timer4_last_ticked)*TCLK1)/ticks_per_sec); + } + return s3c2410x_timers_reg[addr]; +} + + +static CPUReadMemoryFunc *s3c2410x_timers_read[] = { + &s3c2410x_timers_read_f, + &s3c2410x_timers_read_f, + &s3c2410x_timers_read_f, +}; + +static CPUWriteMemoryFunc *s3c2410x_timers_write[] = { + &s3c2410x_timers_write_f, + &s3c2410x_timers_write_f, + &s3c2410x_timers_write_f, +}; + +void +s3c2410x_timers_init(qemu_irq timer4_irq) +{ + /* Samsung S3C2410X TIMERS registration. + * + * Specifically the PWM timer4. + */ + int tag = cpu_register_io_memory(0, s3c2410x_timers_read, s3c2410x_timers_write, timer4_irq); + cpu_register_physical_memory(CPU_S3C2410X_TIMERS_BASE, 17*4, tag); + timer4 = qemu_new_timer(vm_clock, s3c2410x_timer4_tick, timer4_irq); +} + +/* + +Need to set up a timer against the vm_clock for 12MHz. (Virtual TCLK1) + +Then we only provide timer4 anyway, and it will always be configured to use TCLK1 + +We need to take on board the count/compare values, and when the timer is reloaded, we set +a qemu_timer_mod to call us back at the appropriate VM tick. + +At that point we probably raise an interrupt. + +*/ === added directory 'hw/s3c24xx' === added file 'hw/s3c24xx/regs-iic.h' --- hw/s3c24xx/regs-iic.h 1970-01-01 00:00:00 +0000 +++ hw/s3c24xx/regs-iic.h 2007-04-16 21:51:37 +0000 @@ -0,0 +1,56 @@ +/* linux/include/asm-arm/arch-s3c2410/regs-iic.h + * + * Copyright (c) 2004 Simtec Electronics + * http://www.simtec.co.uk/products/SWLINUX/ + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * S3C2410 I2C Controller +*/ + +#ifndef __ASM_ARCH_REGS_IIC_H +#define __ASM_ARCH_REGS_IIC_H __FILE__ + +/* see s3c2410x user guide, v1.1, section 9 (p447) for more info */ + +#define S3C2410_IICREG(x) (x) + +#define S3C2410_IICCON S3C2410_IICREG(0x00) +#define S3C2410_IICSTAT S3C2410_IICREG(0x04) +#define S3C2410_IICADD S3C2410_IICREG(0x08) +#define S3C2410_IICDS S3C2410_IICREG(0x0C) +#define S3C2440_IICLC S3C2410_IICREG(0x10) + +#define S3C2410_IICCON_ACKEN (1<<7) +#define S3C2410_IICCON_TXDIV_16 (0<<6) +#define S3C2410_IICCON_TXDIV_512 (1<<6) +#define S3C2410_IICCON_IRQEN (1<<5) +#define S3C2410_IICCON_IRQPEND (1<<4) +#define S3C2410_IICCON_SCALE(x) ((x)&15) +#define S3C2410_IICCON_SCALEMASK (0xf) + +#define S3C2410_IICSTAT_MASTER_RX (2<<6) +#define S3C2410_IICSTAT_MASTER_TX (3<<6) +#define S3C2410_IICSTAT_SLAVE_RX (0<<6) +#define S3C2410_IICSTAT_SLAVE_TX (1<<6) +#define S3C2410_IICSTAT_MODEMASK (3<<6) + +#define S3C2410_IICSTAT_START (1<<5) +#define S3C2410_IICSTAT_BUSBUSY (1<<5) +#define S3C2410_IICSTAT_TXRXEN (1<<4) +#define S3C2410_IICSTAT_ARBITR (1<<3) +#define S3C2410_IICSTAT_ASSLAVE (1<<2) +#define S3C2410_IICSTAT_ADDR0 (1<<1) +#define S3C2410_IICSTAT_LASTBIT (1<<0) + +#define S3C2410_IICLC_SDA_DELAY0 (0 << 0) +#define S3C2410_IICLC_SDA_DELAY5 (1 << 0) +#define S3C2410_IICLC_SDA_DELAY10 (2 << 0) +#define S3C2410_IICLC_SDA_DELAY15 (3 << 0) +#define S3C2410_IICLC_SDA_DELAY_MASK (3 << 0) + +#define S3C2410_IICLC_FILTER_ON (1<<2) + +#endif /* __ASM_ARCH_REGS_IIC_H */ === added file 'hw/simtecbast.c' --- hw/simtecbast.c 1970-01-01 00:00:00 +0000 +++ hw/simtecbast.c 2007-04-16 21:51:37 +0000 @@ -0,0 +1,117 @@ +/* hw/simtecbast.c + * + * Simple system emulation for the Simtec Electronics BAST + * + * Copyright 2006 Daniel Silverstone and Vincent Sanders + * + * This file is under the terms of the GNU General Public + * License Version 2. + */ + +#include "vl.h" +#include "s3c2410x.h" +#include "assert.h" + +#define BIOS_FILENAME "s3c2410x-able.bin" + +/* Bytes in a Kilobyte */ +#define KILO 1024 +/* Bytes in a megabyte */ +#define MEGA 1024 * KILO +/* Bytes */ +#define BYTE 1 +/* Bits in a byte */ +#define BIT 8 + +/* Useful defines */ +#define SIMTEC_BAST_NOR_BASE CPU_S3C2410X_CS0 +#define SIMTEC_BAST_NOR_SIZE 16 * MEGA / BIT +#define SIMTEC_BAST_BOARD_ID 331 + +#define BAST_IDE_PRI_SLOW (CPU_S3C2410X_CS3 | 0x2000000) +#define BAST_IDE_SEC_SLOW (CPU_S3C2410X_CS3 | 0x3000000) +#define BAST_IDE_PRI_FAST (CPU_S3C2410X_CS5 | 0x2000000) +#define BAST_IDE_SEC_FAST (CPU_S3C2410X_CS5 | 0x3000000) + +#define BAST_IDE_PRI_SLOW_BYTE (CPU_S3C2410X_CS2 | 0x2000000) +#define BAST_IDE_SEC_SLOW_BYTE (CPU_S3C2410X_CS2 | 0x3000000) +#define BAST_IDE_PRI_FAST_BYTE (CPU_S3C2410X_CS4 | 0x2000000) +#define BAST_IDE_SEC_FAST_BYTE (CPU_S3C2410X_CS4 | 0x3000000) + +static void stcb_register_ide(void) +{ + int ide0_mem = stcb_ide_init(&bs_table[0], s3c_irqs[16]); + int ide1_mem = stcb_ide_init(&bs_table[2], s3c_irqs[17]); + + cpu_register_physical_memory(BAST_IDE_PRI_SLOW, 0x1000000, ide0_mem); + cpu_register_physical_memory(BAST_IDE_PRI_FAST, 0x1000000, ide0_mem); + + cpu_register_physical_memory(BAST_IDE_SEC_SLOW, 0x1000000, ide1_mem); + cpu_register_physical_memory(BAST_IDE_SEC_FAST, 0x1000000, ide1_mem); + + cpu_register_physical_memory(BAST_IDE_PRI_SLOW_BYTE, 0x1000000, ide0_mem); + cpu_register_physical_memory(BAST_IDE_PRI_FAST_BYTE, 0x1000000, ide0_mem); + + cpu_register_physical_memory(BAST_IDE_SEC_SLOW_BYTE, 0x1000000, ide1_mem); + cpu_register_physical_memory(BAST_IDE_SEC_FAST_BYTE, 0x1000000, ide1_mem); +} + +static void stcb_init(int _ram_size, int vga_ram_size, int boot_device, + DisplayState *ds, const char **fd_filename, int snapshot, + const char *kernel_filename, const char *kernel_cmdline, + const char *initrd_filename) +{ + CPUState *env; + int bios_offset; + char buf[1024]; /* URGH */ + int ret; + NICInfo* nd; + + if (_ram_size > (256 * MEGA * BYTE)) _ram_size = 256 * MEGA * BYTE; + ram_size = _ram_size; + + bios_offset = ram_size + vga_ram_size; + + env = s3c2410x_init(ram_size); + + if( kernel_filename == NULL ) { + snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME); + ret = load_image(buf, phys_ram_base + bios_offset); + if( ret <= 0 ) { + fprintf(stderr, "qemu: warning, could not load BAST BIOS from %s\n", buf); + } else { + fprintf(stdout, "qemu: info, loaded BAST BIOS %d bytes from %s\n", ret, buf); + } + } else { + arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, + initrd_filename, SIMTEC_BAST_BOARD_ID, CPU_S3C2410X_RAM); + /* Construct the smallest bootloader(ish) in the world */ + stl_raw(phys_ram_base + bios_offset, 0xE59FF000); /* ldr pc, [pc, #0] (loads from +8) */ + stl_raw(phys_ram_base + bios_offset + 4, 0x00000000); + stl_raw(phys_ram_base + bios_offset + 8, CPU_S3C2410X_RAM); + stl_raw(phys_ram_base + bios_offset + 12, 0xE3A0F000); + } + + /* Register the NOR flash ROM */ + cpu_register_physical_memory(SIMTEC_BAST_NOR_BASE, SIMTEC_BAST_NOR_SIZE, + bios_offset | IO_MEM_ROM); + stcb_register_ide(); + + nd = &nd_table[0]; + if (!nd->model) + nd->model = "dm9000"; + if (strcmp(nd->model, "dm9000") == 0) { + dm9000_init(nd, 0x2D000000, 0x00, 0x40, s3c_irqs[10]); + } + + + + /* And we're good to go */ +} + + +QEMUMachine simtecbast_machine = { + "simtecbast", + "Simtec Electronics BAST (S3C2410X, ARM920T)", + stcb_init, +}; === modified file 'Makefile.target' --- Makefile.target 2007-04-16 18:27:06 +0000 +++ Makefile.target 2007-04-16 21:51:37 +0000 @@ -447,6 +447,8 @@ ifeq ($(TARGET_BASE_ARCH), arm) VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl181.o pl190.o +VL_OBJS+= simtecbast.o s3c2410x.o s3c2410x_serial.o s3c2410x_memc.o s3c2410x_gpio.o s3c2410x_iic.o dm9000.o +VL_OBJS+= s3c2410x_irq.o s3c2410x_timers.o ide.o s3c2410x_clkcon.o s3c2410x_rtc.o VL_OBJS+= versatile_pci.o sd.o VL_OBJS+= arm_gic.o realview.o arm_sysctl.o VL_OBJS+= arm-semi.o === modified file 'hw/arm_boot.c' --- hw/arm_boot.c 2007-04-01 17:56:36 +0000 +++ hw/arm_boot.c 2007-04-16 21:51:37 +0000 @@ -32,11 +32,12 @@ if (env->kernel_filename) arm_load_kernel(env, env->ram_size, env->kernel_filename, env->kernel_cmdline, env->initrd_filename, - env->board_id); + env->board_id, env->emulated_sdram_base); } static void set_kernel_args(uint32_t ram_size, int initrd_size, - const char *kernel_cmdline) + const char *kernel_cmdline, + target_phys_addr_t emulated_sdram_base) { uint32_t *p; @@ -51,12 +52,12 @@ stl_raw(p++, 4); stl_raw(p++, 0x54410002); stl_raw(p++, ram_size); - stl_raw(p++, 0); + stl_raw(p++, emulated_sdram_base); if (initrd_size) { /* ATAG_INITRD2 */ stl_raw(p++, 4); stl_raw(p++, 0x54420005); - stl_raw(p++, INITRD_LOAD_ADDR); + stl_raw(p++, INITRD_LOAD_ADDR + emulated_sdram_base); stl_raw(p++, initrd_size); } if (kernel_cmdline && *kernel_cmdline) { @@ -77,7 +78,7 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, - int board_id) + int board_id, target_phys_addr_t emulated_sdram_base) { int kernel_size; int initrd_size; @@ -98,6 +99,7 @@ env->kernel_cmdline = kernel_cmdline; env->initrd_filename = initrd_filename; env->board_id = board_id; + env->emulated_sdram_base = emulated_sdram_base; qemu_register_reset(main_cpu_reset, env); } /* Assume that raw images are linux kernels, and ELF images are not. */ @@ -138,7 +140,7 @@ bootloader[6] = entry; for (n = 0; n < sizeof(bootloader) / 4; n++) stl_raw(phys_ram_base + (n * 4), bootloader[n]); - set_kernel_args(ram_size, initrd_size, kernel_cmdline); + set_kernel_args(ram_size, initrd_size, kernel_cmdline, emulated_sdram_base); } } === modified file 'hw/ide.c' --- hw/ide.c 2007-04-07 18:14:41 +0000 +++ hw/ide.c 2007-04-16 21:51:37 +0000 @@ -1789,7 +1789,10 @@ break; case WIN_DIAGNOSE: ide_set_signature(s); - s->status = 0x00; /* NOTE: READY is _not_ set */ + if (s->is_cdrom) + s->status = 0x00; /* NOTE: READY is _not_ set */ + else + s->status = READY_STAT; s->error = 0x01; break; case WIN_SRST: @@ -1879,6 +1882,7 @@ ret = 0; else ret = s->select; + ret |= 0x80; break; default: case 7: @@ -2749,3 +2753,82 @@ pmac_ide_write, &ide_if[0]); return pmac_ide_memory; } + +#if defined(TARGET_ARM) +#include "s3c2410x.h" + +/* MMIO interface to IDE on Simtec's BAST + * + * Copyright Daniel Silverstone and Vincent Sanders + * + * This section of this file is under the terms of + * the GNU General Public License Version 2 + */ + +/* Each BAST IDE region is 0x1000000 bytes long, + * the second half is the "alternate" register set + */ + +static void stcb_ide_write_f (void *opaque, + target_phys_addr_t addr, uint32_t val) +{ + int reg = (addr & 0x3ff) >> 5; /* 0x200 long, 0x20 stride */ + int alt = (addr & 0x800000) != 0; + S3C2410X_DBF("IDE write to addr %08x (reg %d) of value %04x\n",addr, reg, val); + if( alt ) { + ide_cmd_write(opaque, 0, val); + } + if( reg == 0 ) { + /* Data register */ + ide_data_writew(opaque, 0, val); + } else { + /* Everything else */ + ide_ioport_write(opaque, reg, val); + } +} + +static uint32_t stcb_ide_read_f (void *opaque,target_phys_addr_t addr) +{ + int reg = (addr & 0x3ff) >> 5; /* 0x200 long, 0x20 stride */ + int alt = (addr & 0x800000) != 0; + S3C2410X_DBF("IDE read of addr %08x (reg %d)\n",addr, reg); + if( alt ) { + return ide_status_read(opaque, 0); + } + if( reg == 0 ) { + return ide_data_readw(opaque, 0); + } else { + return ide_ioport_read(opaque, reg); + } +} + + +static CPUWriteMemoryFunc *stcb_ide_write[] = { + stcb_ide_write_f, + stcb_ide_write_f, + stcb_ide_write_f, +}; + +static CPUReadMemoryFunc *stcb_ide_read[] = { + stcb_ide_read_f, + stcb_ide_read_f, + stcb_ide_read_f, +}; + +/* hd_table must contain 2 block drivers */ +/* BAST uses memory mapped registers, not I/O. Return the memory + I/O index to access the ide. */ +int stcb_ide_init (BlockDriverState **hd_table, qemu_irq irq) +{ + IDEState *ide_if; + int stcb_ide_memory; + + ide_if = qemu_mallocz(sizeof(IDEState) * 2); + ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq); + + stcb_ide_memory = cpu_register_io_memory(0, stcb_ide_read, + stcb_ide_write, &ide_if[0]); + return stcb_ide_memory; +} + +#endif === modified file 'hw/integratorcp.c' --- hw/integratorcp.c 2007-04-07 18:14:41 +0000 +++ hw/integratorcp.c 2007-04-16 21:51:37 +0000 @@ -508,7 +508,7 @@ pl110_init(ds, 0xc0000000, pic[22], 0); arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, 0x113); + initrd_filename, 0x113, 0); } QEMUMachine integratorcp_machine = { === modified file 'hw/irq.h' --- hw/irq.h 2007-04-07 18:14:41 +0000 +++ hw/irq.h 2007-04-16 21:51:37 +0000 @@ -1,3 +1,5 @@ +#ifndef QEMU_HW_IRQ_H +#define QEMU_HW_IRQ_H /* Generic IRQ/GPIO pin infrastructure. */ typedef void (*qemu_irq_handler)(void *opaque, int n, int level); @@ -19,3 +21,4 @@ /* Returns an array of N IRQs. */ qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n); +#endif === modified file 'hw/realview.c' --- hw/realview.c 2007-04-07 18:14:41 +0000 +++ hw/realview.c 2007-04-16 21:51:37 +0000 @@ -131,7 +131,7 @@ /* 0x6c000000 PCI mem 2. */ arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, 0x33b); + initrd_filename, 0x33b, 0x0); } QEMUMachine realview_machine = { === modified file 'hw/versatilepb.c' --- hw/versatilepb.c 2007-04-07 18:14:41 +0000 +++ hw/versatilepb.c 2007-04-16 21:51:37 +0000 @@ -260,7 +260,7 @@ /* 0x101f4000 SSPI. */ arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline, - initrd_filename, board_id); + initrd_filename, board_id, 0); } static void vpb_init(int ram_size, int vga_ram_size, int boot_device, === modified file 'target-arm/cpu.h' --- target-arm/cpu.h 2007-03-11 13:03:18 +0000 +++ target-arm/cpu.h 2007-04-16 21:51:37 +0000 @@ -127,6 +127,7 @@ const char *kernel_filename; const char *kernel_cmdline; const char *initrd_filename; + target_phys_addr_t emulated_sdram_base; int board_id; } CPUARMState; @@ -220,6 +221,7 @@ #define ARM_CPUID_ARM1026 0x4106a262 #define ARM_CPUID_ARM926 0x41069265 +#define ARM_CPUID_ARM920T 0x41129200 #if defined(CONFIG_USER_ONLY) #define TARGET_PAGE_BITS 12 === modified file 'target-arm/helper.c' --- target-arm/helper.c 2007-04-07 11:21:27 +0000 +++ target-arm/helper.c 2007-04-16 21:51:37 +0000 @@ -14,6 +14,8 @@ { env->cp15.c0_cpuid = id; switch (id) { + case ARM_CPUID_ARM920T: + break; case ARM_CPUID_ARM926: set_feature(env, ARM_FEATURE_VFP); env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090; @@ -68,6 +70,7 @@ static const struct arm_cpu_t arm_cpu_names[] = { { ARM_CPUID_ARM926, "arm926"}, { ARM_CPUID_ARM1026, "arm1026"}, + { ARM_CPUID_ARM920T, "arm920t"}, { 0, NULL} }; === modified file 'target-arm/translate.c' --- target-arm/translate.c 2007-04-02 08:18:36 +0000 +++ target-arm/translate.c 2007-04-16 21:51:37 +0000 @@ -525,6 +525,19 @@ return 0; } +static int disas_cp14_insn(DisasContext *s, uint32_t insn) +{ + uint32_t rd = (insn >> 12) & 0xf; + if (insn & (1<<20)) { + gen_op_movl_T0_im(0); + gen_op_movl_reg_TN[0][rd](); + } else { + /* Nothing to do on writes to cp14 */ + } + gen_lookup_tb(s); + return 0; +} + /* Disassemble a VFP instruction. Returns nonzero if an error occured (ie. an undefined instruction). */ static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn) @@ -1818,6 +1831,11 @@ if (disas_vfp_insn (env, s, insn)) goto illegal_op; break; + case 14: + /* ice */ + if (disas_cp14_insn (s, insn)) + goto illegal_op; + break; case 15: if (disas_cp15_insn (s, insn)) goto illegal_op; === modified file 'vl.c' --- vl.c 2007-04-16 17:23:27 +0000 +++ vl.c 2007-04-16 21:51:37 +0000 @@ -6710,6 +6710,7 @@ qemu_register_machine(&versatilepb_machine); qemu_register_machine(&versatileab_machine); qemu_register_machine(&realview_machine); + qemu_register_machine(&simtecbast_machine); #elif defined(TARGET_SH4) qemu_register_machine(&shix_machine); #elif defined(TARGET_ALPHA) === modified file 'vl.h' --- vl.h 2007-04-16 17:23:27 +0000 +++ vl.h 2007-04-16 21:51:37 +0000 @@ -173,6 +173,11 @@ #define BIOS_SIZE ((512 + 32) * 1024) #elif defined(TARGET_MIPS) #define BIOS_SIZE (4 * 1024 * 1024) +#elif defined(TARGET_ARM) +/* ARM boards often have bootloaders in NOR which ends up + * memory mapped. 8 Megabytes seems enough for this + */ +#define BIOS_SIZE (8 * 1024 * 1024) #endif /* keyboard/mouse support */ @@ -964,6 +969,7 @@ void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn, qemu_irq *pic); int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq); +int stcb_ide_init (BlockDriverState **hd_table, qemu_irq irq); /* cdrom.c */ int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track); @@ -1363,6 +1369,9 @@ extern QEMUMachine versatilepb_machine; extern QEMUMachine versatileab_machine; +/* simtecbast.c */ +extern QEMUMachine simtecbast_machine; + /* realview.c */ extern QEMUMachine realview_machine; @@ -1379,6 +1388,11 @@ /* smc91c111.c */ void smc91c111_init(NICInfo *, uint32_t, qemu_irq); +/* dm9000.c */ + +void dm9000_init(NICInfo *nd, target_phys_addr_t base_addr, uint32_t addr_offset, + uint32_t data_offset, qemu_irq irq); + /* pl110.c */ void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int); @@ -1412,7 +1426,7 @@ void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename, const char *kernel_cmdline, const char *initrd_filename, - int board_id); + int board_id, target_phys_addr_t emulated_sdram_base); /* sh7750.c */ struct SH7750State;