aboutsummaryrefslogtreecommitdiffstats
path: root/hw
diff options
context:
space:
mode:
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-12-19 23:18:01 +0000
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>2004-12-19 23:18:01 +0000
commite80cfcfc8884400e826328b772971913a14d0f44 (patch)
treef9bbe461ff5dd6f13fbdbd781053309564c0b872 /hw
parent9772c73bbc9f24a66bf060e16c0625a258b1bb41 (diff)
SPARC merge
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1179 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'hw')
-rw-r--r--hw/fdc.c35
-rw-r--r--hw/iommu.c54
-rw-r--r--hw/lance.c127
-rw-r--r--hw/m48t08.c161
-rw-r--r--hw/m48t08.h8
-rw-r--r--hw/magic-load.c179
-rw-r--r--hw/sched.c268
-rw-r--r--hw/slavio_intctl.c299
-rw-r--r--hw/slavio_serial.c364
-rw-r--r--hw/slavio_timer.c289
-rw-r--r--hw/sun4m.c163
-rw-r--r--hw/tcx.c297
-rw-r--r--hw/timer.c97
13 files changed, 1567 insertions, 774 deletions
diff --git a/hw/fdc.c b/hw/fdc.c
index d512b1ca9..ee0732848 100644
--- a/hw/fdc.c
+++ b/hw/fdc.c
@@ -21,6 +21,10 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+/*
+ * The controller is used in Sun4m systems in a slightly different
+ * way. There are changes in DOR register and DMA is not available.
+ */
#include "vl.h"
/********************************************************/
@@ -90,6 +94,16 @@ typedef struct fdrive_t {
uint8_t ro; /* Is read-only */
} fdrive_t;
+#ifdef TARGET_SPARC
+#define DMA_read_memory(a,b,c,d)
+#define DMA_write_memory(a,b,c,d)
+#define DMA_register_channel(a,b,c)
+#define DMA_hold_DREQ(a)
+#define DMA_release_DREQ(a)
+#define DMA_get_channel_mode(a) (0)
+#define DMA_schedule(a)
+#endif
+
static void fd_init (fdrive_t *drv, BlockDriverState *bs)
{
/* Drive */
@@ -455,6 +469,18 @@ static void fdctrl_write (void *opaque, uint32_t reg, uint32_t value)
}
}
+static CPUReadMemoryFunc *fdctrl_mem_read[3] = {
+ fdctrl_read,
+ fdctrl_read,
+ fdctrl_read,
+};
+
+static CPUWriteMemoryFunc *fdctrl_mem_write[3] = {
+ fdctrl_write,
+ fdctrl_write,
+ fdctrl_write,
+};
+
static void fd_change_cb (void *opaque)
{
fdrive_t *drv = opaque;
@@ -473,7 +499,7 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
BlockDriverState **fds)
{
fdctrl_t *fdctrl;
-// int io_mem;
+ int io_mem;
int i;
FLOPPY_DPRINTF("init controller\n");
@@ -504,11 +530,8 @@ fdctrl_t *fdctrl_init (int irq_lvl, int dma_chann, int mem_mapped,
fdctrl_reset(fdctrl, 0);
fdctrl->state = FD_CTRL_ACTIVE;
if (mem_mapped) {
- FLOPPY_ERROR("memory mapped floppy not supported by now !\n");
-#if 0
- io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write);
- cpu_register_physical_memory(base, 0x08, io_mem);
-#endif
+ io_mem = cpu_register_io_memory(0, fdctrl_mem_read, fdctrl_mem_write, fdctrl);
+ cpu_register_physical_memory(io_base, 0x08, io_mem);
} else {
register_ioport_read(io_base + 0x01, 5, 1, &fdctrl_read, fdctrl);
register_ioport_read(io_base + 0x07, 1, 1, &fdctrl_read, fdctrl);
diff --git a/hw/iommu.c b/hw/iommu.c
index a9249c4ba..62927acd5 100644
--- a/hw/iommu.c
+++ b/hw/iommu.c
@@ -117,8 +117,6 @@ typedef struct IOMMUState {
uint32_t iostart;
} IOMMUState;
-static IOMMUState *ps;
-
static uint32_t iommu_mem_readw(void *opaque, target_phys_addr_t addr)
{
IOMMUState *s = opaque;
@@ -187,25 +185,61 @@ static CPUWriteMemoryFunc *iommu_mem_write[3] = {
iommu_mem_writew,
};
-uint32_t iommu_translate(uint32_t addr)
+uint32_t iommu_translate_local(void *opaque, uint32_t addr)
{
- uint32_t *iopte = (void *)(ps->regs[1] << 4), pa;
+ IOMMUState *s = opaque;
+ uint32_t *iopte = (void *)(s->regs[1] << 4), pa;
- iopte += ((addr - ps->iostart) >> PAGE_SHIFT);
- cpu_physical_memory_rw((uint32_t)iopte, (void *) &pa, 4, 0);
+ iopte += ((addr - s->iostart) >> PAGE_SHIFT);
+ cpu_physical_memory_read((uint32_t)iopte, (void *) &pa, 4);
bswap32s(&pa);
pa = (pa & IOPTE_PAGE) << 4; /* Loose higher bits of 36 */
return pa + (addr & PAGE_MASK);
}
-void iommu_init(uint32_t addr)
+static void iommu_save(QEMUFile *f, void *opaque)
+{
+ IOMMUState *s = opaque;
+ int i;
+
+ qemu_put_be32s(f, &s->addr);
+ for (i = 0; i < sizeof(struct iommu_regs); i += 4)
+ qemu_put_be32s(f, &s->regs[i]);
+ qemu_put_be32s(f, &s->iostart);
+}
+
+static int iommu_load(QEMUFile *f, void *opaque, int version_id)
+{
+ IOMMUState *s = opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f, &s->addr);
+ for (i = 0; i < sizeof(struct iommu_regs); i += 4)
+ qemu_put_be32s(f, &s->regs[i]);
+ qemu_get_be32s(f, &s->iostart);
+
+ return 0;
+}
+
+static void iommu_reset(void *opaque)
+{
+ IOMMUState *s = opaque;
+
+ memset(s->regs, 0, sizeof(struct iommu_regs));
+ s->iostart = 0;
+}
+
+void *iommu_init(uint32_t addr)
{
IOMMUState *s;
int iommu_io_memory;
s = qemu_mallocz(sizeof(IOMMUState));
if (!s)
- return;
+ return NULL;
s->addr = addr;
@@ -213,6 +247,8 @@ void iommu_init(uint32_t addr)
cpu_register_physical_memory(addr, sizeof(struct iommu_regs),
iommu_io_memory);
- ps = s;
+ register_savevm("iommu", addr, 1, iommu_save, iommu_load, s);
+ qemu_register_reset(iommu_reset, s);
+ return s;
}
diff --git a/hw/lance.c b/hw/lance.c
index 25ad8c45b..c594c52e8 100644
--- a/hw/lance.c
+++ b/hw/lance.c
@@ -147,6 +147,7 @@ struct lance_init_block {
};
#define LEDMA_REGS 4
+#define LEDMA_MAXADDR (LEDMA_REGS * 4 - 1)
#if 0
/* Structure to describe the current status of DMA registers on the Sparc */
struct sparc_dma_registers {
@@ -157,32 +158,28 @@ struct sparc_dma_registers {
};
#endif
-typedef struct LEDMAState {
- uint32_t addr;
- uint32_t regs[LEDMA_REGS];
-} LEDMAState;
-
typedef struct LANCEState {
- uint32_t paddr;
NetDriverState *nd;
uint32_t leptr;
uint16_t addr;
uint16_t regs[LE_MAXREG];
uint8_t phys[6]; /* mac address */
int irq;
- LEDMAState *ledma;
+ unsigned int rxptr, txptr;
+ uint32_t ledmaregs[LEDMA_REGS];
} LANCEState;
-static unsigned int rxptr, txptr;
-
static void lance_send(void *opaque);
-static void lance_reset(LANCEState *s)
+static void lance_reset(void *opaque)
{
+ LANCEState *s = opaque;
memcpy(s->phys, s->nd->macaddr, 6);
- rxptr = 0;
- txptr = 0;
+ s->rxptr = 0;
+ s->txptr = 0;
+ memset(s->regs, 0, LE_MAXREG * 2);
s->regs[LE_CSR0] = LE_C0_STOP;
+ memset(s->ledmaregs, 0, LEDMA_REGS * 4);
}
static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
@@ -190,7 +187,7 @@ static uint32_t lance_mem_readw(void *opaque, target_phys_addr_t addr)
LANCEState *s = opaque;
uint32_t saddr;
- saddr = addr - s->paddr;
+ saddr = addr & LE_MAXREG;
switch (saddr >> 1) {
case LE_RDP:
return s->regs[s->addr];
@@ -208,7 +205,7 @@ static void lance_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val
uint32_t saddr;
uint16_t reg;
- saddr = addr - s->paddr;
+ saddr = addr & LE_MAXREG;
switch (saddr >> 1) {
case LE_RDP:
switch(s->addr) {
@@ -292,7 +289,7 @@ static CPUWriteMemoryFunc *lance_mem_write[3] = {
static int lance_can_receive(void *opaque)
{
LANCEState *s = opaque;
- void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+ uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
int i;
uint16_t temp;
@@ -303,7 +300,7 @@ static int lance_can_receive(void *opaque)
ib = (void *) iommu_translate(dmaptr);
for (i = 0; i < RX_RING_SIZE; i++) {
- cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
+ cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
temp &= 0xff;
if (temp == (LE_R1_OWN)) {
#ifdef DEBUG_LANCE
@@ -323,7 +320,7 @@ static int lance_can_receive(void *opaque)
static void lance_receive(void *opaque, const uint8_t *buf, int size)
{
LANCEState *s = opaque;
- void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+ uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
unsigned int i, old_rxptr, j;
uint16_t temp;
@@ -333,23 +330,23 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size)
ib = (void *) iommu_translate(dmaptr);
- old_rxptr = rxptr;
- for (i = rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
- cpu_physical_memory_read(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
+ old_rxptr = s->rxptr;
+ for (i = s->rxptr; i != ((old_rxptr - 1) & RX_RING_MOD_MASK); i = (i + 1) & RX_RING_MOD_MASK) {
+ cpu_physical_memory_read((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
if (temp == (LE_R1_OWN)) {
- rxptr = (rxptr + 1) & RX_RING_MOD_MASK;
+ s->rxptr = (s->rxptr + 1) & RX_RING_MOD_MASK;
temp = size;
bswap16s(&temp);
- cpu_physical_memory_write(&ib->brx_ring[i].mblength, (void *) &temp, 2);
+ cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].mblength, (void *) &temp, 2);
#if 0
- cpu_physical_memory_write(&ib->rx_buf[i], buf, size);
+ cpu_physical_memory_write((uint32_t)&ib->rx_buf[i], buf, size);
#else
for (j = 0; j < size; j++) {
- cpu_physical_memory_write(((void *)&ib->rx_buf[i]) + j, &buf[j], 1);
+ cpu_physical_memory_write(((uint32_t)&ib->rx_buf[i]) + j, &buf[j], 1);
}
#endif
temp = LE_R1_POK;
- cpu_physical_memory_write(&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
+ cpu_physical_memory_write((uint32_t)&ib->brx_ring[i].rmd1_bits, (void *) &temp, 1);
s->regs[LE_CSR0] |= LE_C0_RINT | LE_C0_INTR;
if ((s->regs[LE_CSR0] & LE_C0_INTR) && (s->regs[LE_CSR0] & LE_C0_INEA))
pic_set_irq(s->irq, 1);
@@ -364,7 +361,7 @@ static void lance_receive(void *opaque, const uint8_t *buf, int size)
static void lance_send(void *opaque)
{
LANCEState *s = opaque;
- void *dmaptr = (void *) (s->leptr + s->ledma->regs[3]);
+ uint32_t dmaptr = s->leptr + s->ledmaregs[3];
struct lance_init_block *ib;
unsigned int i, old_txptr, j;
uint16_t temp;
@@ -375,18 +372,18 @@ static void lance_send(void *opaque)
ib = (void *) iommu_translate(dmaptr);
- old_txptr = txptr;
- for (i = txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
- cpu_physical_memory_read(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
+ old_txptr = s->txptr;
+ for (i = s->txptr; i != ((old_txptr - 1) & TX_RING_MOD_MASK); i = (i + 1) & TX_RING_MOD_MASK) {
+ cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
if (temp == (LE_T1_POK|LE_T1_OWN)) {
- cpu_physical_memory_read(&ib->btx_ring[i].length, (void *) &temp, 2);
+ cpu_physical_memory_read((uint32_t)&ib->btx_ring[i].length, (void *) &temp, 2);
bswap16s(&temp);
temp = (~temp) + 1;
#if 0
- cpu_physical_memory_read(&ib->tx_buf[i], pkt_buf, temp);
+ cpu_physical_memory_read((uint32_t)&ib->tx_buf[i], pkt_buf, temp);
#else
for (j = 0; j < temp; j++) {
- cpu_physical_memory_read(((void *)&ib->tx_buf[i]) + j, &pkt_buf[j], 1);
+ cpu_physical_memory_read((uint32_t)&ib->tx_buf[i] + j, &pkt_buf[j], 1);
}
#endif
@@ -395,8 +392,8 @@ static void lance_send(void *opaque)
#endif
qemu_send_packet(s->nd, pkt_buf, temp);
temp = LE_T1_POK;
- cpu_physical_memory_write(&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
- txptr = (txptr + 1) & TX_RING_MOD_MASK;
+ cpu_physical_memory_write((uint32_t)&ib->btx_ring[i].tmd1_bits, (void *) &temp, 1);
+ s->txptr = (s->txptr + 1) & TX_RING_MOD_MASK;
s->regs[LE_CSR0] |= LE_C0_TINT | LE_C0_INTR;
}
}
@@ -404,24 +401,20 @@ static void lance_send(void *opaque)
static uint32_t ledma_mem_readl(void *opaque, target_phys_addr_t addr)
{
- LEDMAState *s = opaque;
+ LANCEState *s = opaque;
uint32_t saddr;
- saddr = (addr - s->addr) >> 2;
- if (saddr < LEDMA_REGS)
- return s->regs[saddr];
- else
- return 0;
+ saddr = (addr & LEDMA_MAXADDR) >> 2;
+ return s->ledmaregs[saddr];
}
static void ledma_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
{
- LEDMAState *s = opaque;
+ LANCEState *s = opaque;
uint32_t saddr;
- saddr = (addr - s->addr) >> 2;
- if (saddr < LEDMA_REGS)
- s->regs[saddr] = val;
+ saddr = (addr & LEDMA_MAXADDR) >> 2;
+ s->ledmaregs[saddr] = val;
}
static CPUReadMemoryFunc *ledma_mem_read[3] = {
@@ -436,33 +429,61 @@ static CPUWriteMemoryFunc *ledma_mem_write[3] = {
ledma_mem_writel,
};
+static void lance_save(QEMUFile *f, void *opaque)
+{
+ LANCEState *s = opaque;
+ int i;
+
+ qemu_put_be32s(f, &s->leptr);
+ qemu_put_be16s(f, &s->addr);
+ for (i = 0; i < LE_MAXREG; i ++)
+ qemu_put_be16s(f, &s->regs[i]);
+ qemu_put_buffer(f, s->phys, 6);
+ qemu_put_be32s(f, &s->irq);
+ for (i = 0; i < LEDMA_REGS; i ++)
+ qemu_put_be32s(f, &s->ledmaregs[i]);
+}
+
+static int lance_load(QEMUFile *f, void *opaque, int version_id)
+{
+ LANCEState *s = opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f, &s->leptr);
+ qemu_get_be16s(f, &s->addr);
+ for (i = 0; i < LE_MAXREG; i ++)
+ qemu_get_be16s(f, &s->regs[i]);
+ qemu_get_buffer(f, s->phys, 6);
+ qemu_get_be32s(f, &s->irq);
+ for (i = 0; i < LEDMA_REGS; i ++)
+ qemu_get_be32s(f, &s->ledmaregs[i]);
+ return 0;
+}
+
void lance_init(NetDriverState *nd, int irq, uint32_t leaddr, uint32_t ledaddr)
{
LANCEState *s;
- LEDMAState *led;
int lance_io_memory, ledma_io_memory;
s = qemu_mallocz(sizeof(LANCEState));
if (!s)
return;
- s->paddr = leaddr;
s->nd = nd;
s->irq = irq;
lance_io_memory = cpu_register_io_memory(0, lance_mem_read, lance_mem_write, s);
cpu_register_physical_memory(leaddr, 8, lance_io_memory);
- led = qemu_mallocz(sizeof(LEDMAState));
- if (!led)
- return;
-
- s->ledma = led;
- led->addr = ledaddr;
- ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, led);
+ ledma_io_memory = cpu_register_io_memory(0, ledma_mem_read, ledma_mem_write, s);
cpu_register_physical_memory(ledaddr, 16, ledma_io_memory);
lance_reset(s);
qemu_add_read_packet(nd, lance_can_receive, lance_receive, s);
+ register_savevm("lance", leaddr, 1, lance_save, lance_load, s);
+ qemu_register_reset(lance_reset, s);
}
diff --git a/hw/m48t08.c b/hw/m48t08.c
index 46ec66557..094587953 100644
--- a/hw/m48t08.c
+++ b/hw/m48t08.c
@@ -32,19 +32,14 @@
#define NVRAM_PRINTF(fmt, args...) do { } while (0)
#endif
-#define NVRAM_MAX_MEM 0xfff0
+#define NVRAM_MAX_MEM 0x1ff0
+#define NVRAM_MAXADDR 0x1fff
struct m48t08_t {
- /* Hardware parameters */
- int mem_index;
- uint32_t mem_base;
- uint16_t size;
/* RTC management */
time_t time_offset;
time_t stop_time;
/* NVRAM storage */
- uint8_t lock;
- uint16_t addr;
uint8_t *buffer;
};
@@ -83,14 +78,13 @@ static void set_time (m48t08_t *NVRAM, struct tm *tm)
}
/* Direct access to NVRAM */
-void m48t08_write (m48t08_t *NVRAM, uint32_t val)
+void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val)
{
struct tm tm;
int tmp;
- if (NVRAM->addr > NVRAM_MAX_MEM && NVRAM->addr < 0x2000)
- NVRAM_PRINTF("%s: 0x%08x => 0x%08x\n", __func__, NVRAM->addr, val);
- switch (NVRAM->addr) {
+ addr &= NVRAM_MAXADDR;
+ switch (addr) {
case 0x1FF8:
/* control */
NVRAM->buffer[0x1FF8] = (val & ~0xA0) | 0x90;
@@ -167,25 +161,18 @@ void m48t08_write (m48t08_t *NVRAM, uint32_t val)
}
break;
default:
- /* Check lock registers state */
- if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
- break;
- if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
- break;
- if (NVRAM->addr < NVRAM_MAX_MEM ||
- (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
- NVRAM->buffer[NVRAM->addr] = val & 0xFF;
- }
+ NVRAM->buffer[addr] = val & 0xFF;
break;
}
}
-uint32_t m48t08_read (m48t08_t *NVRAM)
+uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr)
{
struct tm tm;
- uint32_t retval = 0xFF;
+ uint8_t retval = 0xFF;
- switch (NVRAM->addr) {
+ addr &= NVRAM_MAXADDR;
+ switch (addr) {
case 0x1FF8:
/* control */
goto do_read;
@@ -225,65 +212,36 @@ uint32_t m48t08_read (m48t08_t *NVRAM)
retval = toBCD(tm.tm_year);
break;
default:
- /* Check lock registers state */
- if (NVRAM->addr >= 0x20 && NVRAM->addr <= 0x2F && (NVRAM->lock & 1))
- break;
- if (NVRAM->addr >= 0x30 && NVRAM->addr <= 0x3F && (NVRAM->lock & 2))
- break;
- if (NVRAM->addr < NVRAM_MAX_MEM ||
- (NVRAM->addr > 0x1FFF && NVRAM->addr < NVRAM->size)) {
- do_read:
- retval = NVRAM->buffer[NVRAM->addr];
- }
+ do_read:
+ retval = NVRAM->buffer[addr];
break;
}
- if (NVRAM->addr > NVRAM_MAX_MEM + 1 && NVRAM->addr < 0x2000)
- NVRAM_PRINTF("0x%08x <= 0x%08x\n", NVRAM->addr, retval);
-
return retval;
}
-void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr)
-{
- NVRAM->addr = addr;
-}
-
-void m48t08_toggle_lock (m48t08_t *NVRAM, int lock)
-{
- NVRAM->lock ^= 1 << lock;
-}
-
static void nvram_writeb (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
- addr -= NVRAM->mem_base;
- if (addr < NVRAM_MAX_MEM)
- NVRAM->buffer[addr] = value;
+ m48t08_write(NVRAM, addr, value);
}
static void nvram_writew (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
- addr -= NVRAM->mem_base;
- if (addr < NVRAM_MAX_MEM) {
- NVRAM->buffer[addr] = value >> 8;
- NVRAM->buffer[addr + 1] = value;
- }
+ m48t08_write(NVRAM, addr, value);
+ m48t08_write(NVRAM, addr + 1, value >> 8);
}
static void nvram_writel (void *opaque, target_phys_addr_t addr, uint32_t value)
{
m48t08_t *NVRAM = opaque;
- addr -= NVRAM->mem_base;
- if (addr < NVRAM_MAX_MEM) {
- NVRAM->buffer[addr] = value >> 24;
- NVRAM->buffer[addr + 1] = value >> 16;
- NVRAM->buffer[addr + 2] = value >> 8;
- NVRAM->buffer[addr + 3] = value;
- }
+ m48t08_write(NVRAM, addr, value);
+ m48t08_write(NVRAM, addr + 1, value >> 8);
+ m48t08_write(NVRAM, addr + 2, value >> 16);
+ m48t08_write(NVRAM, addr + 3, value >> 24);
}
static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
@@ -291,10 +249,7 @@ static uint32_t nvram_readb (void *opaque, target_phys_addr_t addr)
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
- addr -= NVRAM->mem_base;
- if (addr < NVRAM_MAX_MEM)
- retval = NVRAM->buffer[addr];
-
+ retval = m48t08_read(NVRAM, addr);
return retval;
}
@@ -303,12 +258,8 @@ static uint32_t nvram_readw (void *opaque, target_phys_addr_t addr)
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
- addr -= NVRAM->mem_base;
- if (addr < NVRAM_MAX_MEM) {
- retval = NVRAM->buffer[addr] << 8;
- retval |= NVRAM->buffer[addr + 1];
- }
-
+ retval = m48t08_read(NVRAM, addr) << 8;
+ retval |= m48t08_read(NVRAM, addr + 1);
return retval;
}
@@ -317,14 +268,10 @@ static uint32_t nvram_readl (void *opaque, target_phys_addr_t addr)
m48t08_t *NVRAM = opaque;
uint32_t retval = 0;
- addr -= NVRAM->mem_base;
- if (addr < NVRAM_MAX_MEM) {
- retval = NVRAM->buffer[addr] << 24;
- retval |= NVRAM->buffer[addr + 1] << 16;
- retval |= NVRAM->buffer[addr + 2] << 8;
- retval |= NVRAM->buffer[addr + 3];
- }
-
+ retval = m48t08_read(NVRAM, addr) << 24;
+ retval |= m48t08_read(NVRAM, addr + 1) << 16;
+ retval |= m48t08_read(NVRAM, addr + 2) << 8;
+ retval |= m48t08_read(NVRAM, addr + 3);
return retval;
}
@@ -340,12 +287,42 @@ static CPUReadMemoryFunc *nvram_read[] = {
&nvram_readl,
};
+static void nvram_save(QEMUFile *f, void *opaque)
+{
+ m48t08_t *s = opaque;
+
+ qemu_put_be32s(f, (uint32_t *)&s->time_offset);
+ qemu_put_be32s(f, (uint32_t *)&s->stop_time);
+ qemu_put_buffer(f, s->buffer, 0x2000);
+}
+
+static int nvram_load(QEMUFile *f, void *opaque, int version_id)
+{
+ m48t08_t *s = opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f, (uint32_t *)&s->time_offset);
+ qemu_get_be32s(f, (uint32_t *)&s->stop_time);
+ qemu_get_buffer(f, s->buffer, 0x2000);
+ return 0;
+}
+
+static void m48t08_reset(void *opaque)
+{
+ m48t08_t *s = opaque;
+
+ s->time_offset = 0;
+ s->stop_time = 0;
+}
+
+
/* Initialisation routine */
-m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr)
+m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size)
{
m48t08_t *s;
- int i;
- unsigned char tmp = 0;
+ int mem_index;
s = qemu_mallocz(sizeof(m48t08_t));
if (!s)
@@ -355,25 +332,13 @@ m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr)
qemu_free(s);
return NULL;
}
- s->size = size;
- s->mem_base = mem_base;
- s->addr = 0;
if (mem_base != 0) {
- s->mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
- cpu_register_physical_memory(mem_base, 0x4000, s->mem_index);
+ mem_index = cpu_register_io_memory(0, nvram_read, nvram_write, s);
+ cpu_register_physical_memory(mem_base, 0x2000, mem_index);
}
- s->lock = 0;
- i = 0x1fd8;
- s->buffer[i++] = 0x01;
- s->buffer[i++] = 0x80; /* Sun4m OBP */
- memcpy(&s->buffer[i], macaddr, 6);
-
- /* Calculate checksum */
- for (i = 0x1fd8; i < 0x1fe7; i++) {
- tmp ^= s->buffer[i];
- }
- s->buffer[0x1fe7] = tmp;
+ register_savevm("nvram", mem_base, 1, nvram_save, nvram_load, s);
+ qemu_register_reset(m48t08_reset, s);
return s;
}
diff --git a/hw/m48t08.h b/hw/m48t08.h
index 9b44bc0d1..985116a09 100644
--- a/hw/m48t08.h
+++ b/hw/m48t08.h
@@ -3,10 +3,8 @@
typedef struct m48t08_t m48t08_t;
-void m48t08_write (m48t08_t *NVRAM, uint32_t val);
-uint32_t m48t08_read (m48t08_t *NVRAM);
-void m48t08_set_addr (m48t08_t *NVRAM, uint32_t addr);
-void m48t08_toggle_lock (m48t08_t *NVRAM, int lock);
-m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size, uint8_t *macaddr);
+void m48t08_write (m48t08_t *NVRAM, uint32_t addr, uint8_t val);
+uint8_t m48t08_read (m48t08_t *NVRAM, uint32_t addr);
+m48t08_t *m48t08_init(uint32_t mem_base, uint16_t size);
#endif /* !defined (__M48T08_H__) */
diff --git a/hw/magic-load.c b/hw/magic-load.c
index 06a5f743a..713343a75 100644
--- a/hw/magic-load.c
+++ b/hw/magic-load.c
@@ -1,5 +1,54 @@
#include "vl.h"
#include "disas.h"
+#include "exec-all.h"
+
+struct exec
+{
+ uint32_t a_info; /* Use macros N_MAGIC, etc for access */
+ uint32_t a_text; /* length of text, in bytes */
+ uint32_t a_data; /* length of data, in bytes */
+ uint32_t a_bss; /* length of uninitialized data area, in bytes */
+ uint32_t a_syms; /* length of symbol table data in file, in bytes */
+ uint32_t a_entry; /* start address */
+ uint32_t a_trsize; /* length of relocation info for text, in bytes */
+ uint32_t a_drsize; /* length of relocation info for data, in bytes */
+};
+
+#ifdef BSWAP_NEEDED
+static void bswap_ahdr(struct exec *e)
+{
+ bswap32s(&e->a_info);
+ bswap32s(&e->a_text);
+ bswap32s(&e->a_data);
+ bswap32s(&e->a_bss);
+ bswap32s(&e->a_syms);
+ bswap32s(&e->a_entry);
+ bswap32s(&e->a_trsize);
+ bswap32s(&e->a_drsize);
+}
+#else
+#define bswap_ahdr(x) do { } while (0)
+#endif
+
+#define N_MAGIC(exec) ((exec).a_info & 0xffff)
+#define OMAGIC 0407
+#define NMAGIC 0410
+#define ZMAGIC 0413
+#define QMAGIC 0314
+#define _N_HDROFF(x) (1024 - sizeof (struct exec))
+#define N_TXTOFF(x) \
+ (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \
+ (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec)))
+#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? TARGET_PAGE_SIZE : 0)
+#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text)
+#define _N_SEGMENT_ROUND(x) (((x) + TARGET_PAGE_SIZE - 1) & ~(TARGET_PAGE_SIZE - 1))
+
+#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text)
+
+#define N_DATADDR(x) \
+ (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \
+ : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x))))
+
#define ELF_CLASS ELFCLASS32
#define ELF_DATA ELFDATA2MSB
@@ -103,27 +152,27 @@ static void *find_shdr(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, uint3
return NULL;
}
-static int find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
+static void *find_strtab(struct elfhdr *ehdr, int fd, struct elf_shdr *shdr, struct elf_shdr *symtab)
{
int retval;
retval = lseek(fd, ehdr->e_shoff + sizeof(struct elf_shdr) * symtab->sh_link, SEEK_SET);
if (retval < 0)
- return -1;
+ return NULL;
retval = read(fd, shdr, sizeof(*shdr));
if (retval < 0)
- return -1;
+ return NULL;
bswap_shdr(shdr);
if (shdr->sh_type == SHT_STRTAB)
return qemu_malloc(shdr->sh_size);;
- return 0;
+ return NULL;
}
-static int read_program(int fd, struct elf_phdr *phdr, void *dst)
+static int read_program(int fd, struct elf_phdr *phdr, void *dst, uint32_t entry)
{
int retval;
- retval = lseek(fd, 0x4000, SEEK_SET);
+ retval = lseek(fd, phdr->p_offset + entry - phdr->p_vaddr, SEEK_SET);
if (retval < 0)
return -1;
return read(fd, dst, phdr->p_filesz);
@@ -178,6 +227,7 @@ static void load_symbols(struct elfhdr *ehdr, int fd)
{
struct elf_shdr symtab, strtab;
struct elf_sym *syms;
+ struct syminfo *s;
int nsyms, i;
char *str;
@@ -196,20 +246,19 @@ static void load_symbols(struct elfhdr *ehdr, int fd)
goto error_freesyms;
/* Commit */
- if (disas_symtab)
- qemu_free(disas_symtab); /* XXX Merge with old symbols? */
- if (disas_strtab)
- qemu_free(disas_strtab);
- disas_symtab = syms;
- disas_num_syms = nsyms;
- disas_strtab = str;
+ s = qemu_mallocz(sizeof(*s));
+ s->disas_symtab = syms;
+ s->disas_num_syms = nsyms;
+ s->disas_strtab = str;
+ s->next = syminfos;
+ syminfos = s;
return;
error_freesyms:
qemu_free(syms);
return;
}
-int load_elf(const char * filename, uint8_t *addr)
+int load_elf(const char *filename, uint8_t *addr)
{
struct elfhdr ehdr;
struct elf_phdr phdr;
@@ -227,12 +276,13 @@ int load_elf(const char * filename, uint8_t *addr)
if (ehdr.e_ident[0] != 0x7f || ehdr.e_ident[1] != 'E'
|| ehdr.e_ident[2] != 'L' || ehdr.e_ident[3] != 'F'
- || ehdr.e_machine != EM_SPARC)
+ || (ehdr.e_machine != EM_SPARC
+ && ehdr.e_machine != EM_SPARC32PLUS))
goto error;
if (find_phdr(&ehdr, fd, &phdr, PT_LOAD))
goto error;
- retval = read_program(fd, &phdr, addr);
+ retval = read_program(fd, &phdr, addr, ehdr.e_entry);
if (retval < 0)
goto error;
@@ -245,17 +295,45 @@ int load_elf(const char * filename, uint8_t *addr)
return -1;
}
-int load_kernel(const char *filename, uint8_t *addr)
+int load_aout(const char *filename, uint8_t *addr)
{
- int fd, size;
+ int fd, size, ret;
+ struct exec e;
+ uint32_t magic;
fd = open(filename, O_RDONLY | O_BINARY);
if (fd < 0)
return -1;
- /* load 32 bit code */
- size = read(fd, addr, 16 * 1024 * 1024);
+
+ size = read(fd, &e, sizeof(e));
if (size < 0)
goto fail;
+
+ bswap_ahdr(&e);
+
+ magic = N_MAGIC(e);
+ switch (magic) {
+ case ZMAGIC:
+ case QMAGIC:
+ case OMAGIC:
+ lseek(fd, N_TXTOFF(e), SEEK_SET);
+ size = read(fd, addr, e.a_text + e.a_data);
+ if (size < 0)
+ goto fail;
+ break;
+ case NMAGIC:
+ lseek(fd, N_TXTOFF(e), SEEK_SET);
+ size = read(fd, addr, e.a_text);
+ if (size < 0)
+ goto fail;
+ ret = read(fd, addr + N_DATADDR(e), e.a_data);
+ if (ret < 0)
+ goto fail;
+ size += ret;
+ break;
+ default:
+ goto fail;
+ }
close(fd);
return size;
fail:
@@ -263,64 +341,3 @@ int load_kernel(const char *filename, uint8_t *addr)
return -1;
}
-typedef struct MAGICState {
- uint32_t addr;
- uint32_t saved_addr;
- int magic_state;
- char saved_kfn[1024];
-} MAGICState;
-
-static uint32_t magic_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- int ret;
- MAGICState *s = opaque;
-
- if (s->magic_state == 0) {
- ret = load_elf(s->saved_kfn, (uint8_t *)s->saved_addr);
- if (ret < 0)
- ret = load_kernel(s->saved_kfn, (uint8_t *)s->saved_addr);
- if (ret < 0) {
- fprintf(stderr, "qemu: could not load kernel '%s'\n",
- s->saved_kfn);
- }
- s->magic_state = 1; /* No more magic */
- tb_flush();
- return bswap32(ret);
- }
- return 0;
-}
-
-static void magic_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
-}
-
-
-static CPUReadMemoryFunc *magic_mem_read[3] = {
- magic_mem_readl,
- magic_mem_readl,
- magic_mem_readl,
-};
-
-static CPUWriteMemoryFunc *magic_mem_write[3] = {
- magic_mem_writel,
- magic_mem_writel,
- magic_mem_writel,
-};
-
-void magic_init(const char *kfn, int kloadaddr, uint32_t addr)
-{
- int magic_io_memory;
- MAGICState *s;
-
- s = qemu_mallocz(sizeof(MAGICState));
- if (!s)
- return;
-
- strcpy(s->saved_kfn, kfn);
- s->saved_addr = kloadaddr;
- s->magic_state = 0;
- s->addr = addr;
- magic_io_memory = cpu_register_io_memory(0, magic_mem_read, magic_mem_write, s);
- cpu_register_physical_memory(addr, 4, magic_io_memory);
-}
-
diff --git a/hw/sched.c b/hw/sched.c
deleted file mode 100644
index 2ab966de4..000000000
--- a/hw/sched.c
+++ /dev/null
@@ -1,268 +0,0 @@
-/*
- * QEMU interrupt controller emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "vl.h"
-//#define DEBUG_IRQ_COUNT
-
-/* These registers are used for sending/receiving irqs from/to
- * different cpu's.
- */
-struct sun4m_intreg_percpu {
- unsigned int tbt; /* Intrs pending for this cpu, by PIL. */
- /* These next two registers are WRITE-ONLY and are only
- * "on bit" sensitive, "off bits" written have NO affect.
- */
- unsigned int clear; /* Clear this cpus irqs here. */
- unsigned int set; /* Set this cpus irqs here. */
-};
-/*
- * djhr
- * Actually the clear and set fields in this struct are misleading..
- * according to the SLAVIO manual (and the same applies for the SEC)
- * the clear field clears bits in the mask which will ENABLE that IRQ
- * the set field sets bits in the mask to DISABLE the IRQ.
- *
- * Also the undirected_xx address in the SLAVIO is defined as
- * RESERVED and write only..
- *
- * DAVEM_NOTE: The SLAVIO only specifies behavior on uniprocessor
- * sun4m machines, for MP the layout makes more sense.
- */
-struct sun4m_intreg_master {
- unsigned int tbt; /* IRQ's that are pending, see sun4m masks. */
- unsigned int irqs; /* Master IRQ bits. */
-
- /* Again, like the above, two these registers are WRITE-ONLY. */
- unsigned int clear; /* Clear master IRQ's by setting bits here. */
- unsigned int set; /* Set master IRQ's by setting bits here. */
-
- /* This register is both READ and WRITE. */
- unsigned int undirected_target; /* Which cpu gets undirected irqs. */
-};
-
-#define SUN4M_INT_ENABLE 0x80000000
-#define SUN4M_INT_E14 0x00000080
-#define SUN4M_INT_E10 0x00080000
-
-#define SUN4M_HARD_INT(x) (0x000000001 << (x))
-#define SUN4M_SOFT_INT(x) (0x000010000 << (x))
-
-#define SUN4M_INT_MASKALL 0x80000000 /* mask all interrupts */
-#define SUN4M_INT_MODULE_ERR 0x40000000 /* module error */
-#define SUN4M_INT_M2S_WRITE 0x20000000 /* write buffer error */
-#define SUN4M_INT_ECC 0x10000000 /* ecc memory error */
-#define SUN4M_INT_FLOPPY 0x00400000 /* floppy disk */
-#define SUN4M_INT_MODULE 0x00200000 /* module interrupt */
-#define SUN4M_INT_VIDEO 0x00100000 /* onboard video */
-#define SUN4M_INT_REALTIME 0x00080000 /* system timer */
-#define SUN4M_INT_SCSI 0x00040000 /* onboard scsi */
-#define SUN4M_INT_AUDIO 0x00020000 /* audio/isdn */
-#define SUN4M_INT_ETHERNET 0x00010000 /* onboard ethernet */
-#define SUN4M_INT_SERIAL 0x00008000 /* serial ports */
-#define SUN4M_INT_SBUSBITS 0x00003F80 /* sbus int bits */
-
-#define SUN4M_INT_SBUS(x) (1 << (x+7))
-#define SUN4M_INT_VME(x) (1 << (x))
-
-typedef struct SCHEDState {
- uint32_t addr, addrg;
- uint32_t intreg_pending;
- uint32_t intreg_enabled;
- uint32_t intregm_pending;
- uint32_t intregm_enabled;
-} SCHEDState;
-
-static SCHEDState *ps;
-
-#ifdef DEBUG_IRQ_COUNT
-static uint64_t irq_count[32];
-#endif
-
-static uint32_t intreg_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- SCHEDState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr - s->addr) >> 2;
- switch (saddr) {
- case 0:
- return s->intreg_pending;
- break;
- default:
- break;
- }
- return 0;
-}
-
-static void intreg_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- SCHEDState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr - s->addr) >> 2;
- switch (saddr) {
- case 0:
- s->intreg_pending = val;
- break;
- case 1: // clear
- s->intreg_enabled &= ~val;
- break;
- case 2: // set
- s->intreg_enabled |= val;
- break;
- default:
- break;
- }
-}
-
-static CPUReadMemoryFunc *intreg_mem_read[3] = {
- intreg_mem_readl,
- intreg_mem_readl,
- intreg_mem_readl,
-};
-
-static CPUWriteMemoryFunc *intreg_mem_write[3] = {
- intreg_mem_writel,
- intreg_mem_writel,
- intreg_mem_writel,
-};
-
-static uint32_t intregm_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- SCHEDState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr - s->addrg) >> 2;
- switch (saddr) {
- case 0:
- return s->intregm_pending;
- break;
- case 1:
- return s->intregm_enabled;
- break;
- default:
- break;
- }
- return 0;
-}
-
-static void intregm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- SCHEDState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr - s->addrg) >> 2;
- switch (saddr) {
- case 0:
- s->intregm_pending = val;
- break;
- case 1:
- s->intregm_enabled = val;
- break;
- case 2: // clear
- s->intregm_enabled &= ~val;
- break;
- case 3: // set
- s->intregm_enabled |= val;
- break;
- default:
- break;
- }
-}
-
-static CPUReadMemoryFunc *intregm_mem_read[3] = {
- intregm_mem_readl,
- intregm_mem_readl,
- intregm_mem_readl,
-};
-
-static CPUWriteMemoryFunc *intregm_mem_write[3] = {
- intregm_mem_writel,
- intregm_mem_writel,
- intregm_mem_writel,
-};
-
-void pic_info(void)
-{
- term_printf("per-cpu: pending 0x%08x, enabled 0x%08x\n", ps->intreg_pending, ps->intreg_enabled);
- term_printf("master: pending 0x%08x, enabled 0x%08x\n", ps->intregm_pending, ps->intregm_enabled);
-}
-
-void irq_info(void)
-{
-#ifndef DEBUG_IRQ_COUNT
- term_printf("irq statistic code not compiled.\n");
-#else
- int i;
- int64_t count;
-
- term_printf("IRQ statistics:\n");
- for (i = 0; i < 32; i++) {
- count = irq_count[i];
- if (count > 0)
- term_printf("%2d: %lld\n", i, count);
- }
-#endif
-}
-
-static const unsigned int intr_to_mask[16] = {
- 0, 0, 0, 0, 0, 0, SUN4M_INT_ETHERNET, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
-};
-
-void pic_set_irq(int irq, int level)
-{
- if (irq < 16) {
- unsigned int mask = intr_to_mask[irq];
- ps->intreg_pending |= 1 << irq;
- if (ps->intregm_enabled & mask) {
- cpu_single_env->interrupt_index = irq;
- cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
- }
- }
-#ifdef DEBUG_IRQ_COUNT
- if (level == 1)
- irq_count[irq]++;
-#endif
-}
-
-void sched_init(uint32_t addr, uint32_t addrg)
-{
- int intreg_io_memory, intregm_io_memory;
- SCHEDState *s;
-
- s = qemu_mallocz(sizeof(SCHEDState));
- if (!s)
- return;
- s->addr = addr;
- s->addrg = addrg;
-
- intreg_io_memory = cpu_register_io_memory(0, intreg_mem_read, intreg_mem_write, s);
- cpu_register_physical_memory(addr, 3, intreg_io_memory);
-
- intregm_io_memory = cpu_register_io_memory(0, intregm_mem_read, intregm_mem_write, s);
- cpu_register_physical_memory(addrg, 5, intregm_io_memory);
-
- ps = s;
-}
-
diff --git a/hw/slavio_intctl.c b/hw/slavio_intctl.c
new file mode 100644
index 000000000..745467214
--- /dev/null
+++ b/hw/slavio_intctl.c
@@ -0,0 +1,299 @@
+/*
+ * QEMU Sparc SLAVIO interrupt controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+//#define DEBUG_IRQ_COUNT
+
+/*
+ * Registers of interrupt controller in sun4m.
+ *
+ * This is the interrupt controller part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * There is a system master controller and one for each cpu.
+ *
+ */
+
+#define MAX_CPUS 16
+
+typedef struct SLAVIO_INTCTLState {
+ uint32_t intreg_pending[MAX_CPUS];
+ uint32_t intregm_pending;
+ uint32_t intregm_disabled;
+ uint32_t target_cpu;
+#ifdef DEBUG_IRQ_COUNT
+ uint64_t irq_count[32];
+#endif
+} SLAVIO_INTCTLState;
+
+#define INTCTL_MAXADDR 0xf
+#define INTCTLM_MAXADDR 0xf
+
+// per-cpu interrupt controller
+static uint32_t slavio_intctl_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ uint32_t saddr;
+ int cpu;
+
+ cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
+ saddr = (addr & INTCTL_MAXADDR) >> 2;
+ switch (saddr) {
+ case 0:
+ return s->intreg_pending[cpu];
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void slavio_intctl_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ uint32_t saddr;
+ int cpu;
+
+ cpu = (addr & (MAX_CPUS - 1) * TARGET_PAGE_SIZE) >> 12;
+ saddr = (addr & INTCTL_MAXADDR) >> 2;
+ switch (saddr) {
+ case 1: // clear pending softints
+ if (val & 0x4000)
+ val |= 80000000;
+ val &= 0xfffe0000;
+ s->intreg_pending[cpu] &= ~val;
+ break;
+ case 2: // set softint
+ val &= 0xfffe0000;
+ s->intreg_pending[cpu] |= val;
+ break;
+ default:
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *slavio_intctl_mem_read[3] = {
+ slavio_intctl_mem_readl,
+ slavio_intctl_mem_readl,
+ slavio_intctl_mem_readl,
+};
+
+static CPUWriteMemoryFunc *slavio_intctl_mem_write[3] = {
+ slavio_intctl_mem_writel,
+ slavio_intctl_mem_writel,
+ slavio_intctl_mem_writel,
+};
+
+// master system interrupt controller
+static uint32_t slavio_intctlm_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ uint32_t saddr;
+
+ saddr = (addr & INTCTLM_MAXADDR) >> 2;
+ switch (saddr) {
+ case 0:
+ return s->intregm_pending;
+ case 1:
+ return s->intregm_disabled;
+ case 4:
+ return s->target_cpu;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static void slavio_intctlm_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ uint32_t saddr;
+
+ saddr = (addr & INTCTLM_MAXADDR) >> 2;
+ switch (saddr) {
+ case 2: // clear (enable)
+ // Force unused bits
+ val |= 0x7fb2007f;
+ s->intregm_disabled &= ~val;
+ break;
+ case 3: // set (disable, clear pending)
+ // Force unused bits
+ val &= ~0x7fb2007f;
+ s->intregm_disabled |= val;
+ s->intregm_pending &= ~val;
+ break;
+ case 4:
+ s->target_cpu = val & (MAX_CPUS - 1);
+ break;
+ default:
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *slavio_intctlm_mem_read[3] = {
+ slavio_intctlm_mem_readl,
+ slavio_intctlm_mem_readl,
+ slavio_intctlm_mem_readl,
+};
+
+static CPUWriteMemoryFunc *slavio_intctlm_mem_write[3] = {
+ slavio_intctlm_mem_writel,
+ slavio_intctlm_mem_writel,
+ slavio_intctlm_mem_writel,
+};
+
+void slavio_pic_info(void *opaque)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ int i;
+
+ for (i = 0; i < MAX_CPUS; i++) {
+ term_printf("per-cpu %d: pending 0x%08x\n", i, s->intreg_pending[i]);
+ }
+ term_printf("master: pending 0x%08x, disabled 0x%08x\n", s->intregm_pending, s->intregm_disabled);
+}
+
+void slavio_irq_info(void *opaque)
+{
+#ifndef DEBUG_IRQ_COUNT
+ term_printf("irq statistic code not compiled.\n");
+#else
+ SLAVIO_INTCTLState *s = opaque;
+ int i;
+ int64_t count;
+
+ term_printf("IRQ statistics:\n");
+ for (i = 0; i < 32; i++) {
+ count = s->irq_count[i];
+ if (count > 0)
+ term_printf("%2d: %lld\n", i, count);
+ }
+#endif
+}
+
+static const uint32_t intbit_to_level[32] = {
+ 2, 3, 5, 7, 9, 11, 0, 14, 3, 5, 7, 9, 11, 13, 12, 12,
+ 6, 0, 4, 10, 8, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0,
+};
+
+/*
+ * "irq" here is the bit number in the system interrupt register to
+ * separate serial and keyboard interrupts sharing a level.
+ */
+void slavio_pic_set_irq(void *opaque, int irq, int level)
+{
+ SLAVIO_INTCTLState *s = opaque;
+
+ if (irq < 32) {
+ uint32_t mask = 1 << irq;
+ uint32_t pil = intbit_to_level[irq];
+ if (pil > 0) {
+ if (level) {
+ s->intregm_pending |= mask;
+ s->intreg_pending[s->target_cpu] |= 1 << pil;
+ }
+ else {
+ s->intregm_pending &= ~mask;
+ s->intreg_pending[s->target_cpu] &= ~(1 << pil);
+ }
+ if (level &&
+ !(s->intregm_disabled & mask) &&
+ !(s->intregm_disabled & 0x80000000) &&
+ (pil == 15 || (pil > cpu_single_env->psrpil && cpu_single_env->psret == 1))) {
+#ifdef DEBUG_IRQ_COUNT
+ if (level == 1)
+ s->irq_count[pil]++;
+#endif
+ cpu_single_env->interrupt_index = TT_EXTINT | pil;
+ cpu_interrupt(cpu_single_env, CPU_INTERRUPT_HARD);
+ }
+ }
+ }
+}
+
+static void slavio_intctl_save(QEMUFile *f, void *opaque)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ int i;
+
+ for (i = 0; i < MAX_CPUS; i++) {
+ qemu_put_be32s(f, &s->intreg_pending[i]);
+ }
+ qemu_put_be32s(f, &s->intregm_pending);
+ qemu_put_be32s(f, &s->intregm_disabled);
+ qemu_put_be32s(f, &s->target_cpu);
+}
+
+static int slavio_intctl_load(QEMUFile *f, void *opaque, int version_id)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ int i;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ for (i = 0; i < MAX_CPUS; i++) {
+ qemu_get_be32s(f, &s->intreg_pending[i]);
+ }
+ qemu_get_be32s(f, &s->intregm_pending);
+ qemu_get_be32s(f, &s->intregm_disabled);
+ qemu_get_be32s(f, &s->target_cpu);
+ return 0;
+}
+
+static void slavio_intctl_reset(void *opaque)
+{
+ SLAVIO_INTCTLState *s = opaque;
+ int i;
+
+ for (i = 0; i < MAX_CPUS; i++) {
+ s->intreg_pending[i] = 0;
+ }
+ s->intregm_disabled = 0xffffffff;
+ s->intregm_pending = 0;
+ s->target_cpu = 0;
+}
+
+void *slavio_intctl_init(uint32_t addr, uint32_t addrg)
+{
+ int slavio_intctl_io_memory, slavio_intctlm_io_memory, i;
+ SLAVIO_INTCTLState *s;
+
+ s = qemu_mallocz(sizeof(SLAVIO_INTCTLState));
+ if (!s)
+ return NULL;
+
+ for (i = 0; i < MAX_CPUS; i++) {
+ slavio_intctl_io_memory = cpu_register_io_memory(0, slavio_intctl_mem_read, slavio_intctl_mem_write, s);
+ cpu_register_physical_memory(addr + i * TARGET_PAGE_SIZE, INTCTL_MAXADDR, slavio_intctl_io_memory);
+ }
+
+ slavio_intctlm_io_memory = cpu_register_io_memory(0, slavio_intctlm_mem_read, slavio_intctlm_mem_write, s);
+ cpu_register_physical_memory(addrg, INTCTLM_MAXADDR, slavio_intctlm_io_memory);
+
+ register_savevm("slavio_intctl", addr, 1, slavio_intctl_save, slavio_intctl_load, s);
+ qemu_register_reset(slavio_intctl_reset, s);
+ slavio_intctl_reset(s);
+ return s;
+}
+
diff --git a/hw/slavio_serial.c b/hw/slavio_serial.c
new file mode 100644
index 000000000..348f328f5
--- /dev/null
+++ b/hw/slavio_serial.c
@@ -0,0 +1,364 @@
+/*
+ * QEMU Sparc SLAVIO serial port emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+//#define DEBUG_SERIAL
+
+/* debug keyboard */
+//#define DEBUG_KBD
+
+/* debug keyboard : only mouse */
+//#define DEBUG_MOUSE
+
+/*
+ * This is the serial port, mouse and keyboard part of chip STP2001
+ * (Slave I/O), also produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
+ * mouse and keyboard ports don't implement all functions and they are
+ * only asynchronous. There is no DMA.
+ *
+ */
+
+typedef struct ChannelState {
+ int irq;
+ int reg;
+ int rxint, txint;
+ uint8_t rx, tx, wregs[16], rregs[16];
+ CharDriverState *chr;
+} ChannelState;
+
+struct SerialState {
+ struct ChannelState chn[2];
+};
+
+#define SERIAL_MAXADDR 7
+
+static void slavio_serial_update_irq(ChannelState *s)
+{
+ if ((s->wregs[1] & 1) && // interrupts enabled
+ (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
+ ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
+ s->rxint == 1) || // rx ints enabled, pending
+ ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
+ pic_set_irq(s->irq, 1);
+ } else {
+ pic_set_irq(s->irq, 0);
+ }
+}
+
+static void slavio_serial_reset_chn(ChannelState *s)
+{
+ int i;
+
+ s->reg = 0;
+ for (i = 0; i < SERIAL_MAXADDR; i++) {
+ s->rregs[i] = 0;
+ s->wregs[i] = 0;
+ }
+ s->wregs[4] = 4;
+ s->wregs[9] = 0xc0;
+ s->wregs[11] = 8;
+ s->wregs[14] = 0x30;
+ s->wregs[15] = 0xf8;
+ s->rregs[0] = 0x44;
+ s->rregs[1] = 6;
+
+ s->rx = s->tx = 0;
+ s->rxint = s->txint = 0;
+}
+
+static void slavio_serial_reset(void *opaque)
+{
+ SerialState *s = opaque;
+ slavio_serial_reset_chn(&s->chn[0]);
+ slavio_serial_reset_chn(&s->chn[1]);
+}
+
+static void slavio_serial_mem_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+ SerialState *ser = opaque;
+ ChannelState *s;
+ uint32_t saddr;
+ int newreg, channel;
+
+ val &= 0xff;
+ saddr = (addr & 3) >> 1;
+ channel = (addr & SERIAL_MAXADDR) >> 2;
+ s = &ser->chn[channel];
+ switch (saddr) {
+ case 0:
+ newreg = 0;
+ switch (s->reg) {
+ case 0:
+ newreg = val & 7;
+ val &= 0x38;
+ switch (val) {
+ case 8:
+ s->reg |= 0x8;
+ break;
+ case 0x20:
+ s->rxint = 0;
+ break;
+ case 0x28:
+ s->txint = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 1 ... 8:
+ case 10 ... 15:
+ s->wregs[s->reg] = val;
+ break;
+ case 9:
+ switch (val & 0xc0) {
+ case 0:
+ default:
+ break;
+ case 0x40:
+ slavio_serial_reset_chn(&ser->chn[1]);
+ return;
+ case 0x80:
+ slavio_serial_reset_chn(&ser->chn[0]);
+ return;
+ case 0xc0:
+ slavio_serial_reset(ser);
+ return;
+ }
+ break;
+ default:
+ break;
+ }
+ if (s->reg == 0)
+ s->reg = newreg;
+ else
+ s->reg = 0;
+ break;
+ case 1:
+ if (s->wregs[5] & 8) { // tx enabled
+ s->tx = val;
+ if (s->chr)
+ qemu_chr_write(s->chr, &s->tx, 1);
+ s->txint = 1;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static uint32_t slavio_serial_mem_readb(void *opaque, uint32_t addr)
+{
+ SerialState *ser = opaque;
+ ChannelState *s;
+ uint32_t saddr;
+ uint32_t ret;
+ int channel;
+
+ saddr = (addr & 3) >> 1;
+ channel = (addr & SERIAL_MAXADDR) >> 2;
+ s = &ser->chn[channel];
+ switch (saddr) {
+ case 0:
+ ret = s->rregs[s->reg];
+ s->reg = 0;
+ return ret;
+ case 1:
+ s->rregs[0] &= ~1;
+ return s->rx;
+ default:
+ break;
+ }
+ return 0;
+}
+
+static int serial_can_receive(void *opaque)
+{
+ ChannelState *s = opaque;
+ if (((s->wregs[3] & 1) == 0) // Rx not enabled
+ || ((s->rregs[0] & 1) == 1)) // char already available
+ return 0;
+ else
+ return 1;
+}
+
+static void serial_receive_byte(ChannelState *s, int ch)
+{
+ s->rregs[0] |= 1;
+ s->rx = ch;
+ s->rxint = 1;
+ slavio_serial_update_irq(s);
+}
+
+static void serial_receive_break(ChannelState *s)
+{
+ s->rregs[0] |= 0x80;
+ slavio_serial_update_irq(s);
+}
+
+static void serial_receive1(void *opaque, const uint8_t *buf, int size)
+{
+ ChannelState *s = opaque;
+ serial_receive_byte(s, buf[0]);
+}
+
+static void serial_event(void *opaque, int event)
+{
+ ChannelState *s = opaque;
+ if (event == CHR_EVENT_BREAK)
+ serial_receive_break(s);
+}
+
+static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
+ slavio_serial_mem_readb,
+ slavio_serial_mem_readb,
+ slavio_serial_mem_readb,
+};
+
+static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
+ slavio_serial_mem_writeb,
+ slavio_serial_mem_writeb,
+ slavio_serial_mem_writeb,
+};
+
+static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
+{
+ qemu_put_be32s(f, &s->irq);
+ qemu_put_be32s(f, &s->reg);
+ qemu_put_be32s(f, &s->rxint);
+ qemu_put_be32s(f, &s->txint);
+ qemu_put_8s(f, &s->rx);
+ qemu_put_8s(f, &s->tx);
+ qemu_put_buffer(f, s->wregs, 16);
+ qemu_put_buffer(f, s->rregs, 16);
+}
+
+static void slavio_serial_save(QEMUFile *f, void *opaque)
+{
+ SerialState *s = opaque;
+
+ slavio_serial_save_chn(f, &s->chn[0]);
+ slavio_serial_save_chn(f, &s->chn[1]);
+}
+
+static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
+{
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f, &s->irq);
+ qemu_get_be32s(f, &s->reg);
+ qemu_get_be32s(f, &s->rxint);
+ qemu_get_be32s(f, &s->txint);
+ qemu_get_8s(f, &s->rx);
+ qemu_get_8s(f, &s->tx);
+ qemu_get_buffer(f, s->wregs, 16);
+ qemu_get_buffer(f, s->rregs, 16);
+ return 0;
+}
+
+static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
+{
+ SerialState *s = opaque;
+ int ret;
+
+ ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
+ if (ret != 0)
+ return ret;
+ ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
+ return ret;
+
+}
+
+SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
+{
+ int slavio_serial_io_memory;
+ SerialState *s;
+
+ s = qemu_mallocz(sizeof(SerialState));
+ if (!s)
+ return NULL;
+ s->chn[0].irq = irq;
+ s->chn[1].irq = irq;
+ s->chn[0].chr = chr1;
+ s->chn[1].chr = chr2;
+
+ slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
+ cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
+
+ if (chr1) {
+ qemu_chr_add_read_handler(chr1, serial_can_receive, serial_receive1, &s->chn[0]);
+ qemu_chr_add_event_handler(chr1, serial_event);
+ }
+ if (chr2) {
+ qemu_chr_add_read_handler(chr2, serial_can_receive, serial_receive1, &s->chn[1]);
+ qemu_chr_add_event_handler(chr2, serial_event);
+ }
+ register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s);
+ qemu_register_reset(slavio_serial_reset, s);
+ slavio_serial_reset(s);
+ return s;
+}
+
+static void sunkbd_event(void *opaque, int ch)
+{
+ ChannelState *s = opaque;
+ // XXX: PC -> Sun Type 5 translation?
+ serial_receive_byte(s, ch);
+}
+
+static void sunmouse_event(void *opaque,
+ int dx, int dy, int dz, int buttons_state)
+{
+ ChannelState *s = opaque;
+ int ch;
+
+ // XXX
+ ch = 0x42;
+ serial_receive_byte(s, ch);
+}
+
+void slavio_serial_ms_kbd_init(int base, int irq)
+{
+ int slavio_serial_io_memory;
+ SerialState *s;
+
+ s = qemu_mallocz(sizeof(SerialState));
+ if (!s)
+ return;
+ s->chn[0].irq = irq;
+ s->chn[1].irq = irq;
+ s->chn[0].chr = NULL;
+ s->chn[1].chr = NULL;
+
+ slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
+ cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
+
+ qemu_add_kbd_event_handler(sunkbd_event, &s->chn[0]);
+ qemu_add_mouse_event_handler(sunmouse_event, &s->chn[1]);
+ qemu_register_reset(slavio_serial_reset, s);
+ slavio_serial_reset(s);
+}
diff --git a/hw/slavio_timer.c b/hw/slavio_timer.c
new file mode 100644
index 000000000..43f59d275
--- /dev/null
+++ b/hw/slavio_timer.c
@@ -0,0 +1,289 @@
+/*
+ * QEMU Sparc SLAVIO timer controller emulation
+ *
+ * Copyright (c) 2003-2004 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+#include "vl.h"
+
+//#define DEBUG_TIMER
+
+/*
+ * Registers of hardware timer in sun4m.
+ *
+ * This is the timer/counter part of chip STP2001 (Slave I/O), also
+ * produced as NCR89C105. See
+ * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
+ *
+ * The 31-bit counter is incremented every 500ns by bit 9. Bits 8..0
+ * are zero. Bit 31 is 1 when count has been reached.
+ *
+ */
+
+typedef struct SLAVIO_TIMERState {
+ uint32_t limit, count, counthigh;
+ int64_t count_load_time;
+ int64_t expire_time;
+ int64_t stop_time, tick_offset;
+ QEMUTimer *irq_timer;
+ int irq;
+ int reached, stopped;
+ int mode; // 0 = processor, 1 = user, 2 = system
+} SLAVIO_TIMERState;
+
+#define TIMER_MAXADDR 0x1f
+#define CNT_FREQ 2000000
+#define MAX_CPUS 16
+
+// Update count, set irq, update expire_time
+static void slavio_timer_get_out(SLAVIO_TIMERState *s)
+{
+ int out;
+ int64_t diff, ticks, count;
+ uint32_t limit;
+
+ // There are three clock tick units: CPU ticks, register units
+ // (nanoseconds), and counter ticks (500 ns).
+ if (s->mode == 1 && s->stopped)
+ ticks = s->stop_time;
+ else
+ ticks = qemu_get_clock(vm_clock) - s->tick_offset;
+
+ out = (ticks >= s->expire_time);
+ if (out)
+ s->reached = 0x80000000;
+ if (!s->limit)
+ limit = 0x7fffffff;
+ else
+ limit = s->limit;
+
+ // Convert register units to counter ticks
+ limit = limit >> 9;
+
+ // Convert cpu ticks to counter ticks
+ diff = muldiv64(ticks - s->count_load_time, CNT_FREQ, ticks_per_sec);
+
+ // Calculate what the counter should be, convert to register
+ // units
+ count = diff % limit;
+ s->count = count << 9;
+ s->counthigh = count >> 22;
+
+ // Expire time: CPU ticks left to next interrupt
+ // Convert remaining counter ticks to CPU ticks
+ s->expire_time = ticks + muldiv64(limit - count, ticks_per_sec, CNT_FREQ);
+
+#ifdef DEBUG_TIMER
+ term_printf("timer: irq %d limit %d reached %d d %lld count %d s->c %x diff %lld stopped %d mode %d\n", s->irq, limit, s->reached?1:0, (ticks-s->count_load_time), count, s->count, s->expire_time - ticks, s->stopped, s->mode);
+#endif
+ if (s->mode != 1)
+ pic_set_irq(s->irq, out);
+}
+
+// timer callback
+static void slavio_timer_irq(void *opaque)
+{
+ SLAVIO_TIMERState *s = opaque;
+
+ if (!s->irq_timer)
+ return;
+ slavio_timer_get_out(s);
+ if (s->mode != 1)
+ qemu_mod_timer(s->irq_timer, s->expire_time);
+}
+
+static uint32_t slavio_timer_mem_readl(void *opaque, target_phys_addr_t addr)
+{
+ SLAVIO_TIMERState *s = opaque;
+ uint32_t saddr;
+
+ saddr = (addr & TIMER_MAXADDR) >> 2;
+ switch (saddr) {
+ case 0:
+ // read limit (system counter mode) or read most signifying
+ // part of counter (user mode)
+ if (s->mode != 1) {
+ // clear irq
+ pic_set_irq(s->irq, 0);
+ s->count_load_time = qemu_get_clock(vm_clock);
+ s->reached = 0;
+ return s->limit;
+ }
+ else {
+ slavio_timer_get_out(s);
+ return s->counthigh & 0x7fffffff;
+ }
+ case 1:
+ // read counter and reached bit (system mode) or read lsbits
+ // of counter (user mode)
+ slavio_timer_get_out(s);
+ if (s->mode != 1)
+ return (s->count & 0x7fffffff) | s->reached;
+ else
+ return s->count;
+ case 3:
+ // read start/stop status
+ return s->stopped;
+ case 4:
+ // read user/system mode
+ return s->mode & 1;
+ default:
+ return 0;
+ }
+}
+
+static void slavio_timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+{
+ SLAVIO_TIMERState *s = opaque;
+ uint32_t saddr;
+
+ saddr = (addr & TIMER_MAXADDR) >> 2;
+ switch (saddr) {
+ case 0:
+ // set limit, reset counter
+ s->count_load_time = qemu_get_clock(vm_clock);
+ // fall through
+ case 2:
+ // set limit without resetting counter
+ if (!val)
+ s->limit = 0x7fffffff;
+ else
+ s->limit = val & 0x7fffffff;
+ slavio_timer_irq(s);
+ break;
+ case 3:
+ // start/stop user counter
+ if (s->mode == 1) {
+ if (val & 1) {
+ s->stop_time = qemu_get_clock(vm_clock);
+ s->stopped = 1;
+ }
+ else {
+ if (s->stopped)
+ s->tick_offset += qemu_get_clock(vm_clock) - s->stop_time;
+ s->stopped = 0;
+ }
+ }
+ break;
+ case 4:
+ // bit 0: user (1) or system (0) counter mode
+ if (s->mode == 0 || s->mode == 1)
+ s->mode = val & 1;
+ break;
+ default:
+ break;
+ }
+}
+
+static CPUReadMemoryFunc *slavio_timer_mem_read[3] = {
+ slavio_timer_mem_readl,
+ slavio_timer_mem_readl,
+ slavio_timer_mem_readl,
+};
+
+static CPUWriteMemoryFunc *slavio_timer_mem_write[3] = {
+ slavio_timer_mem_writel,
+ slavio_timer_mem_writel,
+ slavio_timer_mem_writel,
+};
+
+static void slavio_timer_save(QEMUFile *f, void *opaque)
+{
+ SLAVIO_TIMERState *s = opaque;
+
+ qemu_put_be32s(f, &s->limit);
+ qemu_put_be32s(f, &s->count);
+ qemu_put_be32s(f, &s->counthigh);
+ qemu_put_be64s(f, &s->count_load_time);
+ qemu_put_be64s(f, &s->expire_time);
+ qemu_put_be64s(f, &s->stop_time);
+ qemu_put_be64s(f, &s->tick_offset);
+ qemu_put_be32s(f, &s->irq);
+ qemu_put_be32s(f, &s->reached);
+ qemu_put_be32s(f, &s->stopped);
+ qemu_put_be32s(f, &s->mode);
+}
+
+static int slavio_timer_load(QEMUFile *f, void *opaque, int version_id)
+{
+ SLAVIO_TIMERState *s = opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f, &s->limit);
+ qemu_get_be32s(f, &s->count);
+ qemu_get_be32s(f, &s->counthigh);
+ qemu_get_be64s(f, &s->count_load_time);
+ qemu_get_be64s(f, &s->expire_time);
+ qemu_get_be64s(f, &s->stop_time);
+ qemu_get_be64s(f, &s->tick_offset);
+ qemu_get_be32s(f, &s->irq);
+ qemu_get_be32s(f, &s->reached);
+ qemu_get_be32s(f, &s->stopped);
+ qemu_get_be32s(f, &s->mode);
+ return 0;
+}
+
+static void slavio_timer_reset(void *opaque)
+{
+ SLAVIO_TIMERState *s = opaque;
+
+ s->limit = 0;
+ s->count = 0;
+ s->count_load_time = qemu_get_clock(vm_clock);;
+ s->stop_time = s->count_load_time;
+ s->tick_offset = 0;
+ s->reached = 0;
+ s->mode &= 2;
+ s->stopped = 1;
+ slavio_timer_get_out(s);
+}
+
+static void slavio_timer_init_internal(uint32_t addr, int irq, int mode)
+{
+ int slavio_timer_io_memory;
+ SLAVIO_TIMERState *s;
+
+ s = qemu_mallocz(sizeof(SLAVIO_TIMERState));
+ if (!s)
+ return;
+ s->irq = irq;
+ s->mode = mode;
+ s->irq_timer = qemu_new_timer(vm_clock, slavio_timer_irq, s);
+
+ slavio_timer_io_memory = cpu_register_io_memory(0, slavio_timer_mem_read,
+ slavio_timer_mem_write, s);
+ cpu_register_physical_memory(addr, TIMER_MAXADDR, slavio_timer_io_memory);
+ register_savevm("slavio_timer", addr, 1, slavio_timer_save, slavio_timer_load, s);
+ qemu_register_reset(slavio_timer_reset, s);
+ slavio_timer_reset(s);
+}
+
+void slavio_timer_init(uint32_t addr1, int irq1, uint32_t addr2, int irq2)
+{
+ int i;
+
+ for (i = 0; i < MAX_CPUS; i++) {
+ slavio_timer_init_internal(addr1 + i * TARGET_PAGE_SIZE, irq1, 0);
+ }
+
+ slavio_timer_init_internal(addr2, irq2, 2);
+}
diff --git a/hw/sun4m.c b/hw/sun4m.c
index 80305e09c..7cc5bd8d9 100644
--- a/hw/sun4m.c
+++ b/hw/sun4m.c
@@ -25,29 +25,32 @@
#include "m48t08.h"
#define KERNEL_LOAD_ADDR 0x00004000
-#define MMU_CONTEXT_TBL 0x00003000
-#define MMU_L1PTP (MMU_CONTEXT_TBL + 0x0400)
-#define MMU_L2PTP (MMU_CONTEXT_TBL + 0x0800)
-#define PROM_ADDR 0xffd04000
+#define PROM_ADDR 0xffd00000
#define PROM_FILENAMEB "proll.bin"
#define PROM_FILENAMEE "proll.elf"
-#define PROLL_MAGIC_ADDR 0x20000000
-#define PHYS_JJ_EEPROM 0x71200000 /* [2000] MK48T08 */
+#define PHYS_JJ_EEPROM 0x71200000 /* m48t08 */
#define PHYS_JJ_IDPROM_OFF 0x1FD8
#define PHYS_JJ_EEPROM_SIZE 0x2000
-#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */
+// IRQs are not PIL ones, but master interrupt controller register
+// bits
+#define PHYS_JJ_IOMMU 0x10000000 /* I/O MMU */
#define PHYS_JJ_TCX_FB 0x50800000 /* Start address, frame buffer body */
-#define PHYS_JJ_TCX_0E 0x5E000000 /* Top address, one byte used. */
-#define PHYS_JJ_IOMMU 0x10000000 /* First page of sun4m IOMMU */
-#define PHYS_JJ_LEDMA 0x78400010 /* ledma, off by 10 from unused SCSI */
-#define PHYS_JJ_LE 0x78C00000 /* LANCE, typical sun4m */
-#define PHYS_JJ_LE_IRQ 6
-#define PHYS_JJ_CLOCK 0x71D00000
-#define PHYS_JJ_CLOCK_IRQ 10
-#define PHYS_JJ_CLOCK1 0x71D10000
-#define PHYS_JJ_CLOCK1_IRQ 14
-#define PHYS_JJ_INTR0 0x71E00000 /* CPU0 interrupt control registers */
+#define PHYS_JJ_LEDMA 0x78400010 /* Lance DMA controller */
+#define PHYS_JJ_LE 0x78C00000 /* Lance ethernet */
+#define PHYS_JJ_LE_IRQ 16
+#define PHYS_JJ_CLOCK 0x71D00000 /* Per-CPU timer/counter, L14 */
+#define PHYS_JJ_CLOCK_IRQ 7
+#define PHYS_JJ_CLOCK1 0x71D10000 /* System timer/counter, L10 */
+#define PHYS_JJ_CLOCK1_IRQ 19
+#define PHYS_JJ_INTR0 0x71E00000 /* Per-CPU interrupt control registers */
#define PHYS_JJ_INTR_G 0x71E10000 /* Master interrupt control registers */
+#define PHYS_JJ_MS_KBD 0x71000000 /* Mouse and keyboard */
+#define PHYS_JJ_MS_KBD_IRQ 14
+#define PHYS_JJ_SER 0x71100000 /* Serial */
+#define PHYS_JJ_SER_IRQ 15
+#define PHYS_JJ_SCSI_IRQ 18
+#define PHYS_JJ_FDC 0x71400000 /* Floppy */
+#define PHYS_JJ_FLOPPY_IRQ 22
/* TSC handling */
@@ -57,13 +60,73 @@ uint64_t cpu_get_tsc()
}
void DMA_run() {}
-void SB16_run() {}
-int serial_can_receive(SerialState *s) { return 0; }
-void serial_receive_byte(SerialState *s, int ch) {}
-void serial_receive_break(SerialState *s) {}
static m48t08_t *nvram;
+static void nvram_init(m48t08_t *nvram, uint8_t *macaddr)
+{
+ unsigned char tmp = 0;
+ int i, j;
+
+ i = 0x1fd8;
+ m48t08_write(nvram, i++, 0x01);
+ m48t08_write(nvram, i++, 0x80); /* Sun4m OBP */
+ j = 0;
+ m48t08_write(nvram, i++, macaddr[j++]);
+ m48t08_write(nvram, i++, macaddr[j++]);
+ m48t08_write(nvram, i++, macaddr[j++]);
+ m48t08_write(nvram, i++, macaddr[j++]);
+ m48t08_write(nvram, i++, macaddr[j++]);
+ m48t08_write(nvram, i, macaddr[j]);
+
+ /* Calculate checksum */
+ for (i = 0x1fd8; i < 0x1fe7; i++) {
+ tmp ^= m48t08_read(nvram, i);
+ }
+ m48t08_write(nvram, 0x1fe7, tmp);
+}
+
+static void *slavio_intctl;
+
+void pic_info()
+{
+ slavio_pic_info(slavio_intctl);
+}
+
+void irq_info()
+{
+ slavio_irq_info(slavio_intctl);
+}
+
+void pic_set_irq(int irq, int level)
+{
+ slavio_pic_set_irq(slavio_intctl, irq, level);
+}
+
+static void *tcx;
+
+void vga_update_display()
+{
+ tcx_update_display(tcx);
+}
+
+void vga_invalidate_display()
+{
+ tcx_invalidate_display(tcx);
+}
+
+void vga_screen_dump(const char *filename)
+{
+ tcx_screen_dump(tcx, filename);
+}
+
+static void *iommu;
+
+uint32_t iommu_translate(uint32_t addr)
+{
+ return iommu_translate_local(iommu, addr);
+}
+
/* Sun4m hardware initialisation */
void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
DisplayState *ds, const char **fd_filename, int snapshot,
@@ -72,42 +135,50 @@ void sun4m_init(int ram_size, int vga_ram_size, int boot_device,
{
char buf[1024];
int ret, linux_boot;
- unsigned long bios_offset;
+ unsigned long vram_size = 0x100000, prom_offset;
linux_boot = (kernel_filename != NULL);
/* allocate RAM */
cpu_register_physical_memory(0, ram_size, 0);
- bios_offset = ram_size;
- iommu_init(PHYS_JJ_IOMMU);
- sched_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
- tcx_init(ds, PHYS_JJ_TCX_FB);
+ iommu = iommu_init(PHYS_JJ_IOMMU);
+ slavio_intctl = slavio_intctl_init(PHYS_JJ_INTR0, PHYS_JJ_INTR_G);
+ tcx = tcx_init(ds, PHYS_JJ_TCX_FB, phys_ram_base + ram_size, ram_size, vram_size);
lance_init(&nd_table[0], PHYS_JJ_LE_IRQ, PHYS_JJ_LE, PHYS_JJ_LEDMA);
- nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE, &nd_table[0].macaddr);
- timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ);
- timer_init(PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
- magic_init(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR, PROLL_MAGIC_ADDR);
+ nvram = m48t08_init(PHYS_JJ_EEPROM, PHYS_JJ_EEPROM_SIZE);
+ nvram_init(nvram, (uint8_t *)&nd_table[0].macaddr);
+ slavio_timer_init(PHYS_JJ_CLOCK, PHYS_JJ_CLOCK_IRQ, PHYS_JJ_CLOCK1, PHYS_JJ_CLOCK1_IRQ);
+ slavio_serial_ms_kbd_init(PHYS_JJ_MS_KBD, PHYS_JJ_MS_KBD_IRQ);
+ slavio_serial_init(PHYS_JJ_SER, PHYS_JJ_SER_IRQ, serial_hds[0], serial_hds[1]);
+ fdctrl_init(PHYS_JJ_FLOPPY_IRQ, 0, 1, PHYS_JJ_FDC, fd_table);
- /* We load Proll as the kernel and start it. It will issue a magic
- IO to load the real kernel */
- if (linux_boot) {
+ prom_offset = ram_size + vram_size;
+
+ snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEE);
+ ret = load_elf(buf, phys_ram_base + prom_offset);
+ if (ret < 0) {
snprintf(buf, sizeof(buf), "%s/%s", bios_dir, PROM_FILENAMEB);
- ret = load_kernel(buf,
- phys_ram_base + KERNEL_LOAD_ADDR);
+ ret = load_image(buf, phys_ram_base + prom_offset);
+ }
+ if (ret < 0) {
+ fprintf(stderr, "qemu: could not load prom '%s'\n",
+ buf);
+ exit(1);
+ }
+ cpu_register_physical_memory(PROM_ADDR, (ret + TARGET_PAGE_SIZE) & TARGET_PAGE_MASK,
+ prom_offset | IO_MEM_ROM);
+
+ if (linux_boot) {
+ ret = load_elf(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+ if (ret < 0)
+ ret = load_aout(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
+ if (ret < 0)
+ ret = load_image(kernel_filename, phys_ram_base + KERNEL_LOAD_ADDR);
if (ret < 0) {
fprintf(stderr, "qemu: could not load kernel '%s'\n",
- buf);
- exit(1);
+ kernel_filename);
+ exit(1);
}
}
- /* Setup a MMU entry for entire address space */
- stl_raw(phys_ram_base + MMU_CONTEXT_TBL, (MMU_L1PTP >> 4) | 1);
- stl_raw(phys_ram_base + MMU_L1PTP, (MMU_L2PTP >> 4) | 1);
- stl_raw(phys_ram_base + MMU_L1PTP + (0x01 << 2), (MMU_L2PTP >> 4) | 1); // 01.. == 00..
- stl_raw(phys_ram_base + MMU_L1PTP + (0xff << 2), (MMU_L2PTP >> 4) | 1); // ff.. == 00..
- stl_raw(phys_ram_base + MMU_L1PTP + (0xf0 << 2), (MMU_L2PTP >> 4) | 1); // f0.. == 00..
- /* 3 = U:RWX S:RWX */
- stl_raw(phys_ram_base + MMU_L2PTP, (3 << PTE_ACCESS_SHIFT) | 2);
- stl_raw(phys_ram_base + MMU_L2PTP, ((0x01 << PTE_PPN_SHIFT) >> 4 ) | (3 << PTE_ACCESS_SHIFT) | 2);
}
diff --git a/hw/tcx.c b/hw/tcx.c
index 7f979946f..ccac0bffa 100644
--- a/hw/tcx.c
+++ b/hw/tcx.c
@@ -25,179 +25,254 @@
#define MAXX 1024
#define MAXY 768
+/*
+ * Proll uses only small part of display, we need to switch to full
+ * display when we get linux framebuffer console or X11 running. For
+ * now it's just slower and awkward.
+*/
+#if 1
#define XSZ (8*80)
#define YSZ (24*11)
#define XOFF (MAXX-XSZ)
#define YOFF (MAXY-YSZ)
+#else
+#define XSZ MAXX
+#define YSZ MAXY
+#define XOFF 0
+#define YOFF 0
+#endif
typedef struct TCXState {
uint32_t addr;
DisplayState *ds;
uint8_t *vram;
+ unsigned long vram_offset;
+ uint8_t r[256], g[256], b[256];
} TCXState;
-static TCXState *ts;
-
-void vga_update_display()
+static void tcx_draw_line32(TCXState *s1, uint8_t *d,
+ const uint8_t *s, int width)
{
- dpy_update(ts->ds, 0, 0, XSZ, YSZ);
+ int x;
+ uint8_t val;
+
+ for(x = 0; x < width; x++) {
+ val = *s++;
+ *d++ = s1->r[val];
+ *d++ = s1->g[val];
+ *d++ = s1->b[val];
+ d++;
+ }
}
-void vga_invalidate_display() {}
+static void tcx_draw_line24(TCXState *s1, uint8_t *d,
+ const uint8_t *s, int width)
+{
+ int x;
+ uint8_t val;
-static uint32_t tcx_mem_readb(void *opaque, target_phys_addr_t addr)
+ for(x = 0; x < width; x++) {
+ val = *s++;
+ *d++ = s1->r[val];
+ *d++ = s1->g[val];
+ *d++ = s1->b[val];
+ }
+}
+
+static void tcx_draw_line8(TCXState *s1, uint8_t *d,
+ const uint8_t *s, int width)
{
- TCXState *s = opaque;
- uint32_t saddr;
- unsigned int x, y;
-
- saddr = addr - s->addr - YOFF*MAXX - XOFF;
- y = saddr / MAXX;
- x = saddr - y * MAXX;
- if (x < XSZ && y < YSZ) {
- return s->vram[y * XSZ + x];
+ int x;
+ uint8_t val;
+
+ for(x = 0; x < width; x++) {
+ val = *s++;
+ /* XXX translate between palettes? */
+ *d++ = val;
}
- return 0;
}
-static uint32_t tcx_mem_readw(void *opaque, target_phys_addr_t addr)
+/* Fixed line length 1024 allows us to do nice tricks not possible on
+ VGA... */
+void tcx_update_display(void *opaque)
{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = tcx_mem_readb(opaque, addr) << 8;
- v |= tcx_mem_readb(opaque, addr + 1);
+ TCXState *ts = opaque;
+ uint32_t page;
+ int y, page_min, page_max, y_start, dd, ds;
+ uint8_t *d, *s;
+ void (*f)(TCXState *s1, uint8_t *d, const uint8_t *s, int width);
+
+ if (ts->ds->depth == 0)
+ return;
+#ifdef LD_BYPASS_OK
+ page = ts->vram_offset + YOFF*MAXX;
#else
- v = tcx_mem_readb(opaque, addr);
- v |= tcx_mem_readb(opaque, addr + 1) << 8;
+ page = ts->addr + YOFF*MAXX;
#endif
- return v;
+ y_start = -1;
+ page_min = 0x7fffffff;
+ page_max = -1;
+ d = ts->ds->data;
+ s = ts->vram + YOFF*MAXX + XOFF;
+ dd = ts->ds->linesize;
+ ds = 1024;
+
+ switch (ts->ds->depth) {
+ case 32:
+ f = tcx_draw_line32;
+ break;
+ case 24:
+ f = tcx_draw_line24;
+ break;
+ default:
+ case 8:
+ f = tcx_draw_line8;
+ break;
+ case 0:
+ return;
+ }
+
+ for(y = 0; y < YSZ; y += 4, page += TARGET_PAGE_SIZE) {
+ if (cpu_physical_memory_is_dirty(page)) {
+ if (y_start < 0)
+ y_start = y;
+ if (page < page_min)
+ page_min = page;
+ if (page > page_max)
+ page_max = page;
+ f(ts, d, s, XSZ);
+ d += dd;
+ s += ds;
+ f(ts, d, s, XSZ);
+ d += dd;
+ s += ds;
+ f(ts, d, s, XSZ);
+ d += dd;
+ s += ds;
+ f(ts, d, s, XSZ);
+ d += dd;
+ s += ds;
+ } else {
+ if (y_start >= 0) {
+ /* flush to display */
+ dpy_update(ts->ds, 0, y_start,
+ XSZ, y - y_start);
+ y_start = -1;
+ }
+ d += dd * 4;
+ s += ds * 4;
+ }
+ }
+ if (y_start >= 0) {
+ /* flush to display */
+ dpy_update(ts->ds, 0, y_start,
+ XSZ, y - y_start);
+ }
+ /* reset modified pages */
+ if (page_max != -1) {
+ cpu_physical_memory_reset_dirty(page_min, page_max + TARGET_PAGE_SIZE);
+ }
}
-static uint32_t tcx_mem_readl(void *opaque, target_phys_addr_t addr)
+void tcx_invalidate_display(void *opaque)
{
- uint32_t v;
-#ifdef TARGET_WORDS_BIGENDIAN
- v = tcx_mem_readb(opaque, addr) << 24;
- v |= tcx_mem_readb(opaque, addr + 1) << 16;
- v |= tcx_mem_readb(opaque, addr + 2) << 8;
- v |= tcx_mem_readb(opaque, addr + 3);
+ TCXState *s = opaque;
+ int i;
+
+ for (i = 0; i < MAXX*MAXY; i += TARGET_PAGE_SIZE) {
+#ifdef LD_BYPASS_OK
+ cpu_physical_memory_set_dirty(s->vram_offset + i);
#else
- v = tcx_mem_readb(opaque, addr);
- v |= tcx_mem_readb(opaque, addr + 1) << 8;
- v |= tcx_mem_readb(opaque, addr + 2) << 16;
- v |= tcx_mem_readb(opaque, addr + 3) << 24;
+ cpu_physical_memory_set_dirty(s->addr + i);
#endif
- return v;
+ }
}
-static void tcx_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void tcx_save(QEMUFile *f, void *opaque)
{
TCXState *s = opaque;
- uint32_t saddr;
- unsigned int x, y;
- char *sptr;
-
- saddr = addr - s->addr - YOFF*MAXX - XOFF;
- y = saddr / MAXX;
- x = saddr - y * MAXX;
- if (x < XSZ && y < YSZ) {
- sptr = s->ds->data;
- if (sptr) {
- if (s->ds->depth == 24 || s->ds->depth == 32) {
- /* XXX need to do CLUT translation */
- sptr[y * s->ds->linesize + x*4] = val & 0xff;
- sptr[y * s->ds->linesize + x*4+1] = val & 0xff;
- sptr[y * s->ds->linesize + x*4+2] = val & 0xff;
- }
- else if (s->ds->depth == 8) {
- sptr[y * s->ds->linesize + x] = val & 0xff;
- }
- }
- cpu_physical_memory_set_dirty(addr);
- s->vram[y * XSZ + x] = val & 0xff;
- }
+
+ qemu_put_be32s(f, (uint32_t *)&s->addr);
+ qemu_put_be32s(f, (uint32_t *)&s->vram);
+ qemu_put_buffer(f, s->r, 256);
+ qemu_put_buffer(f, s->g, 256);
+ qemu_put_buffer(f, s->b, 256);
}
-static void tcx_mem_writew(void *opaque, target_phys_addr_t addr, uint32_t val)
+static int tcx_load(QEMUFile *f, void *opaque, int version_id)
{
-#ifdef TARGET_WORDS_BIGENDIAN
- tcx_mem_writeb(opaque, addr, (val >> 8) & 0xff);
- tcx_mem_writeb(opaque, addr + 1, val & 0xff);
-#else
- tcx_mem_writeb(opaque, addr, val & 0xff);
- tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
-#endif
+ TCXState *s = opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+
+ qemu_get_be32s(f, (uint32_t *)&s->addr);
+ qemu_get_be32s(f, (uint32_t *)&s->vram);
+ qemu_get_buffer(f, s->r, 256);
+ qemu_get_buffer(f, s->g, 256);
+ qemu_get_buffer(f, s->b, 256);
+ return 0;
}
-static void tcx_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
+static void tcx_reset(void *opaque)
{
-#ifdef TARGET_WORDS_BIGENDIAN
- tcx_mem_writeb(opaque, addr, (val >> 24) & 0xff);
- tcx_mem_writeb(opaque, addr + 1, (val >> 16) & 0xff);
- tcx_mem_writeb(opaque, addr + 2, (val >> 8) & 0xff);
- tcx_mem_writeb(opaque, addr + 3, val & 0xff);
-#else
- tcx_mem_writeb(opaque, addr, val & 0xff);
- tcx_mem_writeb(opaque, addr + 1, (val >> 8) & 0xff);
- tcx_mem_writeb(opaque, addr + 2, (val >> 16) & 0xff);
- tcx_mem_writeb(opaque, addr + 3, (val >> 24) & 0xff);
+ TCXState *s = opaque;
+
+ /* Initialize palette */
+ memset(s->r, 0, 256);
+ memset(s->g, 0, 256);
+ memset(s->b, 0, 256);
+ s->r[255] = s->g[255] = s->b[255] = 255;
+ memset(s->vram, 0, MAXX*MAXY);
+#ifdef LD_BYPASS_OK
+ cpu_physical_memory_reset_dirty(s->vram_offset, s->vram_offset + MAXX*MAXY - 1);
#endif
}
-static CPUReadMemoryFunc *tcx_mem_read[3] = {
- tcx_mem_readb,
- tcx_mem_readw,
- tcx_mem_readl,
-};
-
-static CPUWriteMemoryFunc *tcx_mem_write[3] = {
- tcx_mem_writeb,
- tcx_mem_writew,
- tcx_mem_writel,
-};
-
-void tcx_init(DisplayState *ds, uint32_t addr)
+void *tcx_init(DisplayState *ds, uint32_t addr, uint8_t *vram_base,
+ unsigned long vram_offset, int vram_size)
{
TCXState *s;
- int tcx_io_memory;
s = qemu_mallocz(sizeof(TCXState));
if (!s)
- return;
+ return NULL;
s->ds = ds;
s->addr = addr;
- ts = s;
- tcx_io_memory = cpu_register_io_memory(0, tcx_mem_read, tcx_mem_write, s);
- cpu_register_physical_memory(addr, 0x100000,
- tcx_io_memory);
- s->vram = qemu_mallocz(XSZ*YSZ);
+ s->vram = vram_base;
+ s->vram_offset = vram_offset;
+
+ cpu_register_physical_memory(addr, vram_size, vram_offset);
+
+ register_savevm("tcx", addr, 1, tcx_save, tcx_load, s);
+ qemu_register_reset(tcx_reset, s);
+ tcx_reset(s);
dpy_resize(s->ds, XSZ, YSZ);
+ return s;
}
-void vga_screen_dump(const char *filename)
+void tcx_screen_dump(void *opaque, const char *filename)
{
- TCXState *s = ts;
+ TCXState *s = opaque;
FILE *f;
- uint8_t *d, *d1;
- unsigned int v;
+ uint8_t *d, *d1, v;
int y, x;
f = fopen(filename, "wb");
if (!f)
- return -1;
- fprintf(f, "P6\n%d %d\n%d\n",
- XSZ, YSZ, 255);
- d1 = s->vram;
+ return;
+ fprintf(f, "P6\n%d %d\n%d\n", XSZ, YSZ, 255);
+ d1 = s->vram + YOFF*MAXX + XOFF;
for(y = 0; y < YSZ; y++) {
d = d1;
for(x = 0; x < XSZ; x++) {
v = *d;
- fputc((v) & 0xff, f);
- fputc((v) & 0xff, f);
- fputc((v) & 0xff, f);
+ fputc(s->r[v], f);
+ fputc(s->g[v], f);
+ fputc(s->b[v], f);
d++;
}
- d1 += XSZ;
+ d1 += MAXX;
}
fclose(f);
return;
diff --git a/hw/timer.c b/hw/timer.c
deleted file mode 100644
index e393fa36f..000000000
--- a/hw/timer.c
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * QEMU Sparc timer controller emulation
- *
- * Copyright (c) 2003-2004 Fabrice Bellard
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- */
-#include "vl.h"
-
-/*
- * Registers of hardware timer in sun4m.
- */
-struct sun4m_timer_percpu {
- volatile unsigned int l14_timer_limit; /* Initial value is 0x009c4000 */
- volatile unsigned int l14_cur_count;
-};
-
-struct sun4m_timer_global {
- volatile unsigned int l10_timer_limit;
- volatile unsigned int l10_cur_count;
-};
-
-typedef struct TIMERState {
- uint32_t addr;
- uint32_t timer_regs[2];
- int irq;
-} TIMERState;
-
-static uint32_t timer_mem_readl(void *opaque, target_phys_addr_t addr)
-{
- TIMERState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr - s->addr) >> 2;
- switch (saddr) {
- default:
- return s->timer_regs[saddr];
- break;
- }
- return 0;
-}
-
-static void timer_mem_writel(void *opaque, target_phys_addr_t addr, uint32_t val)
-{
- TIMERState *s = opaque;
- uint32_t saddr;
-
- saddr = (addr - s->addr) >> 2;
- switch (saddr) {
- default:
- s->timer_regs[saddr] = val;
- break;
- }
-}
-
-static CPUReadMemoryFunc *timer_mem_read[3] = {
- timer_mem_readl,
- timer_mem_readl,
- timer_mem_readl,
-};
-
-static CPUWriteMemoryFunc *timer_mem_write[3] = {
- timer_mem_writel,
- timer_mem_writel,
- timer_mem_writel,
-};
-
-void timer_init(uint32_t addr, int irq)
-{
- int timer_io_memory;
- TIMERState *s;
-
- s = qemu_mallocz(sizeof(TIMERState));
- if (!s)
- return;
- s->addr = addr;
- s->irq = irq;
-
- timer_io_memory = cpu_register_io_memory(0, timer_mem_read, timer_mem_write, s);
- cpu_register_physical_memory(addr, 2, timer_io_memory);
-}