qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [patch] Simtec BAST system emulation


From: Daniel Silverstone
Subject: [Qemu-devel] [patch] Simtec BAST system emulation
Date: Thu, 19 Apr 2007 14:06:17 +0100

Hi,

I have spent a while now sorting out the Simtec BAST patch which I
originally subbed at the start of this month.

Paul: I believe I have addressed all the points you raised when you
previously reviewed the patch

andrzej: We eventually chose to continue with our emulation because
yours is too hw-faithful to be fast. Hopefully we can work together in
the future when you have some more bandwidth to integrate your work into
ours and thus get a best-of-both-worlds solution into mainline.

Everyone else:

Have a play. I believe the patch is clean and it does fix a bug in the
IDE emulation and adds support to the ARM boot stuff for ARM systems
which do not place their SDRAM at phys_addr 0x00

Thanks,

Daniel.

-- 
Daniel Silverstone                         http://www.digital-scurf.org/
PGP mail accepted and encouraged.            Key Id: 2BC8 4016 2068 7895

=== 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 <string.h>
+#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 <arpa/inet.h>
+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-19 12:37:50 +0000
@@ -0,0 +1,73 @@
+/* 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"
+
+/* Initialise a Samsung S3C2410X and all its internal peripherals.
+ *
+ * This emulation was originally intended to be sufficient to get a
+ * Simtec Electronics BAST (EB2410ITX) system emulation up and going
+ * well enough that the Simtec Advanced BootLoader Environment (ABLE)
+ * would startup and in its turn, be able to start a Linux system.
+ *
+ * The emulation is thus faithful to functionality only where it was
+ * necessary for getting things going. In particular it is not a fully
+ * faithful IRQ emulator, it does not implement the memory controller
+ * fully since there's no real simulated SDRAM is it were.
+ *
+ * The emulation is thus quite fast, where a more faithful emulation
+ * may be slower.
+ *
+ * Over time, the following peripherals are planned for implementing:
+ *  LCD controller
+ *  NAND controller
+ *  I2C device bus of some kind.
+ *  USB device port.
+ */
+S3CState *
+s3c2410x_init(int ram_size)
+{
+  S3CState *s = (S3CState *)qemu_mallocz(sizeof(S3CState));
+  /* Prepare the ARM 920T */
+  s->cpu_env = cpu_init();
+  cpu_arm_set_model(s->cpu_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(s);
+  /* And some interrupts (coo) */
+  S3C2410X_DBF("interrupts\n");
+  s->irqs = s3c2410x_irq_init(s);
+  /* The clock control allows for idling the CPU */
+  s3c2410x_clkcon_init(s);
+  /* And some GPIO */
+  S3C2410X_DBF("gpio\n");
+  s3c2410x_gpio_init(s); 
+  /* RTC for time */
+  s3c2410x_rtc_init(s);
+  /* And some IIC */
+  s3c2410x_iic_init(s);
+  /* And some timers */
+  s3c2410x_timers_init(s);
+  /* Serial ports */
+  S3C2410X_DBF("serial\n");
+  s3c2410x_serial_init(s, 0);
+  s3c2410x_serial_init(s, 1);
+  s3c2410x_serial_init(s, 2);
+  /* 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, s->irqs[26]);
+  return s;
+}
+

=== added file 'hw/s3c2410x.h'
--- hw/s3c2410x.h       1970-01-01 00:00:00 +0000
+++ hw/s3c2410x.h       2007-04-19 12:39:54 +0000
@@ -0,0 +1,395 @@
+/* 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
+
+/* This structure type encapsulates the state of the
+ * S3C2410X SoC.
+ */
+typedef struct {
+  CPUState *cpu_env;
+  qemu_irq *irqs;
+  qemu_irq *eirqs;
+  /* Memory controller */
+  uint32_t memc_reg[13];
+  /* Interrupt controller */
+  uint32_t irq_main_level, irq_subsrc_level;
+  uint32_t irq_reg[8];
+  /* Clock controller */
+  uint32_t clkcon_reg[6];
+  /* GPIO block */
+  uint32_t gpio_reg[47];
+  /* Realtime clock */
+  uint8_t rtc_reg[19];
+  /* I2C */
+  uint32_t iic_reg[4];
+  /* Timers, (Specifically timer4) */
+  uint32_t timers_reg[17];
+  QEMUTimer *timer4;
+  uint32_t timer4_reload_value;
+  int64_t timer4_last_ticked;
+} S3CState;
+
+/* External */
+S3CState *s3c2410x_init(int ram_size);
+
+/* Internal functions for s3c2410x implementation */
+void s3c2410x_memc_init(S3CState *soc);
+qemu_irq *s3c2410x_irq_init(S3CState *soc);
+void s3c2410x_gpio_init(S3CState *soc);
+void s3c2410x_clkcon_init(S3CState *soc);
+void s3c2410x_timers_init(S3CState *soc);
+void s3c2410x_iic_init(S3CState *soc);
+void s3c2410x_rtc_init(S3CState *soc);
+void s3c2410x_serial_init(S3CState *soc, int port);
+
+
+#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-17 11:47:14 +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"
+
+/* Currently this is not exported from the core. Should it be? */
+void cpu_loop_exit(void);
+
+static void
+s3c2410x_clkcon_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  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( !(soc->clkcon_reg[addr] & CPU_S3C2410X_REG_CLKCON_IDLE) &&
+        (value & CPU_S3C2410X_REG_CLKCON_IDLE) ) idle_rising_edge = 1;
+  }
+  soc->clkcon_reg[addr] = value;
+  if( idle_rising_edge ) {
+    S3C2410X_DBF("CLKCON: Idling CPU\n");
+    soc->cpu_env->exception_index = EXCP_HLT;
+    soc->cpu_env->halted = 1;
+    cpu_loop_exit(); /* May longjmp() away so nothing after here please */
+  }
+}
+
+static uint32_t
+s3c2410x_clkcon_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0x1F) >> 2;
+  if (addr < 0 || addr > 5) addr = 5;
+  S3C2410X_DBF("Read CLKCON[%d]\n", addr);
+  return soc->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(S3CState *soc)
+{
+  int tag;
+
+  tag = cpu_register_io_memory(0, s3c2410x_clkcon_read, s3c2410x_clkcon_write, 
soc);
+  cpu_register_physical_memory(CPU_S3C2410X_CLKCON, 6*4, tag);
+  
+#define CR(X) soc->clkcon_reg[X]
+  CR(0) = 0x00FFFFFF;
+  CR(1) = 0x0005C080;
+  CR(2) = 0x00028080;
+  CR(3) = 0x0007FFF0;
+  CR(4) = 0x00000004;
+  CR(5) = 0x00000000;
+#undef CR
+}

=== added file 'hw/s3c2410x_gpio.c'
--- hw/s3c2410x_gpio.c  1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_gpio.c  2007-04-17 11:52:15 +0000
@@ -0,0 +1,160 @@
+/* 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"
+
+#define EINT_MASK (0xA4)
+#define EINT_PEND (0xA8)
+#define GPR(P) soc->gpio_reg[P>>2]
+
+static void
+s3c2410x_gpio_propogate_eint(S3CState *soc)
+{
+  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(soc->irqs[i], (ints&(1<<i))?1:0);
+  /* EINT4 - EINT7 are INT4 */
+  qemu_set_irq(soc->irqs[4], (ints&0xf0)?1:0);
+  /* EINT8 - EINT23 are INT5 */
+  qemu_set_irq(soc->irqs[5], (ints&0x00ffff00)?1:0);
+}
+
+static uint32_t
+gpio_con_to_mask(uint32_t con)
+{
+  uint32_t mask = 0x0;
+  int bit;
+
+  for (bit = 0; bit < 16; bit++) {
+    if (((con >> (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)
+{
+  S3CState *soc = (S3CState *)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))
+    soc->gpio_reg[addr] &= ~value;
+  else {
+    if (addr < (0x80/4) && (addr_ & 0xf) == 0x04) {
+      uint32_t mask = gpio_con_to_mask(soc->gpio_reg[addr-1]);
+
+      value &= mask;
+
+      soc->gpio_reg[addr] &= ~mask;
+      soc->gpio_reg[addr] |= value;
+    } else
+      soc->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(soc);
+  }
+}
+
+static uint32_t
+s3c2410x_gpio_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  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 = soc->gpio_reg[addr];
+    if ((soc->gpio_reg[15] & 3<<28) == 0) ret |= 1 << 14;
+    if ((soc->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, soc->gpio_reg[addr]);
+  return soc->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)
+{
+  S3CState *soc = (S3CState *)opaque;
+  if (level)
+    GPR(EINT_PEND) |= (1<<n);
+  s3c2410x_gpio_propogate_eint(soc);
+}
+
+void
+s3c2410x_gpio_init(S3CState *soc)
+{
+  /* Samsung S3C2410X GPIO magic badger.
+   *
+   * The only really magic thing we do currently is the ID register
+   */
+  int tag = cpu_register_io_memory(0, s3c2410x_gpio_read, s3c2410x_gpio_write, 
soc);
+  cpu_register_physical_memory(CPU_S3C2410X_GPIO_BASE, 47*4, tag);
+  GPR(0x00) = 0x7fffff;
+  GPR(0x10) = 0;
+  GPR(0x18) = 0;
+  GPR(0x20) = 0;
+  GPR(0x28) = 0;
+  GPR(0x30) = 0;
+  GPR(0x34) = 0xfefc;          /* This happens to be the default in the h1940 
*/
+  GPR(0x38) = 0xf000;
+  GPR(0x40) = 0;
+  GPR(0x48) = 0;
+  GPR(0x50) = 0;
+  GPR(0x58) = 0;
+  GPR(0x60) = 0;
+  GPR(0x68) = 0xf800;
+  GPR(0x70) = 0;
+  GPR(0x78) = 0;
+  GPR(0x80) = 0x10330;
+  GPR(0x84) = 0;
+  GPR(0x88) = 0;
+  GPR(0x8C) = 0;
+  GPR(0x90) = 0;
+  GPR(0x9C) = 0;
+  GPR(0xA0) = 0;
+  GPR(0xA4) = 0xfffff0;
+  GPR(0xA8) = 0;
+  GPR(0xB0) = 0x3241000;
+  GPR(0xB4) = 1;
+  GPR(0xB8) = 0;
+  GPR(0xBC) = 0;
+  /* EINTs 0-23 */
+  soc->eirqs = qemu_allocate_irqs(s3c2410x_gpio_irq_handler, soc, 24);
+}

=== added file 'hw/s3c2410x_iic.c'
--- hw/s3c2410x_iic.c   1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_iic.c   2007-04-19 12:40:35 +0000
@@ -0,0 +1,145 @@
+/* hw/s3c2410x_iic.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2006, 2007 Daniel Silverstone, Ben Dooks
+ *  and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "vl.h"
+#include "s3c2410x.h"
+#include "s3c24xx/regs-iic.h"
+
+static void
+s3c2410x_iic_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0xf);
+  
+  S3C2410X_DBF("Write IIC[%02x] = %08x\n", addr, value);
+
+
+  switch (addr) {
+  case S3C2410_IICCON:
+    value |= (soc->iic_reg[0] & S3C2410_IICCON_IRQPEND);
+    soc->iic_reg[0] = value ;
+    break;
+
+  case S3C2410_IICSTAT:
+    if ((value & S3C2410_IICSTAT_START) &&
+       (((value & S3C2410_IICSTAT_MODEMASK) == S3C2410_IICSTAT_MASTER_TX) ||
+        ((value & S3C2410_IICSTAT_MODEMASK) == S3C2410_IICSTAT_MASTER_RX))) {
+      /* When we're Master TX and told to start, we hiccough inappropriately */
+      S3C2410X_DBF("Oooh, IIC write to fail, yum!\n");
+
+      value &= ~S3C2410_IICSTAT_BUSBUSY; /* Not running */
+      soc->iic_reg[1] = value;
+
+      soc->iic_reg[0] |= S3C2410_IICCON_IRQPEND; /* Claim an interrupt */
+
+      switch (soc->iic_reg[1] & S3C2410_IICSTAT_MODEMASK) {
+      case S3C2410_IICSTAT_MASTER_TX:
+       break;
+
+      case S3C2410_IICSTAT_MASTER_RX:
+       break;
+      }
+      
+      S3C2410X_DBF("And raise an interrupt\n");
+      qemu_set_irq(soc->irqs[27], 1);
+    }
+    break;
+
+  case S3C2410_IICDS:
+    /* write to data register */
+    soc->iic_reg[addr >> 2] = 0xff;
+    break;
+    
+  default:
+    soc->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, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0xf);
+  uint32_t val;
+
+  if (addr < 0 || addr > 12) addr = 12;
+
+  val = soc->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(S3CState *soc)
+{
+  /* Samsung S3C2410X IIC registration. */
+  int tag = cpu_register_io_memory(0, s3c2410x_iic_read, s3c2410x_iic_write, 
soc);
+  cpu_register_physical_memory(CPU_S3C2410X_IIC_BASE, 4*4, tag);
+  soc->iic_reg[0] = 0;
+  soc->iic_reg[1] = 0;
+  soc->iic_reg[2] = 0;
+  soc->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 11:38:54 +0000
@@ -0,0 +1,182 @@
+/* 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 void
+__s3c2410x_percolate_interrupt(S3CState *soc)
+{
+  /* Take the status of the srcpnd register, percolate it through, raise to 
CPU if necessary */
+  uint32_t ints = (soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] & 
+                   ~soc->irq_reg[CPU_S3C2410X_IRQ_INTMSK]);
+  int fsb = ffs(ints);
+  
+  /* TODO: Priority encoder could go here */
+  if (ints & soc->irq_reg[CPU_S3C2410X_IRQ_INTMOD]) {
+    /* Detected a FIQ */
+    S3C2410X_DBF("IRQ: Setting FIQ on CPU\n");
+    cpu_interrupt(soc->cpu_env, CPU_INTERRUPT_FIQ);
+    return;
+  } else {
+    /* No FIQ here today */
+    cpu_reset_interrupt(soc->cpu_env, CPU_INTERRUPT_FIQ);
+  }
+  /* No FIQ, do we have an IRQ */
+  if (fsb) {
+    if ((soc->irq_reg[CPU_S3C2410X_IRQ_INTPND] == 0) ||
+        (soc->irq_reg[CPU_S3C2410X_IRQ_INTPND] > 1<<(fsb-1))) {
+      /* Current INTPND is lower priority than fsb of ints (or empty) */
+      soc->irq_reg[CPU_S3C2410X_IRQ_INTPND] = 1<<(fsb-1);
+      soc->irq_reg[CPU_S3C2410X_IRQ_OFFSET] = fsb-1;
+    }
+  } else {
+    /* No FSB, thus no IRQ, thus nothing to see yet */
+  }
+
+  if (soc->irq_reg[CPU_S3C2410X_IRQ_INTPND] != 0) {
+    S3C2410X_DBF("IRQ: Setting IRQ on CPU\n");
+    cpu_interrupt(soc->cpu_env, CPU_INTERRUPT_HARD);
+  } else {
+    cpu_reset_interrupt(soc->cpu_env, CPU_INTERRUPT_HARD);
+  }
+}
+
+static void
+s3c2410x_percolate_subsrc_interrupt(S3CState *soc)
+{
+  uint32_t ints;
+  
+  soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= soc->irq_main_level;
+  soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] |= soc->irq_subsrc_level;
+  
+  ints = (soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] &
+          ~soc->irq_reg[CPU_S3C2410X_IRQ_INTSUBMSK]);
+   
+  /* If UART0 has asserted, raise that */
+  S3C2410X_DBF("SUBSRCPND 0x%08x\n", soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND]);
+  S3C2410X_DBF("INTSUBMSK 0x%08x\n", soc->irq_reg[CPU_S3C2410X_IRQ_INTSUBMSK]);
+  S3C2410X_DBF(" => Pending Subsource interrupts: %08x\n", ints);
+  if( ints & 0x7 ) {
+    S3C2410X_DBF("IRQ: Percolating UART0 subsource\n");
+    soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<28);
+  }
+  /* Ditto UART1 */
+  if( ints & 0x7<<3 ) soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<23);
+  /* Ditto UART2 */
+  if( ints & 0x7<<6 ) soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<15);
+  /* And percolate it through */
+  __s3c2410x_percolate_interrupt(soc);
+}
+
+static void
+s3c2410x_irq_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)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) {
+    soc->irq_reg[addr] &= ~value;
+  } else {
+    soc->irq_reg[addr] = value;
+  }
+
+  /* Start at the subsrc irqs and percolate from there */
+  s3c2410x_percolate_subsrc_interrupt(soc);
+}
+
+static uint32_t
+s3c2410x_irq_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 0x7;
+  S3C2410X_DBF("Read IRQ[%02x] => 0x%08x\n",addr<<2, soc->irq_reg[addr]);
+  return soc->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(S3CState *soc, 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) soc->irq_main_level |= 1<<irq_num;
+    soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= 1<<irq_num;
+  } else {
+    soc->irq_main_level &= ~(1<<irq_num);
+    soc->irq_reg[CPU_S3C2410X_IRQ_SRCPND] &= ~(1<<irq_num);
+  }
+  s3c2410x_percolate_subsrc_interrupt(soc);
+}
+
+static void
+s3c2410x_irq_set_subsrc_interrupt_level(S3CState *soc, int irq_num, int level, 
int set_level)
+{
+  S3C2410X_DBF("IRQ: Set subsrc level for %d to %d\n", irq_num, level);
+  if( level ) {
+    if (set_level) soc->irq_subsrc_level |= 1<<irq_num;
+    soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] |= 1<<irq_num;
+  } else {
+    soc->irq_subsrc_level &= ~(1<<irq_num);
+    soc->irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] &= ~(1<<irq_num);
+  }
+  s3c2410x_percolate_subsrc_interrupt(soc);
+}
+
+static void
+s3c2410x_irq_handler(void *opaque, int _n, int level)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int irq_num = _n % 32;
+  int is_subsrc = (_n & 32)?1:0;
+  int is_level = (_n & 64)?1:0;
+  S3C2410X_DBF("Setting %sIRQ[%d] = %d%s\n", (is_subsrc?"SUB ":""), irq_num, 
level, (is_level?" (level)":""));
+  if (is_subsrc == 0)
+    s3c2410x_irq_set_interrupt_level(soc, irq_num, level, is_level);
+  else
+    s3c2410x_irq_set_subsrc_interrupt_level(soc, irq_num, level, is_level);
+}
+
+qemu_irq *
+s3c2410x_irq_init(S3CState *soc)
+{
+  /* Samsung S3C2410X IRQ registration. */
+  int tag = cpu_register_io_memory(0, s3c2410x_irq_read, s3c2410x_irq_write, 
soc);
+  cpu_register_physical_memory(CPU_S3C2410X_IRQ_BASE, 8*4, tag);
+#define IR(X) soc->irq_reg[X]
+  IR(CPU_S3C2410X_IRQ_SRCPND) = 0x00;
+  IR(CPU_S3C2410X_IRQ_INTMOD) = 0x00;
+  IR(CPU_S3C2410X_IRQ_INTMSK) = 0xFFFFFFFF;
+  IR(CPU_S3C2410X_IRQ_PRIORITY) = 0x7F; /* Not that we use it */
+  IR(CPU_S3C2410X_IRQ_INTPND) = 0x00;
+  IR(CPU_S3C2410X_IRQ_OFFSET) = 0x00;
+  IR(CPU_S3C2410X_IRQ_SUBSRCPND) = 0x00;
+  IR(CPU_S3C2410X_IRQ_INTSUBMSK) = 0x7FF;
+#undef IR
+  /* Allocate the interrupts and return them. All 64 potential ones.
+   * We return them doubled up because the latter half are level where
+   * the former half are edge.
+   */
+  return qemu_allocate_irqs(s3c2410x_irq_handler, soc, 128);
+}

=== added file 'hw/s3c2410x_memc.c'
--- hw/s3c2410x_memc.c  1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_memc.c  2007-04-19 12:40:58 +0000
@@ -0,0 +1,60 @@
+/* hw/s3c2410x_memc.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 void
+s3c2410x_memc_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0x3f) >> 2;
+  if (addr < 0 || addr > 12) addr = 12;
+  S3C2410X_DBF("Write MEMC[%d] = %08x\n", addr, value);
+  soc->memc_reg[addr] = value;
+}
+
+static uint32_t
+s3c2410x_memc_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ & 0x3f) >> 2;
+  if (addr < 0 || addr > 12) addr = 12;
+  S3C2410X_DBF("Read MEMC[%d]\n", addr);
+  return soc->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(S3CState *soc)
+{
+  /* 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.
+   */
+  int tag;
+  tag = cpu_register_io_memory(0, s3c2410x_memc_read, s3c2410x_memc_write, 
soc);
+  cpu_register_physical_memory(CPU_S3C2410X_BWSCON, 13*4, tag);
+  
+  for(tag = 0; tag < 13; tag++) soc->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-17 11:55:19 +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 inline int to_bcd(int a)
+{
+  return ((a/10)<<4) | (a%10);
+}
+
+static void
+s3c2410x_rtc_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ - CPU_S3C2410X_RTC_BASE) >> 2;
+  if (addr < 0 || addr > 18) addr = 18;
+  S3C2410X_DBF("Write RTC[%d] = %08x\n", addr, value);
+  soc->rtc_reg[addr] = value;
+}
+
+static uint32_t
+s3c2410x_rtc_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  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 soc->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(S3CState *soc)
+{
+  int tag;
+  tag = cpu_register_io_memory(0, s3c2410x_rtc_read, s3c2410x_rtc_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_RTC_BASE, 19*4, tag);
+  for(tag=0; tag < 18; ++tag) soc->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-19 12:41:09 +0000
@@ -0,0 +1,219 @@
+/* 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(S3CState *soc, int port)
+{
+  /* 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 = soc->irqs[32 + (port * 3) + 1];
+  s->rx_irq = soc->irqs[32 + (port * 3)];
+  s->tx_level = soc->irqs[64 + 32 + (port * 3) + 1];
+  s->rx_level = soc->irqs[64 + 32 + (port * 3)];
+  /* 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-17 12:14:48 +0000
@@ -0,0 +1,114 @@
+/* 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"
+
+/*
+  
+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(S3CState *soc)
+{
+  soc->timers_reg[CPU_S3C2410X_TIMERS_TCNTB4] = soc->timer4_reload_value;
+  soc->timer4_last_ticked = qemu_get_clock(vm_clock);
+  qemu_mod_timer(soc->timer4, soc->timer4_last_ticked + 
((soc->timer4_reload_value*ticks_per_sec)/TCLK1));
+}
+
+static void
+s3c2410x_timer4_tick(void *opaque)
+{
+  S3CState *soc = (S3CState *)opaque;
+  S3C2410X_DBF("Timer4 goes TICK!\n");
+  qemu_set_irq(soc->irqs[14], 1);
+  if (soc->timers_reg[CPU_S3C2410X_TIMERS_TCON] && (1<<22)) {
+    s3c2410x_schedule_timer4(soc);
+  }
+}
+
+static void
+s3c2410x_timers_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 0x1f;
+  S3C2410X_DBF("Write TIMERS[%02x] = %08x\n",addr<<2, value);
+  soc->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) ) 
+      soc->timer4_reload_value = soc->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(soc);
+    }
+  }
+}
+
+static uint32_t
+s3c2410x_timers_read_f(void *opaque, target_phys_addr_t addr_)
+{
+  S3CState *soc = (S3CState *)opaque;
+  int addr = (addr_ >> 2) & 0x1f;
+  S3C2410X_DBF("Read TIMERS[%02x]\n",addr<<2);
+  if( addr == CPU_S3C2410X_TIMERS_TCNTO4 ) {
+    return soc->timer4_reload_value - 
(((qemu_get_clock(vm_clock)-soc->timer4_last_ticked)*TCLK1)/ticks_per_sec);
+  }
+  return soc->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(S3CState *soc)
+{
+  /* Samsung S3C2410X TIMERS registration.
+   *
+   * Specifically the PWM timer4.
+   */
+  int tag = cpu_register_io_memory(0, s3c2410x_timers_read, 
s3c2410x_timers_write, soc);
+  cpu_register_physical_memory(CPU_S3C2410X_TIMERS_BASE, 17*4, tag);
+  soc->timer4 = qemu_new_timer(vm_clock, s3c2410x_timer4_tick, soc);
+}
+
+/*
+  
+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 <address@hidden>
+ *             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-17 11:05:22 +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(S3CState *soc)
+{
+  int ide0_mem = stcb_ide_init(&bs_table[0], soc->irqs[16]);
+  int ide1_mem = stcb_ide_init(&bs_table[2], soc->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)
+{
+  S3CState *soc;
+  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;
+
+  soc = 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(soc->cpu_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(soc);
+
+  nd = &nd_table[0];
+  if (!nd->model)
+      nd->model = "dm9000";
+  if (strcmp(nd->model, "dm9000") == 0) {
+      dm9000_init(nd, 0x2D000000, 0x00, 0x40, soc->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 20:09:44 +0000
+++ Makefile.target     2007-04-19 12:57:34 +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-18 18:11:47 +0000
+++ vl.c        2007-04-19 12:57:34 +0000
@@ -6728,6 +6728,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-17 16:28:29 +0000
+++ vl.h        2007-04-19 12:57:34 +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);
@@ -1376,6 +1382,9 @@
 extern QEMUMachine versatilepb_machine;
 extern QEMUMachine versatileab_machine;
 
+/* simtecbast.c */
+extern QEMUMachine simtecbast_machine;
+
 /* realview.c */
 extern QEMUMachine realview_machine;
 
@@ -1392,6 +1401,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);
 
@@ -1425,7 +1439,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;


reply via email to

[Prev in Thread] Current Thread [Next in Thread]