[Top][All Lists]
[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;
- [Qemu-devel] [patch] Simtec BAST system emulation,
Daniel Silverstone <=