* [Qemu-devel] Simtec BAST emulation
@ 2007-04-02 13:56 Daniel Silverstone
2007-04-02 17:45 ` Paul Brook
2007-04-02 23:04 ` andrzej zaborowski
0 siblings, 2 replies; 8+ messages in thread
From: Daniel Silverstone @ 2007-04-02 13:56 UTC (permalink / raw)
To: qemu-devel; +Cc: paul
[-- Attachment #1: Type: text/plain, Size: 2301 bytes --]
Hi,
Myself and my colleagues have worked hard and produced a new system
emulation for qemu for the Simtec BAST board.
The BAST is a Samsung 2410 based board (ARM 9 based SoC, with MMU) with
various peripherals including a Davicom DM9000 Ethernet port.
The emulation is complete enough to start Simtec's ABLE boot loader
(downloadable from www.simtec.co.uk) and also is capable of being
direct-booted with a linux kernel/initrd combination as per the
versatile etc.
Among other things, the patch needs to add support for OHCI USB systems
not on PCI, ARM systems where SDRAM isn't at 0 (phys) and MMIO based
IDE. Naturally this has all been done as generically as made sense at
the time.
There is one generic fix in the patch which hardly seemed worth breaking
out on its own. It corrects a bug where QEMU would ignore WIN_DIAGNOSE's
behaviour for normal drives. It assumed HDDs behaved as CDROMs under
WIN_DIAGNOSE which is not the case.
Unfortunately I was unable to sensibly separate the patch up because of
the difficulties which stem from qemu's current source layout. E.g. it
was hard to split out the MMIO IDE from the rest of the IDE without
dramatically changing the exported symbol lists.
Hopefully you'll be happy with the whole patch. In particular I've tried
to isolate the s3c2410x stuff away from the BAST stuff, so that in
future other 2410x based systems such as the H1940 PDA or the FIC NEO
1973 (openmoko?) can be implemented with minimal fuss.
We have a partially complete s3c2410x NAND driver, a partial LCD driver
and various other bits which we will submit as and when we have them
done.
Some of the peripherals don't correctly save/restore their state as of
yet, but as the patch was getting larger and larger I felt it safer to
offer this now and to produce those as fix patches once the bulk of the
code was in place.
I trust that the work is of a sufficiently high standard to be included
in the mainline codebase and I'd be happy to either continue to sub
patches through the list, or if you are happy with our work, I'd love to
have CVS commit access for this stuff going forward.
Regards,
Daniel Silverstone.
--
Daniel Silverstone http://www.simtec.co.uk/
PGP mail accepted and encouraged. Key Id: 2BC8 4016 2068 7895
[-- Attachment #2: Simtec BAST implementation for QEMU --]
[-- Type: application/x-gzip, Size: 19157 bytes --]
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] Simtec BAST emulation
2007-04-02 13:56 [Qemu-devel] Simtec BAST emulation Daniel Silverstone
@ 2007-04-02 17:45 ` Paul Brook
2007-04-03 10:12 ` Daniel Silverstone
` (2 more replies)
2007-04-02 23:04 ` andrzej zaborowski
1 sibling, 3 replies; 8+ messages in thread
From: Paul Brook @ 2007-04-02 17:45 UTC (permalink / raw)
To: qemu-devel, dsilvers
On Monday 02 April 2007 14:56, Daniel Silverstone wrote:
> Hi,
>
> Myself and my colleagues have worked hard and produced a new system
> emulation for qemu for the Simtec BAST board.
A few issues with the patch, which I think need to be resolved before it can
be applied:
- You're using global structures to store machine state.
While it's debatable whether you'll ever have more than one s3c2410, I think
it's definitely still worth allowing for this possibility, and encapsulating
the state in a structure, like all the other hardware emulation does.
- For the device emulation (dm9000 and ide, maybe others) you should use
pic_set_irq_new, instead of passing a separate set_irq function. Other ARM
boards already support arbitrary routing of interrupts via hw/arm_pic.[ch].
- usb_ohci_mmap_init should look more like (or even be the same function as)
usb_ohci_init_pxa.
> The emulation is complete enough to start Simtec's ABLE boot loader
> (downloadable from www.simtec.co.uk) and also is capable of being
> direct-booted with a linux kernel/initrd combination as per the
> versatile etc.
What is the licence for ABLE? Would we be able to distribute it with qemu?
Paul
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] Simtec BAST emulation
2007-04-02 13:56 [Qemu-devel] Simtec BAST emulation Daniel Silverstone
2007-04-02 17:45 ` Paul Brook
@ 2007-04-02 23:04 ` andrzej zaborowski
2007-04-03 10:09 ` Daniel Silverstone
1 sibling, 1 reply; 8+ messages in thread
From: andrzej zaborowski @ 2007-04-02 23:04 UTC (permalink / raw)
To: dsilvers, qemu-devel
Hi,
On 02/04/07, Daniel Silverstone <dsilvers@simtec.co.uk> wrote:
> Hi,
>
> Myself and my colleagues have worked hard and produced a new system
> emulation for qemu for the Simtec BAST board.
>
> The BAST is a Samsung 2410 based board (ARM 9 based SoC, with MMU) with
> various peripherals including a Davicom DM9000 Ethernet port.
>
> The emulation is complete enough to start Simtec's ABLE boot loader
> (downloadable from www.simtec.co.uk) and also is capable of being
> direct-booted with a linux kernel/initrd combination as per the
> versatile etc.
>
> Among other things, the patch needs to add support for OHCI USB systems
> not on PCI, ARM systems where SDRAM isn't at 0 (phys) and MMIO based
> IDE. Naturally this has all been done as generically as made sense at
> the time.
>
> There is one generic fix in the patch which hardly seemed worth breaking
> out on its own. It corrects a bug where QEMU would ignore WIN_DIAGNOSE's
> behaviour for normal drives. It assumed HDDs behaved as CDROMs under
> WIN_DIAGNOSE which is not the case.
>
> Unfortunately I was unable to sensibly separate the patch up because of
> the difficulties which stem from qemu's current source layout. E.g. it
> was hard to split out the MMIO IDE from the rest of the IDE without
> dramatically changing the exported symbol lists.
>
> Hopefully you'll be happy with the whole patch. In particular I've tried
> to isolate the s3c2410x stuff away from the BAST stuff, so that in
> future other 2410x based systems such as the H1940 PDA or the FIC NEO
> 1973 (openmoko?) can be implemented with minimal fuss.
>
> We have a partially complete s3c2410x NAND driver, a partial LCD driver
> and various other bits which we will submit as and when we have them
> done.
We have also implemented emulation of the S3C2410x SoC. I hope we can
merge both implementations to come up with better emulation. Our tree
is accessible at http://svn.openmoko.org/trunk/src/host/qemu-neo1973/
and our main target machine is the FIC Neo1973 which you mention
above. The tree is still heavily a work-in-progress but the processor
part (S3C2410 with on-chip preripherals) is quite mature.
All of the on-chip peripherals described in the S3C2410A User Manual
rev 1.0 except the Watchdog timer and USB Slave are emulated with high
level of detail. The OHCI USB uses the same routine as the PXA2xx
emulator. Things that are tested to work:
OpenMoko firmware from the real device boots as a NAND Flash image.
The OpenMoko rootfs can also be booted off the emulated SD card. We
use the u-boot and kernel images from the original device. Input is
through GPIO buttons or touchscreen connected to the on-chip ADC,
output through on-chip UARTs and LCD. Audio through a codec connected
to on-chip I2C and I2S busses. There is also an SPI-connected
peripheral (can be driven either through the on-chip SPI interface or
GPIO bit-banging). S3C2410 idle mode is supported.
There's no save/restore support.
Apparently there's some code duplication, which is sad but I hope we
can get both machines (BAST and Neo1973) to use common code. Briefly
looking at your patch, the openmoko tree seems to have a more
complete/specs-conformant S3C2410 part.
Regards,
Andrzej
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] Simtec BAST emulation
2007-04-02 23:04 ` andrzej zaborowski
@ 2007-04-03 10:09 ` Daniel Silverstone
2007-04-03 15:01 ` andrzej zaborowski
0 siblings, 1 reply; 8+ messages in thread
From: Daniel Silverstone @ 2007-04-03 10:09 UTC (permalink / raw)
To: balrogg, qemu-devel
On Tue, 2007-04-03 at 01:04 +0200, andrzej zaborowski wrote:
> We have also implemented emulation of the S3C2410x SoC. I hope we can
> merge both implementations to come up with better emulation. Our tree
> is accessible at http://svn.openmoko.org/trunk/src/host/qemu-neo1973/
> and our main target machine is the FIC Neo1973 which you mention
> above. The tree is still heavily a work-in-progress but the processor
> part (S3C2410 with on-chip preripherals) is quite mature.
Perhaps we should work together to get your processor core merged into
QEMU proper? I could work on patching our BAST stuff against your core
and then together we could look at getting it merged.
> All of the on-chip peripherals described in the S3C2410A User Manual
> rev 1.0 except the Watchdog timer and USB Slave are emulated with high
> level of detail. The OHCI USB uses the same routine as the PXA2xx
> emulator.
That sounds excellent. Far further than we had gotten thus-far.
> Things that are tested to work:
> OpenMoko firmware from the real device boots as a NAND Flash image.
Cool. Is the NAND format with, or without OOB?
> The OpenMoko rootfs can also be booted off the emulated SD card. We
> use the u-boot and kernel images from the original device. Input is
> through GPIO buttons or touchscreen connected to the on-chip ADC,
> output through on-chip UARTs and LCD. Audio through a codec connected
> to on-chip I2C and I2S busses.
Out of interest, which codec is it?
> There is also an SPI-connected
> peripheral (can be driven either through the on-chip SPI interface or
> GPIO bit-banging).
*nod*
> S3C2410 idle mode is supported.
Aha, this is wonderful news.
> There's no save/restore support.
Hmm, perhaps we could work on that together.
> Apparently there's some code duplication, which is sad but I hope we
> can get both machines (BAST and Neo1973) to use common code. Briefly
> looking at your patch, the openmoko tree seems to have a more
> complete/specs-conformant S3C2410 part.
Yes, our S3C2410 part was only as far as we needed to get Linux and ABLE
booting on the emulator. Yours is much more mature and really deserves
to be merged once we can get a system emulation in place which you're
happy to offer for merging.
I assume you too have noticed that the longer you leave it before
offering patches for merging, the scarier the diff becomes.
I will take a look at your tree and at how hard it will be to merge the
Simtec board emulation into it.
Thanks,
Daniel.
--
Daniel Silverstone http://www.simtec.co.uk/
PGP mail accepted and encouraged. Key Id: 2BC8 4016 2068 7895
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] Simtec BAST emulation
2007-04-02 17:45 ` Paul Brook
@ 2007-04-03 10:12 ` Daniel Silverstone
2007-04-17 9:51 ` Daniel Silverstone
2007-04-17 9:51 ` Daniel Silverstone
2 siblings, 0 replies; 8+ messages in thread
From: Daniel Silverstone @ 2007-04-03 10:12 UTC (permalink / raw)
To: qemu-devel
On Mon, 2007-04-02 at 18:45 +0100, Paul Brook wrote:
> A few issues with the patch, which I think need to be resolved before it can
> be applied:
> - You're using global structures to store machine state.
> While it's debatable whether you'll ever have more than one s3c2410, I think
> it's definitely still worth allowing for this possibility, and encapsulating
> the state in a structure, like all the other hardware emulation does.
Right, I've basically decided that we're going to go with the OpenMoko
core emulation if it turns out to be sensible. However the global state
comment is a good one. It's one thing I wasn't quite happy with, but in
the end we did it for simplicity since having more than one s3c2410
would be strange.
> - For the device emulation (dm9000 and ide, maybe others) you should use
> pic_set_irq_new, instead of passing a separate set_irq function. Other ARM
> boards already support arbitrary routing of interrupts via hw/arm_pic.[ch].
Right, the interrupt controller on the S3C2410 didn't seem to fit with
the hw/arm_pic stuff, but yes, perhaps the separate set_irq stuff was a
touch heavy handed.
> - usb_ohci_mmap_init should look more like (or even be the same function as)
> usb_ohci_init_pxa.
Aha, I'd not spotted that, thanks.
> > The emulation is complete enough to start Simtec's ABLE boot loader
> > (downloadable from www.simtec.co.uk) and also is capable of being
> > direct-booted with a linux kernel/initrd combination as per the
> > versatile etc.
> What is the licence for ABLE? Would we be able to distribute it with qemu?
Unfortunately I don't think so. However I could ask my boss.
D.
--
Daniel Silverstone http://www.simtec.co.uk/
PGP mail accepted and encouraged. Key Id: 2BC8 4016 2068 7895
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] Simtec BAST emulation
2007-04-03 10:09 ` Daniel Silverstone
@ 2007-04-03 15:01 ` andrzej zaborowski
0 siblings, 0 replies; 8+ messages in thread
From: andrzej zaborowski @ 2007-04-03 15:01 UTC (permalink / raw)
To: dsilvers; +Cc: qemu-devel
Hi,
On 03/04/07, Daniel Silverstone <dsilvers@simtec.co.uk> wrote:
> On Tue, 2007-04-03 at 01:04 +0200, andrzej zaborowski wrote:
> > We have also implemented emulation of the S3C2410x SoC. I hope we can
> > merge both implementations to come up with better emulation. Our tree
> > is accessible at http://svn.openmoko.org/trunk/src/host/qemu-neo1973/
> > and our main target machine is the FIC Neo1973 which you mention
> > above. The tree is still heavily a work-in-progress but the processor
> > part (S3C2410 with on-chip preripherals) is quite mature.
>
> Perhaps we should work together to get your processor core merged into
> QEMU proper? I could work on patching our BAST stuff against your core
> and then together we could look at getting it merged.
Agreed, that would be very nice. I'm going to try to add the watchdog
timer this week and get the S3C2410 part of the tree into some clean
state. The watchdog timer is very low priority but Linux uses it for
rebooting, so let's have it in for completeness as it's not so easy to
get improvements merged into qemu tree later.
My concern with preparing and submitting patches at this moment, or
even syncing the openmoko tree with CVS changes, is that we submitted
patches for PXA2xx SoC processors emulation some two weeks ago and the
S3C2410 uses a number of the same structures as PXA2xx (e.g the NAND
emulator, SD card, I2C framework, some GPIO bits). These patches have
not been merged, but also have not been rejected. Paul Brook (*poke*)
expressed that he is willing to merge them when he has time, and I
know that he will make lots of changes when he's applying them (which
is good), so the openmoko tree will have to be rebased anyway.
>
> > All of the on-chip peripherals described in the S3C2410A User Manual
> > rev 1.0 except the Watchdog timer and USB Slave are emulated with high
> > level of detail. The OHCI USB uses the same routine as the PXA2xx
> > emulator.
>
> That sounds excellent. Far further than we had gotten thus-far.
>
> > Things that are tested to work:
> > OpenMoko firmware from the real device boots as a NAND Flash image.
>
> Cool. Is the NAND format with, or without OOB?
Normally it is with OOB. Here's how it works:
On init, hw/nand.c takes only the manufacturer and chip IDs as
arguments and based on a table of chip IDs it looks up the size of the
chip. Now, if a NAND image was given on commandline with "-mtblock" it
will read and write data to this image, otherwise the initial state of
the memory is filled with 0xff bytes and changes are only stored in
memory. Now, if the size of the image is greater or equal (number of
pages) * (page size + OOB size) then the image is interpreted as page
data interleaved with OOB data. If it's below this value then it is
taken the image contains only page data, and OOB part is malloc()ed,
initially filled with 0xff bytes.
>
> > The OpenMoko rootfs can also be booted off the emulated SD card. We
> > use the u-boot and kernel images from the original device. Input is
> > through GPIO buttons or touchscreen connected to the on-chip ADC,
> > output through on-chip UARTs and LCD. Audio through a codec connected
> > to on-chip I2C and I2S busses.
>
> Out of interest, which codec is it?
It's the Wolfson Microsystems WM8753. The tree also has WM8750.
>
> > There is also an SPI-connected
> > peripheral (can be driven either through the on-chip SPI interface or
> > GPIO bit-banging).
>
> *nod*
>
> > S3C2410 idle mode is supported.
>
> Aha, this is wonderful news.
>
> > There's no save/restore support.
>
> Hmm, perhaps we could work on that together.
This would be very nice.
>
> > Apparently there's some code duplication, which is sad but I hope we
> > can get both machines (BAST and Neo1973) to use common code. Briefly
> > looking at your patch, the openmoko tree seems to have a more
> > complete/specs-conformant S3C2410 part.
>
> Yes, our S3C2410 part was only as far as we needed to get Linux and ABLE
> booting on the emulator. Yours is much more mature and really deserves
> to be merged once we can get a system emulation in place which you're
> happy to offer for merging.
>
> I assume you too have noticed that the longer you leave it before
> offering patches for merging, the scarier the diff becomes.
Yes, but I also notice the way qemu tree is maintained, "release
early, realease often" wouldn't work very well.
>
> I will take a look at your tree and at how hard it will be to merge the
> Simtec board emulation into it.
I hope it's not too difficult, we're trying to use APIs similar to
those in the rest of qemu. Maybe looking at hw/neo1973.c can help
getting some things right if you're willing to rebase the BAST board
to use S3C2410 from openmoko tree. This would very nice as then we
could work with only one implementation of S3C2410.
To quickly get a working Neo1973 emulator, I've put some demo
instructions at http://wiki.openmoko.org/wiki/OpenMoko_under_QEMU
Regards,
Andrzej
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] Simtec BAST emulation
2007-04-02 17:45 ` Paul Brook
2007-04-03 10:12 ` Daniel Silverstone
@ 2007-04-17 9:51 ` Daniel Silverstone
2007-04-17 9:51 ` Daniel Silverstone
2 siblings, 0 replies; 8+ messages in thread
From: Daniel Silverstone @ 2007-04-17 9:51 UTC (permalink / raw)
To: qemu-devel
On Mon, 2007-04-02 at 18:45 +0100, Paul Brook wrote:
> A few issues with the patch, which I think need to be resolved before it can
> be applied:
>
> - You're using global structures to store machine state.
> While it's debatable whether you'll ever have more than one s3c2410, I think
> it's definitely still worth allowing for this possibility, and encapsulating
> the state in a structure, like all the other hardware emulation does.
Yes, I concur, this is my next goal.
> - For the device emulation (dm9000 and ide, maybe others) you should use
> pic_set_irq_new, instead of passing a separate set_irq function. Other ARM
> boards already support arbitrary routing of interrupts via hw/arm_pic.[ch].
pic_set_irq_new appears to be missing from trunk unless I'm mistaken or
confused. However hw/irq.[ch] seemed like a nice place to start, so I've
made the s3c2410x_irq stuff use that, and ported all the other drivers
we wrote to this. It has unfortunately added more global state for the
s3c2410x which I will work on factoring into a new structure next.
> - usb_ohci_mmap_init should look more like (or even be the same function as)
> usb_ohci_init_pxa.
I am now using usb_ohci_init_pxa for this.
> What is the licence for ABLE? Would we be able to distribute it with qemu?
ABLE is not going to be distributable *with* qemu, however it may be
possible to ensure that the licence is such that anyone wishing to use
ABLE with qemu will be allowed to in a free-beer sense by downloading it
from Simtec's website.
Would you mind casting your eye over the attached diff and tell me if I
went the right way with the IRQ stuff? I'll get on with deglobalising
(localising?) the s3c2410x state next.
D.
--
Daniel Silverstone http://www.simtec.co.uk/
PGP mail accepted and encouraged. Key Id: 2BC8 4016 2068 7895
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [Qemu-devel] Simtec BAST emulation
2007-04-02 17:45 ` Paul Brook
2007-04-03 10:12 ` Daniel Silverstone
2007-04-17 9:51 ` Daniel Silverstone
@ 2007-04-17 9:51 ` Daniel Silverstone
2 siblings, 0 replies; 8+ messages in thread
From: Daniel Silverstone @ 2007-04-17 9:51 UTC (permalink / raw)
To: qemu-devel
[-- Attachment #1: Type: text/plain, Size: 258 bytes --]
On Mon, 2007-04-02 at 18:45 +0100, Paul Brook wrote:
[snip]
And now the diff (gosh I'm good at this)
D.
--
Daniel Silverstone http://www.simtec.co.uk/
PGP mail accepted and encouraged. Key Id: 2BC8 4016 2068 7895
[-- Attachment #2: new-irqs.diff --]
[-- Type: text/x-patch, Size: 84607 bytes --]
=== 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-17 09:14:20 +0000
@@ -0,0 +1,59 @@
+/* hw/s3c2410x.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "vl.h"
+#include "s3c2410x.h"
+
+CPUState *s3c_env;
+qemu_irq *s3c_irqs;
+qemu_irq *s3c_eirqs;
+
+/* Initialise a Samsung S3C2410X and all its internal peripherals */
+CPUState *
+s3c2410x_init(int ram_size)
+{
+ CPUState *env;
+ qemu_irq *interrupts, *irq;
+ /* Prepare the ARM 920T */
+ s3c_env = env = cpu_init();
+ cpu_arm_set_model(env, "arm920t");
+ /* S3C2410X memory is always at the same physical location */
+ S3C2410X_DBF("RAM\n");
+ cpu_register_physical_memory(CPU_S3C2410X_RAM, ram_size, IO_MEM_RAM);
+ /* We get a memc */
+ S3C2410X_DBF("memc\n");
+ s3c2410x_memc_init();
+ /* And some interrupts (coo) */
+ S3C2410X_DBF("interrupts\n");
+ s3c_irqs = interrupts = irq = s3c2410x_irq_init(env);
+ /* The clock control allows for idling the CPU */
+ s3c2410x_clkcon_init(env);
+ /* And some GPIO */
+ S3C2410X_DBF("gpio\n");
+ s3c_eirqs = s3c2410x_gpio_init(s3c_irqs);
+ /* RTC for time */
+ s3c2410x_rtc_init();
+ /* And some IIC */
+ s3c2410x_iic_init(interrupts[27]);
+ /* And some timers */
+ s3c2410x_timers_init(interrupts[14]);
+ /* Serial ports */
+ S3C2410X_DBF("serial\n");
+ s3c2410x_serial_init(0, irq[33], irq[32], irq[33+64], irq[32+64]); /* Subsrc interrupts 1 and 0 edge and level */
+ s3c2410x_serial_init(1, irq[36], irq[35], irq[36+64], irq[35+64]); /* Subsrc interrupts 4 and 3 edge and level */
+ s3c2410x_serial_init(2, irq[39], irq[38], irq[39+64], irq[38+64]); /* Subsrc interrupts 7 and 6 edge and level */
+
+ /* S3C2410X SRAM */
+ cpu_register_physical_memory(CPU_S3C2410X_SRAM, 4096, ram_size | IO_MEM_RAM);
+ /* A two port OHCI controller on IRQ 26 */
+ usb_ohci_init_pxa(CPU_S3C2410X_OHCI, 2, -1, interrupts[26]);
+ return env;
+}
+
=== added file 'hw/s3c2410x.h'
--- hw/s3c2410x.h 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x.h 2007-04-17 09:10:53 +0000
@@ -0,0 +1,374 @@
+/* s3c2410x/regs.h
+ *
+ * Samsung s3c2410x cpu register definitions
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#ifndef S3C2410X_H
+#define S3C2410X_H 1
+
+#include "hw/irq.h"
+
+/* S3C2410X SoC IDs */
+
+#define CPU_S3C2410X_IDENT_S3C2410X 0x32410000
+#define CPU_S3C2410X_IDENT_S3C2410A 0x32410002
+
+/* all defines are prefixed with CPU_S3C2410X_ */
+
+#define CPU_S3C2410X_REG(x) (0x48000000 + (x))
+
+#define CPU_S3C2410X_CS0 (0x00000000)
+#define CPU_S3C2410X_CS1 (0x08000000)
+#define CPU_S3C2410X_CS2 (0x10000000)
+#define CPU_S3C2410X_CS3 (0x18000000)
+#define CPU_S3C2410X_CS4 (0x20000000)
+#define CPU_S3C2410X_CS5 (0x28000000)
+#define CPU_S3C2410X_RAM (0x30000000)
+#define CPU_S3C2410X_SRAM (0x40000000)
+#define CPU_S3C2410X_OHCI (0x49000000)
+
+/* Clock control */
+#define CPU_S3C2410X_CLKCON 0x4C000000
+/* Lock time RW */
+#define CPU_S3C2410X_REG_LOCKTIME 0
+/* MPLL Control RW */
+#define CPU_S3C2410X_REG_MPLLCON 1
+/* UPLL Control RW */
+#define CPU_S3C2410X_REG_UPLLCON 2
+/* Clock Generator Control RW */
+#define CPU_S3C2410X_REG_CLKCON 3
+/* Slow Clock Control RW */
+#define CPU_S3C2410X_REG_CLKSLOW 4
+/* Clock divider control RW */
+#define CPU_S3C2410X_REG_CLKDIVN 5
+/* CLKCON IDLE */
+#define CPU_S3C2410X_REG_CLKCON_IDLE (1<<2)
+
+/* bus width, and wait state control */
+#define CPU_S3C2410X_BWSCON CPU_S3C2410X_REG(0x0000)
+
+/* bank zero config - note, pinstrapped from OM pins! */
+#define CPU_S3C2410X_BWSCON_DW0_16 (1<<1)
+#define CPU_S3C2410X_BWSCON_DW0_32 (2<<1)
+
+/* bank one configs */
+#define CPU_S3C2410X_BWSCON_DW1_8 (0<<4)
+#define CPU_S3C2410X_BWSCON_DW1_16 (1<<4)
+#define CPU_S3C2410X_BWSCON_DW1_32 (2<<4)
+#define CPU_S3C2410X_BWSCON_WS1 (1<<6)
+#define CPU_S3C2410X_BWSCON_ST1 (1<<7)
+
+/* bank 2 configurations */
+#define CPU_S3C2410X_BWSCON_DW2_8 (0<<8)
+#define CPU_S3C2410X_BWSCON_DW2_16 (1<<8)
+#define CPU_S3C2410X_BWSCON_DW2_32 (2<<8)
+#define CPU_S3C2410X_BWSCON_WS2 (1<<10)
+#define CPU_S3C2410X_BWSCON_ST2 (1<<11)
+
+/* bank 3 configurations */
+#define CPU_S3C2410X_BWSCON_DW3_8 (0<<12)
+#define CPU_S3C2410X_BWSCON_DW3_16 (1<<12)
+#define CPU_S3C2410X_BWSCON_DW3_32 (2<<12)
+#define CPU_S3C2410X_BWSCON_WS3 (1<<14)
+#define CPU_S3C2410X_BWSCON_ST3 (1<<15)
+
+/* bank 4 configurations */
+#define CPU_S3C2410X_BWSCON_DW4_8 (0<<16)
+#define CPU_S3C2410X_BWSCON_DW4_16 (1<<16)
+#define CPU_S3C2410X_BWSCON_DW4_32 (2<<16)
+#define CPU_S3C2410X_BWSCON_WS4 (1<<18)
+#define CPU_S3C2410X_BWSCON_ST4 (1<<19)
+
+/* bank 5 configurations */
+#define CPU_S3C2410X_BWSCON_DW5_8 (0<<20)
+#define CPU_S3C2410X_BWSCON_DW5_16 (1<<20)
+#define CPU_S3C2410X_BWSCON_DW5_32 (2<<20)
+#define CPU_S3C2410X_BWSCON_WS5 (1<<22)
+#define CPU_S3C2410X_BWSCON_ST5 (1<<23)
+
+/* bank 6 configurations */
+#define CPU_S3C2410X_BWSCON_DW6_8 (0<<24)
+#define CPU_S3C2410X_BWSCON_DW6_16 (1<<24)
+#define CPU_S3C2410X_BWSCON_DW6_32 (2<<24)
+#define CPU_S3C2410X_BWSCON_WS6 (1<<26)
+#define CPU_S3C2410X_BWSCON_ST6 (1<<27)
+
+/* bank 7 configurations */
+#define CPU_S3C2410X_BWSCON_DW7_8 (0<<28)
+#define CPU_S3C2410X_BWSCON_DW7_16 (1<<28)
+#define CPU_S3C2410X_BWSCON_DW7_32 (2<<28)
+#define CPU_S3C2410X_BWSCON_WS7 (1<<30)
+#define CPU_S3C2410X_BWSCON_ST7 (1<<31)
+
+
+/* memory set (rom, ram) */
+#define CPU_S3C2410X_BANKCON0 CPU_S3C2410X_REG(0x0004)
+#define CPU_S3C2410X_BANKCON1 CPU_S3C2410X_REG(0x0008)
+#define CPU_S3C2410X_BANKCON2 CPU_S3C2410X_REG(0x000C)
+#define CPU_S3C2410X_BANKCON3 CPU_S3C2410X_REG(0x0010)
+#define CPU_S3C2410X_BANKCON4 CPU_S3C2410X_REG(0x0014)
+#define CPU_S3C2410X_BANKCON5 CPU_S3C2410X_REG(0x0018)
+#define CPU_S3C2410X_BANKCON6 CPU_S3C2410X_REG(0x001C)
+#define CPU_S3C2410X_BANKCON7 CPU_S3C2410X_REG(0x0020)
+
+/* bank configuration registers */
+
+#define CPU_S3C2410X_BANKCON_PMCnorm (0x00)
+#define CPU_S3C2410X_BANKCON_PMC4 (0x01)
+#define CPU_S3C2410X_BANKCON_PMC8 (0x02)
+#define CPU_S3C2410X_BANKCON_PMC16 (0x03)
+
+/* bank configurations for banks 0..7, note banks
+ * 6 and 7 have differnt configurations depending on
+ * the memory type bits! */
+
+#define CPU_S3C2410X_BANKCON_Tacp2 (0x0 << 2)
+#define CPU_S3C2410X_BANKCON_Tacp3 (0x1 << 2)
+#define CPU_S3C2410X_BANKCON_Tacp4 (0x2 << 2)
+#define CPU_S3C2410X_BANKCON_Tacp6 (0x3 << 2)
+
+#define CPU_S3C2410X_BANKCON_Tcah0 (0x0 << 4)
+#define CPU_S3C2410X_BANKCON_Tcah1 (0x1 << 4)
+#define CPU_S3C2410X_BANKCON_Tcah2 (0x2 << 4)
+#define CPU_S3C2410X_BANKCON_Tcah4 (0x3 << 4)
+
+#define CPU_S3C2410X_BANKCON_Tcoh0 (0x0 << 6)
+#define CPU_S3C2410X_BANKCON_Tcoh1 (0x1 << 6)
+#define CPU_S3C2410X_BANKCON_Tcoh2 (0x2 << 6)
+#define CPU_S3C2410X_BANKCON_Tcoh4 (0x3 << 6)
+
+#define CPU_S3C2410X_BANKCON_Tacc1 (0x0 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc2 (0x1 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc3 (0x2 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc4 (0x3 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc6 (0x4 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc8 (0x5 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc10 (0x6 << 8)
+#define CPU_S3C2410X_BANKCON_Tacc14 (0x7 << 8)
+
+#define CPU_S3C2410X_BANKCON_Tcos0 (0x0 << 11)
+#define CPU_S3C2410X_BANKCON_Tcos1 (0x1 << 11)
+#define CPU_S3C2410X_BANKCON_Tcos2 (0x2 << 11)
+#define CPU_S3C2410X_BANKCON_Tcos4 (0x3 << 11)
+
+#define CPU_S3C2410X_BANKCON_Tacs0 (0x0 << 13)
+#define CPU_S3C2410X_BANKCON_Tacs1 (0x1 << 13)
+#define CPU_S3C2410X_BANKCON_Tacs2 (0x2 << 13)
+#define CPU_S3C2410X_BANKCON_Tacs4 (0x3 << 13)
+
+#define CPU_S3C2410X_BANKCON_SRAM (0x0 << 15)
+#define CPU_S3C2410X_BANKCON_SDRAM (0x3 << 15)
+
+/* next bits only for SDRAM in 6,7 */
+#define CPU_S3C2410X_BANKCON_Trdc2 (0x00 << 2)
+#define CPU_S3C2410X_BANKCON_Trdc3 (0x01 << 2)
+#define CPU_S3C2410X_BANKCON_Trdc4 (0x02 << 2)
+
+/* control column address select */
+#define CPU_S3C2410X_BANKCON_SCANb8 (0x00 << 0)
+#define CPU_S3C2410X_BANKCON_SCANb9 (0x01 << 0)
+#define CPU_S3C2410X_BANKCON_SCANb10 (0x02 << 0)
+
+#define CPU_S3C2410X_REFRESH CPU_S3C2410X_REG(0x0024)
+#define CPU_S3C2410X_BANKSIZE CPU_S3C2410X_REG(0x0028)
+#define CPU_S3C2410X_MRSRB6 CPU_S3C2410X_REG(0x002C)
+#define CPU_S3C2410X_MRSRB7 CPU_S3C2410X_REG(0x0030)
+
+/* mode select register(s) */
+
+#define CPU_S3C2410X_MRSRB_CL1 (0x00 << 4)
+#define CPU_S3C2410X_MRSRB_CL2 (0x02 << 4)
+#define CPU_S3C2410X_MRSRB_CL3 (0x03 << 4)
+
+/* bank size register */
+#define CPU_S3C2410X_BANKSIZE_128M (0x2 << 0)
+#define CPU_S3C2410X_BANKSIZE_64M (0x1 << 0)
+#define CPU_S3C2410X_BANKSIZE_32M (0x0 << 0)
+#define CPU_S3C2410X_BANKSIZE_16M (0x7 << 0)
+#define CPU_S3C2410X_BANKSIZE_8M (0x6 << 0)
+#define CPU_S3C2410X_BANKSIZE_4M (0x5 << 0)
+#define CPU_S3C2410X_BANKSIZE_2M (0x4 << 0)
+
+/* interrupt controller */
+
+#define CPU_S3C2410X_SRCPND CPU_S3C2410X_REG(0x02000000)
+#define CPU_S3C2410X_INTMOD CPU_S3C2410X_REG(0x02000004)
+#define CPU_S3C2410X_INTMSK CPU_S3C2410X_REG(0x02000008)
+#define CPU_S3C2410X_PRIORITY CPU_S3C2410X_REG(0x0200000C)
+#define CPU_S3C2410X_INTPND CPU_S3C2410X_REG(0x02000010)
+#define CPU_S3C2410X_INTOFFSET CPU_S3C2410X_REG(0x02000014)
+#define CPU_S3C2410X_SUBSRCPND CPU_S3C2410X_REG(0x02000018)
+#define CPU_S3C2410X_INTSUBMSK CPU_S3C2410X_REG(0x0200001C)
+
+/* serial ports */
+
+#define CPU_S3C2410X_SERIAL_BASE(port) (0x50000000 + (port * 0x4000))
+/* Line control RW WORD */
+#define CPU_S3C2410X_SERIAL_ULCON 0x00
+/* General control RW WORD */
+#define CPU_S3C2410X_SERIAL_UCON 0x04
+/* Fifo control RW WORD */
+#define CPU_S3C2410X_SERIAL_UFCON 0x08
+/* Modem control RW WORD */
+#define CPU_S3C2410X_SERIAL_UMCON 0x0C
+/* TX/RX Status RO WORD */
+#define CPU_S3C2410X_SERIAL_UTRSTAT 0x10
+/* Receive Error Status RO WORD */
+#define CPU_S3C2410X_SERIAL_UERSTAT 0x14
+/* FiFo Status RO WORD */
+#define CPU_S3C2410X_SERIAL_UFSTAT 0x18
+/* Modem Status RO WORD */
+#define CPU_S3C2410X_SERIAL_UMSTAT 0x1C
+/* TX buffer WR BYTE */
+#define CPU_S3C2410X_SERIAL_UTXH 0x20
+/* RX buffer RO BYTE */
+#define CPU_S3C2410X_SERIAL_URXH 0x24
+/* BAUD Divisor RW WORD */
+#define CPU_S3C2410X_SERIAL_UBRDIV 0x28
+
+/* LCD */
+#define CPU_S3C2410X_LCD_BASE 0x4D000000
+
+/* IIC */
+#define CPU_S3C2410X_IIC_BASE 0x54000000
+
+/* Watchdog */
+#define CPU_S3C2410X_WDOG_BASE 0x53000000
+
+/* NAND */
+#define CPU_S3C2410X_NAND_BASE 0x4E000000
+
+/* GPIO */
+#define CPU_S3C2410X_GPIO_BASE 0x56000000
+
+/* Interrupt controller */
+#define CPU_S3C2410X_IRQ_BASE 0x4A000000
+/* IRQ request status RW WORD */
+#define CPU_S3C2410X_IRQ_SRCPND 0
+/* Interrupt mode control WR WORD */
+#define CPU_S3C2410X_IRQ_INTMOD 1
+/* Interrupt mask control RW WORD */
+#define CPU_S3C2410X_IRQ_INTMSK 2
+/* IRQ priority control WR WORD */
+#define CPU_S3C2410X_IRQ_PRIORITY 3
+/* Interrupt request status RW WORD */
+#define CPU_S3C2410X_IRQ_INTPND 4
+/* Interrupt request source offset RO WORD */
+#define CPU_S3C2410X_IRQ_OFFSET 5
+/* Sub-source pending RW WORD */
+#define CPU_S3C2410X_IRQ_SUBSRCPND 6
+/* Interrupt sub-mask RW WORD */
+#define CPU_S3C2410X_IRQ_INTSUBMSK 7
+
+/* Timers */
+
+#define CPU_S3C2410X_TIMERS_BASE 0x51000000
+/* Timer configuration 0 */
+#define CPU_S3C2410X_TIMERS_TCFG0 0
+/* Timer configuration 1 */
+#define CPU_S3C2410X_TIMERS_TCFG1 1
+/* Timer control */
+#define CPU_S3C2410X_TIMERS_TCON 2
+/* Timer count buffer 0 */
+#define CPU_S3C2410X_TIMERS_TCNTB0 3
+/* Timer compare buffer 0 */
+#define CPU_S3C2410X_TIMERS_TCMPB0 4
+/* Timer count observation 0 */
+#define CPU_S3C2410X_TIMERS_TCNTO0 5
+/* Timer count buffer 1 */
+#define CPU_S3C2410X_TIMERS_TCNTB1 6
+/* Timer compare buffer 1 */
+#define CPU_S3C2410X_TIMERS_TCMPB1 7
+/* Timer count observation 1 */
+#define CPU_S3C2410X_TIMERS_TCNTO1 8
+/* Timer count buffer 2 */
+#define CPU_S3C2410X_TIMERS_TCNTB2 9
+/* Timer compare buffer 2 */
+#define CPU_S3C2410X_TIMERS_TCMPB2 10
+/* Timer count observation 2 */
+#define CPU_S3C2410X_TIMERS_TCNTO2 11
+/* Timer count buffer 3 */
+#define CPU_S3C2410X_TIMERS_TCNTB3 12
+/* Timer compare buffer 3 */
+#define CPU_S3C2410X_TIMERS_TCMPB3 13
+/* Timer count observation 3 */
+#define CPU_S3C2410X_TIMERS_TCNTO3 14
+/* Timer count buffer 4 */
+#define CPU_S3C2410X_TIMERS_TCNTB4 15
+/* Timer count observation 4 */
+#define CPU_S3C2410X_TIMERS_TCNTO4 16
+
+/* Real time clock */
+#define CPU_S3C2410X_RTC_BASE 0x57000040
+/* RTC Control RW Byte */
+#define CPU_S3C3410X_REG_RTCCON 0
+/* Tick time count RW Byte */
+#define CPU_S3C2410X_REG_TICNT 1
+/* RTC Alarm Control RW Byte */
+#define CPU_S3C2410X_REG_RTCALM 4
+/* Alarm second */
+#define CPU_S3C2410X_REG_ALMSEC 5
+/* Alarm minute */
+#define CPU_S3C2410X_REG_ALMMIN 6
+/* Alarm hour */
+#define CPU_S3C2410X_REG_ALMHOUR 7
+/* Alarm day */
+#define CPU_S3C2410X_REG_ALMDATE 8
+/* Alarm month */
+#define CPU_S3C2410X_REG_ALMMON 9
+/* Alarm year */
+#define CPU_S3C2410X_REG_ALMYEAR 10
+/* RTC Round Reset */
+#define CPU_S3C2410X_REG_RTCRST 11
+/* BCD Second */
+#define CPU_S3C2410X_REG_BCDSEC 12
+/* BCD Minute */
+#define CPU_S3C2410X_REG_BCDMIN 13
+/* BCD Hour */
+#define CPU_S3C2410X_REG_BCDHOUR 14
+/* BCD Day */
+#define CPU_S3C2410X_REG_BCDDATE 15
+/* BCD Day of week */
+#define CPU_S3C2410X_REG_BCDDAY 16
+/* BCD Month */
+#define CPU_S3C2410X_REG_BCDMON 17
+/* BCD Year */
+#define CPU_S3C2410X_REG_BCDYEAR 18
+
+/* IRQ state */
+extern qemu_irq *s3c_irqs;
+
+/* Functions */
+CPUState *s3c2410x_init(int ram_size);
+
+void s3c2410x_memc_init(void);
+qemu_irq *s3c2410x_irq_init(CPUState *env);
+qemu_irq *s3c2410x_gpio_init(qemu_irq *real_irqs);
+void s3c2410x_serial_init(int port, qemu_irq tx_irq, qemu_irq rx_irq, qemu_irq tx_level, qemu_irq rx_level);
+void s3c2410x_clkcon_init(CPUState *ce);
+void s3c2410x_timers_init(qemu_irq timer4_irq);
+void s3c2410x_iic_init(qemu_irq iic_irq);
+void s3c2410x_rtc_init(void);
+void s3c2410x_lcd_init(void);
+
+int s3c2410_nand_load(const char *fname,
+ unsigned int id1, unsigned id2,
+ unsigned int oob);
+
+#ifdef DEBUG_S3C2410X_INLINE
+#define S3C2410X_DBF_STREAM stdout
+#else
+#define S3C2410X_DBF_STREAM stderr
+#endif
+#if defined(DEBUG_S3C2410X) || 0
+#define S3C2410X_DBF(X...) fprintf(S3C2410X_DBF_STREAM,"S3C2410X:" X)
+#else
+#define S3C2410X_DBF(X...) if(0) (fprintf)(S3C2410X_DBF_STREAM, X)
+#endif
+
+#endif /* S3C2410X_H */
=== added file 'hw/s3c2410x_clkcon.c'
--- hw/s3c2410x_clkcon.c 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_clkcon.c 2007-04-16 21:51:37 +0000
@@ -0,0 +1,79 @@
+/* hw/s3c2410x_clkcon.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "vl.h"
+#include "s3c2410x.h"
+
+CPUState *env;
+
+static uint32_t s3c2410x_clkcon_reg[6];
+#define CR(X) s3c2410x_clkcon_reg[X]
+
+static void
+s3c2410x_clkcon_write_f(void *opaque_ignored, target_phys_addr_t addr_, uint32_t value)
+{
+ int addr = (addr_ & 0x1F) >> 2;
+ int idle_rising_edge = 0;
+ if (addr < 0 || addr > 5) addr = 5;
+
+ S3C2410X_DBF("Write CLKCON[%02x] = %08x\n", addr_&0xFF, value);
+
+ if( addr == CPU_S3C2410X_REG_CLKCON ) {
+ if( !(s3c2410x_clkcon_reg[addr] & CPU_S3C2410X_REG_CLKCON_IDLE) &&
+ (value & CPU_S3C2410X_REG_CLKCON_IDLE) ) idle_rising_edge = 1;
+ }
+ s3c2410x_clkcon_reg[addr] = value;
+ if( idle_rising_edge ) {
+ S3C2410X_DBF("CLKCON: Idling CPU\n");
+ env->exception_index = EXCP_HLT;
+ env->halted = 1;
+ cpu_loop_exit();
+ }
+}
+
+static uint32_t
+s3c2410x_clkcon_read_f(void *opaque_ignored, target_phys_addr_t addr_)
+{
+ int addr = (addr_ & 0x1F) >> 2;
+ if (addr < 0 || addr > 5) addr = 5;
+ S3C2410X_DBF("Read CLKCON[%d]\n", addr);
+ return s3c2410x_clkcon_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c2410x_clkcon_read[] = {
+ &s3c2410x_clkcon_read_f,
+ &s3c2410x_clkcon_read_f,
+ &s3c2410x_clkcon_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c2410x_clkcon_write[] = {
+ &s3c2410x_clkcon_write_f,
+ &s3c2410x_clkcon_write_f,
+ &s3c2410x_clkcon_write_f,
+};
+
+
+void
+s3c2410x_clkcon_init(CPUState *ce)
+{
+ int tag;
+
+ tag = cpu_register_io_memory(0, s3c2410x_clkcon_read, s3c2410x_clkcon_write, 0);
+ cpu_register_physical_memory(CPU_S3C2410X_CLKCON, 6*4, tag);
+
+ CR(0) = 0x00FFFFFF;
+ CR(1) = 0x0005C080;
+ CR(2) = 0x00028080;
+ CR(3) = 0x0007FFF0;
+ CR(4) = 0x00000004;
+ CR(5) = 0x00000000;
+
+ env = ce;
+}
=== added file 'hw/s3c2410x_gpio.c'
--- hw/s3c2410x_gpio.c 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_gpio.c 2007-04-16 22:15:41 +0000
@@ -0,0 +1,161 @@
+/* hw/s3c2410x_gpio.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "vl.h"
+#include "s3c2410x.h"
+#include "hw/irq.h"
+
+static uint32_t s3c2410x_gpio_reg[47];
+
+#define EINT_MASK (0xA4)
+#define EINT_PEND (0xA8)
+#define GPR(P) s3c2410x_gpio_reg[P>>2]
+
+static void
+s3c2410x_gpio_propogate_eint(qemu_irq *real_irqs)
+{
+ uint32_t ints, i;
+ S3C2410X_DBF("EINT: Propogating to IRQ\n");
+ ints = GPR(EINT_PEND) & ~GPR(EINT_MASK);
+ /* EINT0 - EINT3 are INT0 - INT3 */
+ for(i=0; i < 4; ++i)
+ qemu_set_irq(real_irqs[i], (ints&(1<<i))?1:0);
+ /* EINT4 - EINT7 are INT4 */
+ qemu_set_irq(real_irqs[4], (ints&0xf0)?1:0);
+ /* EINT8 - EINT23 are INT5 */
+ qemu_set_irq(real_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)
+{
+ qemu_irq *real_irqs = (qemu_irq *)opaque;
+ int addr = (addr_ >> 2) & 0x3f;
+ if (addr < 0 || addr > 47) addr = 47;
+
+ if (addr == (EINT_MASK>>2)) value &= ~0xf; /* cannot mask EINT0-EINT3 */
+ S3C2410X_DBF("Write GPIO[%02x] = %08x\n",addr<<2, value);
+ if (addr == (EINT_PEND>>2))
+ s3c2410x_gpio_reg[addr] &= ~value;
+ else {
+ if (addr < (0x80/4) && (addr_ & 0xf) == 0x04) {
+ uint32_t mask = gpio_con_to_mask(s3c2410x_gpio_reg[addr-1]);
+
+ value &= mask;
+
+ s3c2410x_gpio_reg[addr] &= ~mask;
+ s3c2410x_gpio_reg[addr] |= value;
+ } else
+ s3c2410x_gpio_reg[addr] = value;
+ }
+
+ if ((addr == (EINT_MASK)>>2) || (addr == (EINT_PEND)>>2)) {
+ /* A write to the EINT regs leads us to determine the interrupts to propagate */
+ s3c2410x_gpio_propogate_eint(real_irqs);
+ }
+}
+
+static uint32_t
+s3c2410x_gpio_read_f(void *opaque_ignored, target_phys_addr_t addr_)
+{
+ int addr = (addr_ >> 2) & 0x3f;
+ if (addr_ == 0x560000b0) return CPU_S3C2410X_IDENT_S3C2410A;
+ if (addr < 0 || addr > 47) addr = 47;
+ /* If IIC pins are wired to GPE, and GPE is on input mode, pretend the IIC is pulled high */
+ if (addr == 0x44>>2) {
+ /* GPEDAT read. */
+ uint32_t ret = s3c2410x_gpio_reg[addr];
+ if ((s3c2410x_gpio_reg[15] & 3<<28) == 0) ret |= 1 << 14;
+ if ((s3c2410x_gpio_reg[15] & 3<<30) == 0) ret |= 1 << 15;
+ S3C2410X_DBF("GPIO read of GPE, returning 0x%08x\n", ret);
+ return ret;
+ }
+ S3C2410X_DBF("Read GPIO[%02x] => 0x%08x\n",addr<<2, s3c2410x_gpio_reg[addr]);
+ return s3c2410x_gpio_reg[addr];
+}
+
+
+static CPUReadMemoryFunc *s3c2410x_gpio_read[] = {
+ &s3c2410x_gpio_read_f,
+ &s3c2410x_gpio_read_f,
+ &s3c2410x_gpio_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c2410x_gpio_write[] = {
+ &s3c2410x_gpio_write_f,
+ &s3c2410x_gpio_write_f,
+ &s3c2410x_gpio_write_f,
+};
+
+static void
+s3c2410x_gpio_irq_handler(void *opaque, int n, int level)
+{
+ qemu_irq *real_irqs = (qemu_irq *)opaque;
+ if (level)
+ GPR(EINT_PEND) |= (1<<n);
+ s3c2410x_gpio_propogate_eint(real_irqs);
+}
+
+qemu_irq *
+s3c2410x_gpio_init(qemu_irq *real_irqs)
+{
+ /* 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, real_irqs);
+ 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 */
+ return qemu_allocate_irqs(s3c2410x_gpio_irq_handler, real_irqs, 24);
+}
=== added file 'hw/s3c2410x_iic.c'
--- hw/s3c2410x_iic.c 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_iic.c 2007-04-17 09:16:02 +0000
@@ -0,0 +1,151 @@
+/* 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
+ */
+
+//#define DEBUG_S3C2410X
+
+#include "vl.h"
+#include "s3c2410x.h"
+#include "s3c24xx/regs-iic.h"
+
+static uint32_t s3c2410x_iic_reg[4];
+
+#undef S3C2410_IICREG
+#define S3C2410_IICREG(x) (x)
+
+static void
+s3c2410x_iic_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+ qemu_irq iic_irq = (qemu_irq)opaque;
+ int addr = (addr_ & 0xf);
+
+ S3C2410X_DBF("Write IIC[%02x] = %08x\n", addr, value);
+
+
+ switch (addr) {
+ case S3C2410_IICCON:
+ value |= (s3c2410x_iic_reg[0] & S3C2410_IICCON_IRQPEND);
+ s3c2410x_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 */
+ s3c2410x_iic_reg[1] = value;
+
+ s3c2410x_iic_reg[0] |= S3C2410_IICCON_IRQPEND; /* Claim an interrupt */
+
+ switch (s3c2410x_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(iic_irq, 1);
+ }
+ break;
+
+ case S3C2410_IICDS:
+ /* write to data register */
+ s3c2410x_iic_reg[addr >> 2] = 0xff;
+ break;
+
+ default:
+ s3c2410x_iic_reg[addr >> 2] = value;
+ }
+}
+
+static const char *
+decode_iicstat_mode(uint32_t mode)
+{
+ switch (mode & S3C2410_IICSTAT_MODEMASK) {
+ case S3C2410_IICSTAT_MASTER_RX:
+ return "MasterRX";
+ case S3C2410_IICSTAT_MASTER_TX:
+ return "MasterTX";
+ case S3C2410_IICSTAT_SLAVE_RX:
+ return "SlaveRX";
+ case S3C2410_IICSTAT_SLAVE_TX:
+ return "SlaveTX";
+ }
+
+ return "";
+}
+
+static uint32_t
+s3c2410x_iic_read_f(void *opaque_ignored, target_phys_addr_t addr_)
+{
+ int addr = (addr_ & 0xf);
+ uint32_t val;
+
+ if (addr < 0 || addr > 12) addr = 12;
+
+ val = s3c2410x_iic_reg[addr >> 2];
+
+ S3C2410X_DBF("Read IIC[%02x] => %02x\n", addr, val);
+
+ switch (addr) {
+ case S3C2410_IICCON:
+ S3C2410X_DBF("Read: IICCON: AckEn %d, TxDiv %d, IrqEn %d, IrqPend %d, Scale %d\n",
+ (val & S3C2410_IICCON_ACKEN) ? 1 : 0,
+ (val & S3C2410_IICCON_TXDIV_512) ? 512 : 16,
+ (val & S3C2410_IICCON_IRQEN) ? 1 : 0,
+ (val & S3C2410_IICCON_IRQPEND) ? 1 : 0,
+ (val & S3C2410_IICCON_SCALEMASK));
+ break;
+
+ case S3C2410_IICSTAT:
+ S3C2410X_DBF("Read: IICSTAT: Mode %s, BusBusy %d, TxRxEn %d, Arb %d, Slave %d, Addr0 %d, LBit %d\n",
+ decode_iicstat_mode(val),
+ (val & S3C2410_IICSTAT_BUSBUSY) ? 1 : 0,
+ (val & S3C2410_IICSTAT_TXRXEN) ? 1 : 0,
+ (val & S3C2410_IICSTAT_ARBITR) ? 1 : 0,
+ (val & S3C2410_IICSTAT_ASSLAVE) ? 1 : 0,
+ (val & S3C2410_IICSTAT_ADDR0) ? 1 : 0,
+ (val & S3C2410_IICSTAT_LASTBIT));
+ }
+
+ return val;
+}
+
+
+static CPUReadMemoryFunc *s3c2410x_iic_read[] = {
+ &s3c2410x_iic_read_f,
+ &s3c2410x_iic_read_f,
+ &s3c2410x_iic_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c2410x_iic_write[] = {
+ &s3c2410x_iic_write_f,
+ &s3c2410x_iic_write_f,
+ &s3c2410x_iic_write_f,
+};
+
+
+void
+s3c2410x_iic_init(qemu_irq iic_irq)
+{
+ /* Samsung S3C2410X IIC registration. */
+ int tag = cpu_register_io_memory(0, s3c2410x_iic_read, s3c2410x_iic_write, iic_irq);
+ cpu_register_physical_memory(CPU_S3C2410X_IIC_BASE, 4*4, tag);
+ s3c2410x_iic_reg[0] = 0;
+ s3c2410x_iic_reg[1] = 0;
+ s3c2410x_iic_reg[2] = 0;
+ s3c2410x_iic_reg[3] = 0;
+
+}
=== added file 'hw/s3c2410x_irq.c'
--- hw/s3c2410x_irq.c 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_irq.c 2007-04-17 09:15:29 +0000
@@ -0,0 +1,183 @@
+/* hw/s3c2410x_irq.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "vl.h"
+#include "s3c2410x.h"
+
+static uint32_t s3c2410x_irq_main_level, s3c2410x_irq_subsrc_level;
+static uint32_t s3c2410x_irq_reg[8];
+#define IR(X) s3c2410x_irq_reg[X]
+
+static void
+__s3c2410x_percolate_interrupt(CPUState *cpu_env)
+{
+ /* Take the status of the srcpnd register, percolate it through, raise to CPU if necessary */
+ uint32_t ints = (s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] &
+ ~s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTMSK]);
+ int fsb = ffs(ints);
+
+ /* TODO: Priority encoder could go here */
+ if (ints & s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTMOD]) {
+ /* Detected a FIQ */
+ S3C2410X_DBF("IRQ: Setting FIQ on CPU\n");
+ cpu_interrupt(cpu_env, CPU_INTERRUPT_FIQ);
+ return;
+ } else {
+ /* No FIQ here today */
+ cpu_reset_interrupt(cpu_env, CPU_INTERRUPT_FIQ);
+ }
+ /* No FIQ, do we have an IRQ */
+ if (fsb) {
+ if ((s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTPND] == 0) ||
+ (s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTPND] > 1<<(fsb-1))) {
+ /* Current INTPND is lower priority than fsb of ints (or empty) */
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTPND] = 1<<(fsb-1);
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_OFFSET] = fsb-1;
+ }
+ } else {
+ /* No FSB, thus no IRQ, thus nothing to see yet */
+ }
+
+ if (s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTPND] != 0) {
+ S3C2410X_DBF("IRQ: Setting IRQ on CPU\n");
+ cpu_interrupt(cpu_env, CPU_INTERRUPT_HARD);
+ } else {
+ cpu_reset_interrupt(cpu_env, CPU_INTERRUPT_HARD);
+ }
+}
+
+static void
+s3c2410x_percolate_subsrc_interrupt(CPUState *cpu_env)
+{
+ uint32_t ints;
+
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= s3c2410x_irq_main_level;
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] |= s3c2410x_irq_subsrc_level;
+
+ ints = (s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] &
+ ~s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTSUBMSK]);
+
+ /* If UART0 has asserted, raise that */
+ S3C2410X_DBF("SUBSRCPND 0x%08x\n", s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND]);
+ S3C2410X_DBF("INTSUBMSK 0x%08x\n", s3c2410x_irq_reg[CPU_S3C2410X_IRQ_INTSUBMSK]);
+ S3C2410X_DBF(" => Pending Subsource interrupts: %08x\n", ints);
+ if( ints & 0x7 ) {
+ S3C2410X_DBF("IRQ: Percolating UART0 subsource\n");
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<28);
+ }
+ /* Ditto UART1 */
+ if( ints & 0x7<<3 ) s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<23);
+ /* Ditto UART2 */
+ if( ints & 0x7<<6 ) s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= (1<<15);
+ /* And percolate it through */
+ __s3c2410x_percolate_interrupt(cpu_env);
+}
+
+static void
+s3c2410x_irq_write_f(void *opaque, target_phys_addr_t addr_, uint32_t value)
+{
+ CPUState *env = (CPUState *)opaque;
+ int addr = (addr_ >> 2) & 7;
+ S3C2410X_DBF("Write IRQ[%02x] = %08x\n",addr<<2, value);
+ if (addr == CPU_S3C2410X_IRQ_SRCPND ||
+ addr == CPU_S3C2410X_IRQ_INTPND ||
+ addr == CPU_S3C2410X_IRQ_SUBSRCPND) {
+ s3c2410x_irq_reg[addr] &= ~value;
+ } else {
+ s3c2410x_irq_reg[addr] = value;
+ }
+
+ /* Start at the subsrc irqs and percolate from there */
+ s3c2410x_percolate_subsrc_interrupt(env);
+}
+
+static uint32_t
+s3c2410x_irq_read_f(void *opaque_ignored, target_phys_addr_t addr_)
+{
+ int addr = (addr_ >> 2) & 0x7;
+ S3C2410X_DBF("Read IRQ[%02x] => 0x%08x\n",addr<<2, s3c2410x_irq_reg[addr]);
+ return s3c2410x_irq_reg[addr];
+}
+
+
+static CPUReadMemoryFunc *s3c2410x_irq_read[] = {
+ &s3c2410x_irq_read_f,
+ &s3c2410x_irq_read_f,
+ &s3c2410x_irq_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c2410x_irq_write[] = {
+ &s3c2410x_irq_write_f,
+ &s3c2410x_irq_write_f,
+ &s3c2410x_irq_write_f,
+};
+
+static void
+s3c2410x_irq_set_interrupt_level(CPUState *env, int irq_num, int level, int set_level)
+{
+ S3C2410X_DBF("IRQ: Set level for %d to %d\n", irq_num, level);
+ if( level ) {
+ if (set_level) s3c2410x_irq_main_level |= 1<<irq_num;
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] |= 1<<irq_num;
+ } else {
+ s3c2410x_irq_main_level &= ~(1<<irq_num);
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SRCPND] &= ~(1<<irq_num);
+ }
+ s3c2410x_percolate_subsrc_interrupt(env);
+}
+
+static void
+s3c2410x_irq_set_subsrc_interrupt_level(CPUState *env, 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) s3c2410x_irq_subsrc_level |= 1<<irq_num;
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] |= 1<<irq_num;
+ } else {
+ s3c2410x_irq_subsrc_level &= ~(1<<irq_num);
+ s3c2410x_irq_reg[CPU_S3C2410X_IRQ_SUBSRCPND] &= ~(1<<irq_num);
+ }
+ s3c2410x_percolate_subsrc_interrupt(env);
+}
+
+static void
+s3c2410x_irq_handler(void *opaque, int _n, int level)
+{
+ CPUState *env = (CPUState *)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(env, irq_num, level, is_level);
+ else
+ s3c2410x_irq_set_subsrc_interrupt_level(env, irq_num, level, is_level);
+}
+
+qemu_irq *
+s3c2410x_irq_init(CPUState *env)
+{
+ /* Samsung S3C2410X IRQ registration. */
+ int tag = cpu_register_io_memory(0, s3c2410x_irq_read, s3c2410x_irq_write, env);
+ cpu_register_physical_memory(CPU_S3C2410X_IRQ_BASE, 8*4, tag);
+ 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;
+ /* 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, env, 128);
+}
=== added file 'hw/s3c2410x_memc.c'
--- hw/s3c2410x_memc.c 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_memc.c 2007-04-16 21:51:37 +0000
@@ -0,0 +1,63 @@
+/* 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 uint32_t s3c2410x_memc_reg[13];
+
+static void
+s3c2410x_memc_write_f(void *opaque_ignored, target_phys_addr_t addr_, uint32_t value)
+{
+ int addr = (addr_ & 0x3f) >> 2;
+ if (addr < 0 || addr > 12) addr = 12;
+ S3C2410X_DBF("Write MEMC[%d] = %08x\n", addr, value);
+ s3c2410x_memc_reg[addr] = value;
+}
+
+static uint32_t
+s3c2410x_memc_read_f(void *opaque_ignored, target_phys_addr_t addr_)
+{
+ int addr = (addr_ & 0x3f) >> 2;
+ if (addr < 0 || addr > 12) addr = 12;
+ S3C2410X_DBF("Read MEMC[%d]\n", addr);
+ return s3c2410x_memc_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c2410x_memc_read[] = {
+ &s3c2410x_memc_read_f,
+ &s3c2410x_memc_read_f,
+ &s3c2410x_memc_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c2410x_memc_write[] = {
+ &s3c2410x_memc_write_f,
+ &s3c2410x_memc_write_f,
+ &s3c2410x_memc_write_f,
+};
+
+
+void
+s3c2410x_memc_init(void)
+{
+ /* Memory controller is all about SDRAM control, thus we just drop
+ * some RAM in there and assume life will be ok.
+ * It is 13 registers, each 4 bytes.
+ *
+ * However because of the bizarro mechanisms in qemu for RAM, we do
+ * it as MMIO which means a tag and then a memory range.
+ */
+ int tag;
+ tag = cpu_register_io_memory(0, s3c2410x_memc_read, s3c2410x_memc_write, 0);
+ cpu_register_physical_memory(CPU_S3C2410X_BWSCON, 13*4, tag);
+
+ for(tag = 0; tag < 13; tag++) s3c2410x_memc_reg[tag] = 0;
+
+}
=== added file 'hw/s3c2410x_rtc.c'
--- hw/s3c2410x_rtc.c 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_rtc.c 2007-04-16 21:51:37 +0000
@@ -0,0 +1,85 @@
+/* hw/s3c2410x_rtc.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "vl.h"
+#include "s3c2410x.h"
+
+static uint8_t s3c2410x_rtc_reg[19];
+
+static inline int to_bcd(int a)
+{
+ return ((a/10)<<4) | (a%10);
+}
+
+static void
+s3c2410x_rtc_write_f(void *opaque_ignored, target_phys_addr_t addr_, uint32_t value)
+{
+ int addr = (addr_ - CPU_S3C2410X_RTC_BASE) >> 2;
+ if (addr < 0 || addr > 18) addr = 18;
+ S3C2410X_DBF("Write RTC[%d] = %08x\n", addr, value);
+ s3c2410x_rtc_reg[addr] = value;
+}
+
+static uint32_t
+s3c2410x_rtc_read_f(void *opaque_ignored, target_phys_addr_t addr_)
+{
+ int addr = (addr_ - CPU_S3C2410X_RTC_BASE) >> 2;
+ struct tm *tm;
+ time_t ti;
+ if (addr < 0 || addr > 18) addr = 18;
+ S3C2410X_DBF("Read RTC[%d]\n", addr);
+ if( addr >= CPU_S3C2410X_REG_BCDSEC &&
+ addr <= CPU_S3C2410X_REG_BCDYEAR ) {
+ time(&ti);
+ if( rtc_utc )
+ tm = gmtime(&ti);
+ else
+ tm = localtime(&ti);
+ switch(addr) {
+ case CPU_S3C2410X_REG_BCDSEC:
+ return to_bcd(tm->tm_sec);
+ case CPU_S3C2410X_REG_BCDMIN:
+ return to_bcd(tm->tm_min);
+ case CPU_S3C2410X_REG_BCDHOUR:
+ return to_bcd(tm->tm_hour);
+ case CPU_S3C2410X_REG_BCDDATE:
+ return to_bcd(tm->tm_mday);
+ case CPU_S3C2410X_REG_BCDDAY:
+ return to_bcd(tm->tm_wday+1);
+ case CPU_S3C2410X_REG_BCDMON:
+ return to_bcd(tm->tm_mon+1);
+ case CPU_S3C2410X_REG_BCDYEAR:
+ return to_bcd(tm->tm_year-100);
+ }
+ }
+ return s3c2410x_rtc_reg[addr];
+}
+
+static CPUReadMemoryFunc *s3c2410x_rtc_read[] = {
+ &s3c2410x_rtc_read_f,
+ &s3c2410x_rtc_read_f,
+ &s3c2410x_rtc_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c2410x_rtc_write[] = {
+ &s3c2410x_rtc_write_f,
+ &s3c2410x_rtc_write_f,
+ &s3c2410x_rtc_write_f,
+};
+
+
+void
+s3c2410x_rtc_init(void)
+{
+ int tag;
+ tag = cpu_register_io_memory(0, s3c2410x_rtc_read, s3c2410x_rtc_write, 0);
+ cpu_register_physical_memory(CPU_S3C2410X_RTC_BASE, 19*4, tag);
+ for(tag=0; tag < 18; ++tag) s3c2410x_rtc_reg[tag] = 0;
+}
=== added file 'hw/s3c2410x_serial.c'
--- hw/s3c2410x_serial.c 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_serial.c 2007-04-17 09:12:47 +0000
@@ -0,0 +1,220 @@
+/* hw/s3c2410x_serial.c
+ *
+ * Samsung S3C2410X Serial block
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#define S3C2410X_DEBUG
+
+#include "vl.h"
+#include "s3c2410x.h"
+
+typedef struct {
+ uint32_t ulcon, ucon, ufcon, umcon, ubrdiv;
+ unsigned char rx_byte;
+ /* Byte is available to be read */
+ unsigned int rx_available : 1;
+ CharDriverState *chr;
+ int port;
+ qemu_irq tx_irq;
+ qemu_irq rx_irq;
+ qemu_irq tx_level;
+ qemu_irq rx_level;
+} s3c2410x_serial_dev;
+
+static void
+s3c2410x_serial_write_f(void *opaque, target_phys_addr_t addr, uint32_t value)
+{
+ s3c2410x_serial_dev *s = opaque;
+ int reg = addr & 0x3f;
+ if (reg != CPU_S3C2410X_SERIAL_UTXH)
+ S3C2410X_DBF("Serial[%d] Write of %08x to %08x (reg %d)\n", s->port, value, addr, reg);
+ switch(reg) {
+ case CPU_S3C2410X_SERIAL_ULCON:
+ s->ulcon = value;
+ break;
+ case CPU_S3C2410X_SERIAL_UCON:
+ s->ucon = value;
+ if( s->ucon & 1<<9 ) {
+ S3C2410X_DBF("Serial[%d] setting TX level interrupt due to ucon write\n", s->port);
+ qemu_set_irq(s->tx_level, 1);
+ } else {
+ S3C2410X_DBF("Serial[%d] clearing TX level interrupt due to ucon write\n", s->port);
+ qemu_set_irq(s->tx_level, 0);
+ }
+ if( !(s->ucon & 1<<8) ) {
+ S3C2410X_DBF("Serial[%d] clearing RX level interrupt (if any) due to ucon write\n", s->port);
+ qemu_set_irq(s->rx_level, 0);
+ }
+ break;
+ case CPU_S3C2410X_SERIAL_UFCON:
+ s->ufcon = value;
+ break;
+ case CPU_S3C2410X_SERIAL_UMCON:
+ s->umcon = value;
+ break;
+ case CPU_S3C2410X_SERIAL_UTRSTAT:
+ break;
+ case CPU_S3C2410X_SERIAL_UERSTAT:
+ break;
+ case CPU_S3C2410X_SERIAL_UFSTAT:
+ break;
+ case CPU_S3C2410X_SERIAL_UMSTAT:
+ break;
+ case CPU_S3C2410X_SERIAL_UTXH: {
+ unsigned char ch = value & 0xff;
+ if (s->chr && ((s->ucon & 1<<5)==0))
+ qemu_chr_write(s->chr, &ch, 1);
+ else {
+ s->rx_byte = ch;
+ s->rx_available = 1;
+ if( s->ucon & 1<<8 ) {
+ S3C2410X_DBF("Serial[%d] Setting RX level interrupt due to loopback write\n", s->port);
+ qemu_set_irq(s->rx_level, 1);
+ } else {
+ S3C2410X_DBF("Serial[%d] Pulsing RX interrupt due to loopback write\n", s->port);
+ qemu_set_irq(s->rx_irq, 1);
+ }
+ }
+ if( s->ucon & 1<<9 ) {
+ S3C2410X_DBF("Serial[%d] Setting TX level interrupt due to byte write\n", s->port);
+ qemu_set_irq(s->tx_level, 1);
+ } else {
+ S3C2410X_DBF("Serial[%d] Pulsing TX interrupt due to byte write\n", s->port);
+ qemu_set_irq(s->tx_irq, 1);
+ }
+ break;
+ }
+ case CPU_S3C2410X_SERIAL_URXH:
+ break;
+ case CPU_S3C2410X_SERIAL_UBRDIV:
+ s->ubrdiv = value;
+ break;
+ default:
+ break;
+ };
+}
+
+static uint32_t
+s3c2410x_serial_read_f(void *opaque, target_phys_addr_t addr)
+{
+ s3c2410x_serial_dev *s = opaque;
+ int reg = addr & 0x3f;
+ if (reg != CPU_S3C2410X_SERIAL_URXH &&
+ reg != CPU_S3C2410X_SERIAL_UFCON &&
+ reg != CPU_S3C2410X_SERIAL_UFSTAT)
+ S3C2410X_DBF("Serial[%d] Read of %08x (reg %d)\n", s->port, addr, reg);
+ switch(reg) {
+ case CPU_S3C2410X_SERIAL_ULCON:
+ return s->ulcon;
+ case CPU_S3C2410X_SERIAL_UCON:
+ return s->ucon;
+ case CPU_S3C2410X_SERIAL_UFCON:
+ return s->ufcon & ~0x8; /* bit 3 is reserved, must be zero */
+ case CPU_S3C2410X_SERIAL_UMCON:
+ return s->umcon & 0x11; /* Rest are reserved, must be zero */
+ case CPU_S3C2410X_SERIAL_UTRSTAT:
+ return 6 | s->rx_available; /* TX always clear, RX when available */
+ case CPU_S3C2410X_SERIAL_UERSTAT:
+ return 0; /* Later, break detect comes in here */
+ case CPU_S3C2410X_SERIAL_UFSTAT:
+ return s->rx_available; /* TXFIFO, always empty, RXFIFO 0 or 1 bytes */
+ case CPU_S3C2410X_SERIAL_UMSTAT:
+ return 0;
+ case CPU_S3C2410X_SERIAL_UTXH:
+ return 0;
+ case CPU_S3C2410X_SERIAL_URXH:
+ s->rx_available = 0;
+ if( s->ucon & 1<<8 ) {
+ S3C2410X_DBF("Serial[%d] clearing RX level interrupt due to byte read\n", s->port);
+ qemu_set_irq(s->rx_level, 0);
+ }
+ return s->rx_byte;
+ case CPU_S3C2410X_SERIAL_UBRDIV:
+ return s->ubrdiv;
+ default:
+ return 0;
+ };
+}
+
+static CPUReadMemoryFunc *s3c2410x_serial_read[] = {
+ &s3c2410x_serial_read_f,
+ &s3c2410x_serial_read_f,
+ &s3c2410x_serial_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c2410x_serial_write[] = {
+ &s3c2410x_serial_write_f,
+ &s3c2410x_serial_write_f,
+ &s3c2410x_serial_write_f,
+};
+
+
+static void s3c2410x_serial_event(void *opaque, int event)
+{
+ /* Disabled currently. *
+ s3c2410x_serial_dev *s = opaque;
+ if (event == CHR_EVENT_BREAK)
+ serial_receive_break(s);
+ /* */
+}
+
+static int
+s3c2410x_serial_can_receive(void *opaque)
+{
+ s3c2410x_serial_dev *s = opaque;
+ /* If there's no byte to be read, we can receive a new one */
+ return !s->rx_available;
+}
+
+static void
+s3c2410x_serial_receive(void *opaque, const uint8_t *buf, int size)
+{
+ s3c2410x_serial_dev *s = opaque;
+ s->rx_byte = buf[0];
+ s->rx_available = 1;
+ if( s->ucon & 1<<8 ) {
+ S3C2410X_DBF("Serial[%d] setting RX level interrupt due to incoming char %02x\n", s->port, buf[0]);
+ qemu_set_irq(s->rx_level, 1);
+ } else {
+ S3C2410X_DBF("Serial[%d] pulse receive interrupt %d for %02x\n", s->port, 1<<(s->port*3), buf[0]);
+ qemu_set_irq(s->rx_irq, 1); /* Is there something we can do here to ensure it's just a pulse ? */
+ }
+}
+
+void
+s3c2410x_serial_init(int port, qemu_irq tx_irq, qemu_irq rx_irq, qemu_irq tx_level, qemu_irq rx_level)
+{
+ /* Initialise a serial port at the given port address */
+ s3c2410x_serial_dev *s;
+ int serial_io_magic;
+
+ s = qemu_mallocz(sizeof(s3c2410x_serial_dev));
+ if (!s) return;
+ s->chr = serial_hds[port];
+ s->ulcon = 0;
+ s->ucon = 0;
+ s->ufcon = 0;
+ s->umcon = 0;
+ s->ubrdiv = 0;
+ s->port = port;
+ s->rx_available = 0;
+ s->tx_irq = tx_irq;
+ s->rx_irq = rx_irq;
+ s->tx_level = tx_level;
+ s->rx_level = rx_level;
+ /* Prepare our MMIO tag */
+ serial_io_magic = cpu_register_io_memory(0, s3c2410x_serial_read, s3c2410x_serial_write, s);
+ /* Register the region with the tag */
+ cpu_register_physical_memory(CPU_S3C2410X_SERIAL_BASE(port), 44, serial_io_magic);
+ if (s->chr) {
+ /* Add ourselves to the character device's IO handlers, if the port is there */
+
+ qemu_chr_add_handlers(s->chr, s3c2410x_serial_can_receive,
+ s3c2410x_serial_receive, s3c2410x_serial_event, s);
+ }
+}
=== added file 'hw/s3c2410x_timers.c'
--- hw/s3c2410x_timers.c 1970-01-01 00:00:00 +0000
+++ hw/s3c2410x_timers.c 2007-04-16 22:14:39 +0000
@@ -0,0 +1,117 @@
+/* hw/s3c2410x_timers.c
+ *
+ * Samsung S3C2410X emulation
+ *
+ * Copyright 2006, 2007 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2
+ */
+
+#include "vl.h"
+#include "s3c2410x.h"
+
+static uint32_t s3c2410x_timers_reg[17];
+QEMUTimer *timer4;
+static uint32_t timer4_reload_value;
+static int64_t timer4_last_ticked;
+
+/*
+
+QEMU_TIMER_BASE is ticks per second for the qemu clocks
+TCLK1 (assumed input for timer4) is 12 MHz
+Thus, period in ticks of timer4 is:
+
+(timer4_period * QEMU_TIMER_BASE) / 12000000
+
+ */
+
+#define MEGA 1000000
+#define HERTZ 1
+
+#define TCLK1 (12 * MEGA * HERTZ)
+
+static void
+s3c2410x_schedule_timer4(void)
+{
+ s3c2410x_timers_reg[CPU_S3C2410X_TIMERS_TCNTB4] = timer4_reload_value;
+ timer4_last_ticked = qemu_get_clock(vm_clock);
+ qemu_mod_timer(timer4, timer4_last_ticked + ((timer4_reload_value*ticks_per_sec)/TCLK1));
+}
+
+static void
+s3c2410x_timer4_tick(void *opaque)
+{
+ qemu_irq timer4_irq = (qemu_irq)opaque;
+ S3C2410X_DBF("Timer4 goes TICK!\n");
+ qemu_set_irq(timer4_irq, 1);
+ if (s3c2410x_timers_reg[CPU_S3C2410X_TIMERS_TCON] && (1<<22)) {
+ s3c2410x_schedule_timer4();
+ }
+}
+
+static void
+s3c2410x_timers_write_f(void *opaque_ignored, target_phys_addr_t addr_, uint32_t value)
+{
+ int addr = (addr_ >> 2) & 0x1f;
+ S3C2410X_DBF("Write TIMERS[%02x] = %08x\n",addr<<2, value);
+ s3c2410x_timers_reg[addr] = value;
+ if( addr == CPU_S3C2410X_TIMERS_TCON ) {
+ /* If Timer4's manual update is set, copy in the reload value */
+ if( value & (1 << 21) )
+ timer4_reload_value = s3c2410x_timers_reg[CPU_S3C2410X_TIMERS_TCNTB4];
+ /* If Timer4's manual update is unset, and the timer is running, start it */
+ if( !(value & (1 << 21)) && value & (1 << 20)) {
+ s3c2410x_schedule_timer4();
+ }
+ }
+}
+
+static uint32_t
+s3c2410x_timers_read_f(void *opaque_ignored, target_phys_addr_t addr_)
+{
+ int addr = (addr_ >> 2) & 0x1f;
+ S3C2410X_DBF("Read TIMERS[%02x]\n",addr<<2);
+ if( addr == CPU_S3C2410X_TIMERS_TCNTO4 ) {
+ return timer4_reload_value - (((qemu_get_clock(vm_clock)-timer4_last_ticked)*TCLK1)/ticks_per_sec);
+ }
+ return s3c2410x_timers_reg[addr];
+}
+
+
+static CPUReadMemoryFunc *s3c2410x_timers_read[] = {
+ &s3c2410x_timers_read_f,
+ &s3c2410x_timers_read_f,
+ &s3c2410x_timers_read_f,
+};
+
+static CPUWriteMemoryFunc *s3c2410x_timers_write[] = {
+ &s3c2410x_timers_write_f,
+ &s3c2410x_timers_write_f,
+ &s3c2410x_timers_write_f,
+};
+
+void
+s3c2410x_timers_init(qemu_irq timer4_irq)
+{
+ /* Samsung S3C2410X TIMERS registration.
+ *
+ * Specifically the PWM timer4.
+ */
+ int tag = cpu_register_io_memory(0, s3c2410x_timers_read, s3c2410x_timers_write, timer4_irq);
+ cpu_register_physical_memory(CPU_S3C2410X_TIMERS_BASE, 17*4, tag);
+ timer4 = qemu_new_timer(vm_clock, s3c2410x_timer4_tick, timer4_irq);
+}
+
+/*
+
+Need to set up a timer against the vm_clock for 12MHz. (Virtual TCLK1)
+
+Then we only provide timer4 anyway, and it will always be configured to use TCLK1
+
+We need to take on board the count/compare values, and when the timer is reloaded, we set
+a qemu_timer_mod to call us back at the appropriate VM tick.
+
+At that point we probably raise an interrupt.
+
+*/
=== added directory 'hw/s3c24xx'
=== added file 'hw/s3c24xx/regs-iic.h'
--- hw/s3c24xx/regs-iic.h 1970-01-01 00:00:00 +0000
+++ hw/s3c24xx/regs-iic.h 2007-04-16 21:51:37 +0000
@@ -0,0 +1,56 @@
+/* linux/include/asm-arm/arch-s3c2410/regs-iic.h
+ *
+ * Copyright (c) 2004 Simtec Electronics <linux@simtec.co.uk>
+ * http://www.simtec.co.uk/products/SWLINUX/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * S3C2410 I2C Controller
+*/
+
+#ifndef __ASM_ARCH_REGS_IIC_H
+#define __ASM_ARCH_REGS_IIC_H __FILE__
+
+/* see s3c2410x user guide, v1.1, section 9 (p447) for more info */
+
+#define S3C2410_IICREG(x) (x)
+
+#define S3C2410_IICCON S3C2410_IICREG(0x00)
+#define S3C2410_IICSTAT S3C2410_IICREG(0x04)
+#define S3C2410_IICADD S3C2410_IICREG(0x08)
+#define S3C2410_IICDS S3C2410_IICREG(0x0C)
+#define S3C2440_IICLC S3C2410_IICREG(0x10)
+
+#define S3C2410_IICCON_ACKEN (1<<7)
+#define S3C2410_IICCON_TXDIV_16 (0<<6)
+#define S3C2410_IICCON_TXDIV_512 (1<<6)
+#define S3C2410_IICCON_IRQEN (1<<5)
+#define S3C2410_IICCON_IRQPEND (1<<4)
+#define S3C2410_IICCON_SCALE(x) ((x)&15)
+#define S3C2410_IICCON_SCALEMASK (0xf)
+
+#define S3C2410_IICSTAT_MASTER_RX (2<<6)
+#define S3C2410_IICSTAT_MASTER_TX (3<<6)
+#define S3C2410_IICSTAT_SLAVE_RX (0<<6)
+#define S3C2410_IICSTAT_SLAVE_TX (1<<6)
+#define S3C2410_IICSTAT_MODEMASK (3<<6)
+
+#define S3C2410_IICSTAT_START (1<<5)
+#define S3C2410_IICSTAT_BUSBUSY (1<<5)
+#define S3C2410_IICSTAT_TXRXEN (1<<4)
+#define S3C2410_IICSTAT_ARBITR (1<<3)
+#define S3C2410_IICSTAT_ASSLAVE (1<<2)
+#define S3C2410_IICSTAT_ADDR0 (1<<1)
+#define S3C2410_IICSTAT_LASTBIT (1<<0)
+
+#define S3C2410_IICLC_SDA_DELAY0 (0 << 0)
+#define S3C2410_IICLC_SDA_DELAY5 (1 << 0)
+#define S3C2410_IICLC_SDA_DELAY10 (2 << 0)
+#define S3C2410_IICLC_SDA_DELAY15 (3 << 0)
+#define S3C2410_IICLC_SDA_DELAY_MASK (3 << 0)
+
+#define S3C2410_IICLC_FILTER_ON (1<<2)
+
+#endif /* __ASM_ARCH_REGS_IIC_H */
=== added file 'hw/simtecbast.c'
--- hw/simtecbast.c 1970-01-01 00:00:00 +0000
+++ hw/simtecbast.c 2007-04-16 21:51:37 +0000
@@ -0,0 +1,117 @@
+/* hw/simtecbast.c
+ *
+ * Simple system emulation for the Simtec Electronics BAST
+ *
+ * Copyright 2006 Daniel Silverstone and Vincent Sanders
+ *
+ * This file is under the terms of the GNU General Public
+ * License Version 2.
+ */
+
+#include "vl.h"
+#include "s3c2410x.h"
+#include "assert.h"
+
+#define BIOS_FILENAME "s3c2410x-able.bin"
+
+/* Bytes in a Kilobyte */
+#define KILO 1024
+/* Bytes in a megabyte */
+#define MEGA 1024 * KILO
+/* Bytes */
+#define BYTE 1
+/* Bits in a byte */
+#define BIT 8
+
+/* Useful defines */
+#define SIMTEC_BAST_NOR_BASE CPU_S3C2410X_CS0
+#define SIMTEC_BAST_NOR_SIZE 16 * MEGA / BIT
+#define SIMTEC_BAST_BOARD_ID 331
+
+#define BAST_IDE_PRI_SLOW (CPU_S3C2410X_CS3 | 0x2000000)
+#define BAST_IDE_SEC_SLOW (CPU_S3C2410X_CS3 | 0x3000000)
+#define BAST_IDE_PRI_FAST (CPU_S3C2410X_CS5 | 0x2000000)
+#define BAST_IDE_SEC_FAST (CPU_S3C2410X_CS5 | 0x3000000)
+
+#define BAST_IDE_PRI_SLOW_BYTE (CPU_S3C2410X_CS2 | 0x2000000)
+#define BAST_IDE_SEC_SLOW_BYTE (CPU_S3C2410X_CS2 | 0x3000000)
+#define BAST_IDE_PRI_FAST_BYTE (CPU_S3C2410X_CS4 | 0x2000000)
+#define BAST_IDE_SEC_FAST_BYTE (CPU_S3C2410X_CS4 | 0x3000000)
+
+static void stcb_register_ide(void)
+{
+ int ide0_mem = stcb_ide_init(&bs_table[0], s3c_irqs[16]);
+ int ide1_mem = stcb_ide_init(&bs_table[2], s3c_irqs[17]);
+
+ cpu_register_physical_memory(BAST_IDE_PRI_SLOW, 0x1000000, ide0_mem);
+ cpu_register_physical_memory(BAST_IDE_PRI_FAST, 0x1000000, ide0_mem);
+
+ cpu_register_physical_memory(BAST_IDE_SEC_SLOW, 0x1000000, ide1_mem);
+ cpu_register_physical_memory(BAST_IDE_SEC_FAST, 0x1000000, ide1_mem);
+
+ cpu_register_physical_memory(BAST_IDE_PRI_SLOW_BYTE, 0x1000000, ide0_mem);
+ cpu_register_physical_memory(BAST_IDE_PRI_FAST_BYTE, 0x1000000, ide0_mem);
+
+ cpu_register_physical_memory(BAST_IDE_SEC_SLOW_BYTE, 0x1000000, ide1_mem);
+ cpu_register_physical_memory(BAST_IDE_SEC_FAST_BYTE, 0x1000000, ide1_mem);
+}
+
+static void stcb_init(int _ram_size, int vga_ram_size, int boot_device,
+ DisplayState *ds, const char **fd_filename, int snapshot,
+ const char *kernel_filename, const char *kernel_cmdline,
+ const char *initrd_filename)
+{
+ CPUState *env;
+ int bios_offset;
+ char buf[1024]; /* URGH */
+ int ret;
+ NICInfo* nd;
+
+ if (_ram_size > (256 * MEGA * BYTE)) _ram_size = 256 * MEGA * BYTE;
+ ram_size = _ram_size;
+
+ bios_offset = ram_size + vga_ram_size;
+
+ env = s3c2410x_init(ram_size);
+
+ if( kernel_filename == NULL ) {
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, BIOS_FILENAME);
+ ret = load_image(buf, phys_ram_base + bios_offset);
+ if( ret <= 0 ) {
+ fprintf(stderr, "qemu: warning, could not load BAST BIOS from %s\n", buf);
+ } else {
+ fprintf(stdout, "qemu: info, loaded BAST BIOS %d bytes from %s\n", ret, buf);
+ }
+ } else {
+ arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
+ initrd_filename, SIMTEC_BAST_BOARD_ID, CPU_S3C2410X_RAM);
+ /* Construct the smallest bootloader(ish) in the world */
+ stl_raw(phys_ram_base + bios_offset, 0xE59FF000); /* ldr pc, [pc, #0] (loads from +8) */
+ stl_raw(phys_ram_base + bios_offset + 4, 0x00000000);
+ stl_raw(phys_ram_base + bios_offset + 8, CPU_S3C2410X_RAM);
+ stl_raw(phys_ram_base + bios_offset + 12, 0xE3A0F000);
+ }
+
+ /* Register the NOR flash ROM */
+ cpu_register_physical_memory(SIMTEC_BAST_NOR_BASE, SIMTEC_BAST_NOR_SIZE,
+ bios_offset | IO_MEM_ROM);
+ stcb_register_ide();
+
+ nd = &nd_table[0];
+ if (!nd->model)
+ nd->model = "dm9000";
+ if (strcmp(nd->model, "dm9000") == 0) {
+ dm9000_init(nd, 0x2D000000, 0x00, 0x40, s3c_irqs[10]);
+ }
+
+
+
+ /* And we're good to go */
+}
+
+
+QEMUMachine simtecbast_machine = {
+ "simtecbast",
+ "Simtec Electronics BAST (S3C2410X, ARM920T)",
+ stcb_init,
+};
=== modified file 'Makefile.target'
--- Makefile.target 2007-04-16 18:27:06 +0000
+++ Makefile.target 2007-04-16 21:51:37 +0000
@@ -447,6 +447,8 @@
ifeq ($(TARGET_BASE_ARCH), arm)
VL_OBJS+= integratorcp.o versatilepb.o ps2.o smc91c111.o arm_pic.o arm_timer.o
VL_OBJS+= arm_boot.o pl011.o pl050.o pl080.o pl110.o pl181.o pl190.o
+VL_OBJS+= simtecbast.o s3c2410x.o s3c2410x_serial.o s3c2410x_memc.o s3c2410x_gpio.o s3c2410x_iic.o dm9000.o
+VL_OBJS+= s3c2410x_irq.o s3c2410x_timers.o ide.o s3c2410x_clkcon.o s3c2410x_rtc.o
VL_OBJS+= versatile_pci.o sd.o
VL_OBJS+= arm_gic.o realview.o arm_sysctl.o
VL_OBJS+= arm-semi.o
=== modified file 'hw/arm_boot.c'
--- hw/arm_boot.c 2007-04-01 17:56:36 +0000
+++ hw/arm_boot.c 2007-04-16 21:51:37 +0000
@@ -32,11 +32,12 @@
if (env->kernel_filename)
arm_load_kernel(env, env->ram_size, env->kernel_filename,
env->kernel_cmdline, env->initrd_filename,
- env->board_id);
+ env->board_id, env->emulated_sdram_base);
}
static void set_kernel_args(uint32_t ram_size, int initrd_size,
- const char *kernel_cmdline)
+ const char *kernel_cmdline,
+ target_phys_addr_t emulated_sdram_base)
{
uint32_t *p;
@@ -51,12 +52,12 @@
stl_raw(p++, 4);
stl_raw(p++, 0x54410002);
stl_raw(p++, ram_size);
- stl_raw(p++, 0);
+ stl_raw(p++, emulated_sdram_base);
if (initrd_size) {
/* ATAG_INITRD2 */
stl_raw(p++, 4);
stl_raw(p++, 0x54420005);
- stl_raw(p++, INITRD_LOAD_ADDR);
+ stl_raw(p++, INITRD_LOAD_ADDR + emulated_sdram_base);
stl_raw(p++, initrd_size);
}
if (kernel_cmdline && *kernel_cmdline) {
@@ -77,7 +78,7 @@
void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
const char *kernel_cmdline, const char *initrd_filename,
- int board_id)
+ int board_id, target_phys_addr_t emulated_sdram_base)
{
int kernel_size;
int initrd_size;
@@ -98,6 +99,7 @@
env->kernel_cmdline = kernel_cmdline;
env->initrd_filename = initrd_filename;
env->board_id = board_id;
+ env->emulated_sdram_base = emulated_sdram_base;
qemu_register_reset(main_cpu_reset, env);
}
/* Assume that raw images are linux kernels, and ELF images are not. */
@@ -138,7 +140,7 @@
bootloader[6] = entry;
for (n = 0; n < sizeof(bootloader) / 4; n++)
stl_raw(phys_ram_base + (n * 4), bootloader[n]);
- set_kernel_args(ram_size, initrd_size, kernel_cmdline);
+ set_kernel_args(ram_size, initrd_size, kernel_cmdline, emulated_sdram_base);
}
}
=== modified file 'hw/ide.c'
--- hw/ide.c 2007-04-07 18:14:41 +0000
+++ hw/ide.c 2007-04-16 21:51:37 +0000
@@ -1789,7 +1789,10 @@
break;
case WIN_DIAGNOSE:
ide_set_signature(s);
- s->status = 0x00; /* NOTE: READY is _not_ set */
+ if (s->is_cdrom)
+ s->status = 0x00; /* NOTE: READY is _not_ set */
+ else
+ s->status = READY_STAT;
s->error = 0x01;
break;
case WIN_SRST:
@@ -1879,6 +1882,7 @@
ret = 0;
else
ret = s->select;
+ ret |= 0x80;
break;
default:
case 7:
@@ -2749,3 +2753,82 @@
pmac_ide_write, &ide_if[0]);
return pmac_ide_memory;
}
+
+#if defined(TARGET_ARM)
+#include "s3c2410x.h"
+
+/* MMIO interface to IDE on Simtec's BAST
+ *
+ * Copyright Daniel Silverstone and Vincent Sanders
+ *
+ * This section of this file is under the terms of
+ * the GNU General Public License Version 2
+ */
+
+/* Each BAST IDE region is 0x1000000 bytes long,
+ * the second half is the "alternate" register set
+ */
+
+static void stcb_ide_write_f (void *opaque,
+ target_phys_addr_t addr, uint32_t val)
+{
+ int reg = (addr & 0x3ff) >> 5; /* 0x200 long, 0x20 stride */
+ int alt = (addr & 0x800000) != 0;
+ S3C2410X_DBF("IDE write to addr %08x (reg %d) of value %04x\n",addr, reg, val);
+ if( alt ) {
+ ide_cmd_write(opaque, 0, val);
+ }
+ if( reg == 0 ) {
+ /* Data register */
+ ide_data_writew(opaque, 0, val);
+ } else {
+ /* Everything else */
+ ide_ioport_write(opaque, reg, val);
+ }
+}
+
+static uint32_t stcb_ide_read_f (void *opaque,target_phys_addr_t addr)
+{
+ int reg = (addr & 0x3ff) >> 5; /* 0x200 long, 0x20 stride */
+ int alt = (addr & 0x800000) != 0;
+ S3C2410X_DBF("IDE read of addr %08x (reg %d)\n",addr, reg);
+ if( alt ) {
+ return ide_status_read(opaque, 0);
+ }
+ if( reg == 0 ) {
+ return ide_data_readw(opaque, 0);
+ } else {
+ return ide_ioport_read(opaque, reg);
+ }
+}
+
+
+static CPUWriteMemoryFunc *stcb_ide_write[] = {
+ stcb_ide_write_f,
+ stcb_ide_write_f,
+ stcb_ide_write_f,
+};
+
+static CPUReadMemoryFunc *stcb_ide_read[] = {
+ stcb_ide_read_f,
+ stcb_ide_read_f,
+ stcb_ide_read_f,
+};
+
+/* hd_table must contain 2 block drivers */
+/* BAST uses memory mapped registers, not I/O. Return the memory
+ I/O index to access the ide. */
+int stcb_ide_init (BlockDriverState **hd_table, qemu_irq irq)
+{
+ IDEState *ide_if;
+ int stcb_ide_memory;
+
+ ide_if = qemu_mallocz(sizeof(IDEState) * 2);
+ ide_init2(&ide_if[0], hd_table[0], hd_table[1], irq);
+
+ stcb_ide_memory = cpu_register_io_memory(0, stcb_ide_read,
+ stcb_ide_write, &ide_if[0]);
+ return stcb_ide_memory;
+}
+
+#endif
=== modified file 'hw/integratorcp.c'
--- hw/integratorcp.c 2007-04-07 18:14:41 +0000
+++ hw/integratorcp.c 2007-04-16 21:51:37 +0000
@@ -508,7 +508,7 @@
pl110_init(ds, 0xc0000000, pic[22], 0);
arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, 0x113);
+ initrd_filename, 0x113, 0);
}
QEMUMachine integratorcp_machine = {
=== modified file 'hw/irq.h'
--- hw/irq.h 2007-04-07 18:14:41 +0000
+++ hw/irq.h 2007-04-16 21:51:37 +0000
@@ -1,3 +1,5 @@
+#ifndef QEMU_HW_IRQ_H
+#define QEMU_HW_IRQ_H
/* Generic IRQ/GPIO pin infrastructure. */
typedef void (*qemu_irq_handler)(void *opaque, int n, int level);
@@ -19,3 +21,4 @@
/* Returns an array of N IRQs. */
qemu_irq *qemu_allocate_irqs(qemu_irq_handler handler, void *opaque, int n);
+#endif
=== modified file 'hw/realview.c'
--- hw/realview.c 2007-04-07 18:14:41 +0000
+++ hw/realview.c 2007-04-16 21:51:37 +0000
@@ -131,7 +131,7 @@
/* 0x6c000000 PCI mem 2. */
arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, 0x33b);
+ initrd_filename, 0x33b, 0x0);
}
QEMUMachine realview_machine = {
=== modified file 'hw/versatilepb.c'
--- hw/versatilepb.c 2007-04-07 18:14:41 +0000
+++ hw/versatilepb.c 2007-04-16 21:51:37 +0000
@@ -260,7 +260,7 @@
/* 0x101f4000 SSPI. */
arm_load_kernel(env, ram_size, kernel_filename, kernel_cmdline,
- initrd_filename, board_id);
+ initrd_filename, board_id, 0);
}
static void vpb_init(int ram_size, int vga_ram_size, int boot_device,
=== modified file 'target-arm/cpu.h'
--- target-arm/cpu.h 2007-03-11 13:03:18 +0000
+++ target-arm/cpu.h 2007-04-16 21:51:37 +0000
@@ -127,6 +127,7 @@
const char *kernel_filename;
const char *kernel_cmdline;
const char *initrd_filename;
+ target_phys_addr_t emulated_sdram_base;
int board_id;
} CPUARMState;
@@ -220,6 +221,7 @@
#define ARM_CPUID_ARM1026 0x4106a262
#define ARM_CPUID_ARM926 0x41069265
+#define ARM_CPUID_ARM920T 0x41129200
#if defined(CONFIG_USER_ONLY)
#define TARGET_PAGE_BITS 12
=== modified file 'target-arm/helper.c'
--- target-arm/helper.c 2007-04-07 11:21:27 +0000
+++ target-arm/helper.c 2007-04-16 21:51:37 +0000
@@ -14,6 +14,8 @@
{
env->cp15.c0_cpuid = id;
switch (id) {
+ case ARM_CPUID_ARM920T:
+ break;
case ARM_CPUID_ARM926:
set_feature(env, ARM_FEATURE_VFP);
env->vfp.xregs[ARM_VFP_FPSID] = 0x41011090;
@@ -68,6 +70,7 @@
static const struct arm_cpu_t arm_cpu_names[] = {
{ ARM_CPUID_ARM926, "arm926"},
{ ARM_CPUID_ARM1026, "arm1026"},
+ { ARM_CPUID_ARM920T, "arm920t"},
{ 0, NULL}
};
=== modified file 'target-arm/translate.c'
--- target-arm/translate.c 2007-04-02 08:18:36 +0000
+++ target-arm/translate.c 2007-04-16 21:51:37 +0000
@@ -525,6 +525,19 @@
return 0;
}
+static int disas_cp14_insn(DisasContext *s, uint32_t insn)
+{
+ uint32_t rd = (insn >> 12) & 0xf;
+ if (insn & (1<<20)) {
+ gen_op_movl_T0_im(0);
+ gen_op_movl_reg_TN[0][rd]();
+ } else {
+ /* Nothing to do on writes to cp14 */
+ }
+ gen_lookup_tb(s);
+ return 0;
+}
+
/* Disassemble a VFP instruction. Returns nonzero if an error occured
(ie. an undefined instruction). */
static int disas_vfp_insn(CPUState * env, DisasContext *s, uint32_t insn)
@@ -1818,6 +1831,11 @@
if (disas_vfp_insn (env, s, insn))
goto illegal_op;
break;
+ case 14:
+ /* ice */
+ if (disas_cp14_insn (s, insn))
+ goto illegal_op;
+ break;
case 15:
if (disas_cp15_insn (s, insn))
goto illegal_op;
=== modified file 'vl.c'
--- vl.c 2007-04-16 17:23:27 +0000
+++ vl.c 2007-04-16 21:51:37 +0000
@@ -6710,6 +6710,7 @@
qemu_register_machine(&versatilepb_machine);
qemu_register_machine(&versatileab_machine);
qemu_register_machine(&realview_machine);
+ qemu_register_machine(&simtecbast_machine);
#elif defined(TARGET_SH4)
qemu_register_machine(&shix_machine);
#elif defined(TARGET_ALPHA)
=== modified file 'vl.h'
--- vl.h 2007-04-16 17:23:27 +0000
+++ vl.h 2007-04-16 21:51:37 +0000
@@ -173,6 +173,11 @@
#define BIOS_SIZE ((512 + 32) * 1024)
#elif defined(TARGET_MIPS)
#define BIOS_SIZE (4 * 1024 * 1024)
+#elif defined(TARGET_ARM)
+/* ARM boards often have bootloaders in NOR which ends up
+ * memory mapped. 8 Megabytes seems enough for this
+ */
+#define BIOS_SIZE (8 * 1024 * 1024)
#endif
/* keyboard/mouse support */
@@ -964,6 +969,7 @@
void pci_piix3_ide_init(PCIBus *bus, BlockDriverState **hd_table, int devfn,
qemu_irq *pic);
int pmac_ide_init (BlockDriverState **hd_table, qemu_irq irq);
+int stcb_ide_init (BlockDriverState **hd_table, qemu_irq irq);
/* cdrom.c */
int cdrom_read_toc(int nb_sectors, uint8_t *buf, int msf, int start_track);
@@ -1363,6 +1369,9 @@
extern QEMUMachine versatilepb_machine;
extern QEMUMachine versatileab_machine;
+/* simtecbast.c */
+extern QEMUMachine simtecbast_machine;
+
/* realview.c */
extern QEMUMachine realview_machine;
@@ -1379,6 +1388,11 @@
/* smc91c111.c */
void smc91c111_init(NICInfo *, uint32_t, qemu_irq);
+/* dm9000.c */
+
+void dm9000_init(NICInfo *nd, target_phys_addr_t base_addr, uint32_t addr_offset,
+ uint32_t data_offset, qemu_irq irq);
+
/* pl110.c */
void *pl110_init(DisplayState *ds, uint32_t base, qemu_irq irq, int);
@@ -1412,7 +1426,7 @@
void arm_load_kernel(CPUState *env, int ram_size, const char *kernel_filename,
const char *kernel_cmdline, const char *initrd_filename,
- int board_id);
+ int board_id, target_phys_addr_t emulated_sdram_base);
/* sh7750.c */
struct SH7750State;
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2007-04-17 9:56 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2007-04-02 13:56 [Qemu-devel] Simtec BAST emulation Daniel Silverstone
2007-04-02 17:45 ` Paul Brook
2007-04-03 10:12 ` Daniel Silverstone
2007-04-17 9:51 ` Daniel Silverstone
2007-04-17 9:51 ` Daniel Silverstone
2007-04-02 23:04 ` andrzej zaborowski
2007-04-03 10:09 ` Daniel Silverstone
2007-04-03 15:01 ` andrzej zaborowski
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).