qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] Re: Qemu SH4 status #2


From: Shin-ichiro KAWASAKI
Subject: Re: [Qemu-devel] Re: Qemu SH4 status #2
Date: Mon, 24 Nov 2008 16:10:47 +0900
User-agent: Thunderbird 2.0.0.18 (Windows/20081105)

Hi,

Aurelien committed Volodya's MMU patch kindly. http://lists.gnu.org/archive/html/qemu-devel/2008-11/msg01182.html

So some part of the big patch is not necessary now.
I omitted the part and generated new big patch and attach it to this mail,
which can be applied to QEMU rev5786.  I hope it helps.


address@hidden wrote:
Another file "linuxconfig_r2d_qemu.diff" is diff for linux kernel
 configuretion. It changes following parameters from r2d+'s defconfig.
- Cache -> off (qemu has no cache)

It seems the kernel with cache works fine.  Even though qemu has no cache
emulation, there is no need to tell it to qemu users, I think.

- commandline change (for debugging)
- 8139too -> 8139cp (qemu's default is c+, still thinking how to switch)

- SH SPI -> off (sci emulation is not mature enough to handle it)
I hope my small patch avoid SPI config problem.
 http://lists.gnu.org/archive/html/qemu-devel/2008-11/msg01229.html

Anyway, your patches on MMIO/ATA and PCI works fine!
Thank you.

Regards,
Shin-ichiro KAWASAKI



address@hidden wrote:
Hi,

I'm still getting segmentation fault at exact same
location. Have you made additional patches?
Please find attached file "qemu081111.diff".
Basically, this is an aggregate of patches found on qemu-devel ML,
 with some conflicts against current svn source being resolved,
 and some small fix are added, which are scheduled to be posted after
 I finished with my pending patches.

I post this to share information between qemu and linux/sh people,
 and hopefully accelerate debugging with linux people's help.

Another file "linuxconfig_r2d_qemu.diff" is diff for linux kernel
 configuretion. It changes following parameters from r2d+'s defconfig.
- Cache -> off (qemu has no cache)
- commandline change (for debugging)
- 8139too -> 8139cp (qemu's default is c+, still thinking how to switch)
- SH SPI -> off (sci emulation is not mature enough to handle it)

Build procedure is as follows,
Configure kernel:
 make ARCH=sh rts7751r2dplus_defconfig
 patch .config < linuxconfig_r2d_qemu.diff
 (and build)

Configure Qemu:
 ./configure --disable-system --target-list=sh4-softmmu \
  --disable-linux-user --disable-kqemu

Execute:
 sh4-softmmu/qemu-system-sh4 -M r2d --serial vc --serial /dev/tty \
  --kernel zImage --append "console=tty0 root=/dev/sda" \
  -usb --usbdevice keyboard --usbdevice mouse disk.img

I've tested it on qemu svn head this morning.
You will see penguin logo, and fbcon input/output working.
For debugging purpose, console=ttySC0,115200 might help.
/yoshii


Index: trunk/target-sh4/helper.c
===================================================================
--- trunk/target-sh4/helper.c   (revision 5786)
+++ trunk/target-sh4/helper.c   (working copy)
@@ -439,6 +439,9 @@
        if (address >= 0x80000000 && address < 0xc0000000) {
            /* Mask upper 3 bits for P1 and P2 areas */
            *physical = address & 0x1fffffff;
+       } else if (address >= 0xfd000000 && address < 0xfe000000) {
+           /* PCI memory space */
+           *physical = address;
        } else if (address >= 0xfc000000) {
            /*
             * Mask upper 3 bits for control registers in P4 area,
Index: trunk/Makefile.target
===================================================================
--- trunk/Makefile.target       (revision 5786)
+++ trunk/Makefile.target       (working copy)
@@ -736,7 +736,8 @@
 endif
 ifeq ($(TARGET_BASE_ARCH), sh4)
 OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o
-OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o sm501.o serial.o
+OBJS+= sh_timer.o ptimer.o sh_serial.o sh_intc.o sh_pci.o sm501.o serial.o
+OBJS+= ide.o
 endif
 ifeq ($(TARGET_BASE_ARCH), m68k)
 OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
Index: trunk/hw/r2d.c
===================================================================
--- trunk/hw/r2d.c      (revision 5786)
+++ trunk/hw/r2d.c      (working copy)
@@ -28,12 +28,16 @@
 #include "devices.h"
 #include "sysemu.h"
 #include "boards.h"
+#include "pci.h"
+#include "net.h"
+#include "sh7750_regs.h"
 
 #define SDRAM_BASE 0x0c000000 /* Physical location of SDRAM: Area 3 */
 #define SDRAM_SIZE 0x04000000
 
 #define SM501_VRAM_SIZE 0x800000
 
+#define PA_IRLMSK      0x00
 #define PA_POWOFF      0x30
 #define PA_VERREG      0x32
 #define PA_OUTPORT     0x36
@@ -41,6 +45,8 @@
 typedef struct {
     target_phys_addr_t base;
 
+/* register */
+    uint16_t irlmsk;
     uint16_t bcr;
     uint16_t irlmon;
     uint16_t cfctl;
@@ -62,8 +68,53 @@
     uint16_t inport;
     uint16_t outport;
     uint16_t bverreg;
+
+/* output pin */
+    qemu_irq irl;
 } r2d_fpga_t;
 
+enum r2d_fpga_irq {
+    PCI_INTD, CF_IDE, CF_CD, PCI_INTC, SM501, KEY, RTC_A, RTC_T,
+    SDCARD, PCI_INTA, PCI_INTB, EXT, TP,
+    NR_IRQS
+};
+
+static const struct { short irl; uint16_t msk; } irqtab[NR_IRQS] = {
+    [CF_IDE]   = {  1, 1<<9 },
+    [CF_CD]    = {  2, 1<<8 },
+    [PCI_INTA] = {  9, 1<<14 },
+    [PCI_INTB] = { 10, 1<<13 },
+    [PCI_INTC] = {  3, 1<<12 },
+    [PCI_INTD] = {  0, 1<<11 },
+    [SM501]    = {  4, 1<<10 },
+    [KEY]      = {  5, 1<<6 },
+    [RTC_A]    = {  6, 1<<5 },
+    [RTC_T]    = {  7, 1<<4 },
+    [SDCARD]   = {  8, 1<<7 },
+    [EXT]      = { 11, 1<<0 },
+    [TP]       = { 12, 1<<15 },
+};
+
+static void update_irl(r2d_fpga_t *fpga)
+{
+    int i, irl = 15;
+    for (i = 0; i < NR_IRQS; i++)
+        if (fpga->irlmon & fpga->irlmsk & irqtab[i].msk)
+            if (irqtab[i].irl < irl)
+                irl = irqtab[i].irl;
+    qemu_set_irq(fpga->irl, irl ^ 15);
+}
+
+static void r2d_fpga_irq_set(void *opaque, int n, int level)
+{
+    r2d_fpga_t *fpga = opaque;
+    if (level)
+        fpga->irlmon |= irqtab[n].msk;
+    else
+        fpga->irlmon &= ~irqtab[n].msk;
+    update_irl(fpga);
+}
+
 static uint32_t r2d_fpga_read(void *opaque, target_phys_addr_t addr)
 {
     r2d_fpga_t *s = opaque;
@@ -71,6 +122,8 @@
     addr -= s->base;
 
     switch (addr) {
+    case PA_IRLMSK:
+        return s->irlmsk;
     case PA_OUTPORT:
        return s->outport;
     case PA_POWOFF:
@@ -90,6 +143,10 @@
     addr -= s->base;
 
     switch (addr) {
+    case PA_IRLMSK:
+        s->irlmsk = value;
+        update_irl(s);
+       break;
     case PA_OUTPORT:
        s->outport = value;
        break;
@@ -114,21 +171,35 @@
     NULL,
 };
 
-static void r2d_fpga_init(target_phys_addr_t base)
+static qemu_irq *r2d_fpga_init(target_phys_addr_t base, qemu_irq irl)
 {
     int iomemtype;
     r2d_fpga_t *s;
 
     s = qemu_mallocz(sizeof(r2d_fpga_t));
     if (!s)
-       return;
+       return NULL;
 
+    s->irl = irl;
+
     s->base = base;
     iomemtype = cpu_register_io_memory(0, r2d_fpga_readfn,
                                       r2d_fpga_writefn, s);
     cpu_register_physical_memory(base, 0x40, iomemtype);
+    return qemu_allocate_irqs(r2d_fpga_irq_set, s, NR_IRQS);
 }
 
+static void r2d_pci_set_irq(qemu_irq *p, int n, int l)
+{
+    qemu_set_irq(p[n], l);
+}
+
+static int r2d_pci_map_irq(PCIDevice *d, int irq_num)
+{
+    const int intx[] = { PCI_INTA, PCI_INTB, PCI_INTC, PCI_INTD };
+    return intx[d->devfn>>3];
+}
+
 static void r2d_init(ram_addr_t ram_size, int vga_ram_size,
               const char *boot_device, DisplayState * ds,
              const char *kernel_filename, const char *kernel_cmdline,
@@ -137,6 +208,9 @@
     CPUState *env;
     struct SH7750State *s;
     ram_addr_t sdram_addr, sm501_vga_ram_addr;
+    qemu_irq *irq;
+    PCIBus *pci;
+    int i;
 
     if (!cpu_model)
         cpu_model = "SH7751R";
@@ -151,23 +225,50 @@
     sdram_addr = qemu_ram_alloc(SDRAM_SIZE);
     cpu_register_physical_memory(SDRAM_BASE, SDRAM_SIZE, sdram_addr);
     /* Register peripherals */
-    r2d_fpga_init(0x04000000);
     s = sh7750_init(env);
+    irq = r2d_fpga_init(0x04000000, sh7750_irl(s));
+
     sm501_vga_ram_addr = qemu_ram_alloc(SM501_VRAM_SIZE);
     sm501_init(ds, 0x10000000, sm501_vga_ram_addr, SM501_VRAM_SIZE,
               serial_hds[2]);
+
+    /* onboard CF (True IDE mode, Master only). */
+    if ((i = drive_get_index(IF_IDE, 0, 0)) != -1)
+        mmio_ide_init(0x14001000, 0x1400080c, irq[CF_IDE], 1,
+                      drives_table[i].bdrv, NULL);
+
+    /* PCI host and peripherals */
+    pci = sh_pci_register_bus(r2d_pci_set_irq, r2d_pci_map_irq, irq, 0, 4);
+
+    /* NIC: rtl8139 on-board, and 2 slots. */
+    if (nb_nics)
+        pci_rtl8139_init(pci, &nd_table[0], 2<<3);
+    for (i = 1; i < nb_nics; i++)
+        pci_nic_init(pci, &nd_table[i], -1);
+    /* USB OHCI for keyboard & mouse */
+    if (usb_enabled)
+        usb_ohci_init_pci(pci, 4, -1);
     /* Todo: register on board registers */
-    {
+    if (kernel_filename) {
       int kernel_size;
+      /* initialization which should be done by firmware */
+      uint32_t bcr1 = 1<<3; // cs3 SDRAM
+      uint16_t bcr2 = 3<<(3*2); // cs3 32bit
+      cpu_physical_memory_write(SH7750_BCR1_A7,&bcr1,4);
+      cpu_physical_memory_write(SH7750_BCR2_A7,&bcr2,2);
 
-      kernel_size = load_image(kernel_filename, phys_ram_base);
-
+      if (kernel_cmdline) {
+          kernel_size = load_image(kernel_filename, phys_ram_base + 0x80000);
+          env->pc = (SDRAM_BASE + 0x80000) | 0xa0000000;
+          pstrcpy(phys_ram_base + 0x10100, 256, kernel_cmdline);
+      } else {
+          kernel_size = load_image(kernel_filename, phys_ram_base);
+          env->pc = SDRAM_BASE | 0xa0000000; /* Start from P2 area */
+      }
       if (kernel_size < 0) {
         fprintf(stderr, "qemu: could not load kernel '%s'\n", kernel_filename);
         exit(1);
       }
-
-      env->pc = SDRAM_BASE | 0xa0000000; /* Start from P2 area */
     }
 }
 
Index: trunk/hw/sh_pci.c
===================================================================
--- trunk/hw/sh_pci.c   (revision 0)
+++ trunk/hw/sh_pci.c   (revision 0)
@@ -0,0 +1,207 @@
+/*
+ * SuperH on-chip PCIC emulation.      
+ *
+ * Copyright (c) 2008 Takashi YOSHII
+ *
+ * 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 "hw.h"
+#include "sh.h"
+#include "pci.h"
+#include "bswap.h"
+
+typedef struct {
+    PCIBus *bus;
+    PCIDevice *dev;
+    uint32_t regbase;
+    uint32_t iopbase;
+    uint32_t membase;
+    uint32_t par;
+    uint32_t mbr;
+    uint32_t iobr;
+} SHPCIC;
+
+static void sh_pci_reg_write (void *p, target_phys_addr_t addr, uint32_t val)
+{
+    SHPCIC *pcic = p;
+    addr -= pcic->regbase;
+    switch(addr) {
+      case 0 ... 0xfc:
+        cpu_to_le32w((uint32_t*)(pcic->dev->config + addr), val);
+        break;
+      case 0x1c0:
+        pcic->par = val;
+        break;
+      case 0x1c4:
+        pcic->mbr = val;
+        break;
+      case 0x1c8:
+        pcic->iobr = val;
+        break;
+      case 0x220:
+        pci_data_write(pcic->bus, pcic->par, val, 4);
+        break;
+    }
+}
+
+static uint32_t sh_pci_reg_read (void *p, target_phys_addr_t addr)
+{
+    SHPCIC *pcic = p;
+    addr -= pcic->regbase;
+    switch(addr) {
+      case 0 ... 0xfc:
+        return le32_to_cpup((uint32_t*)(pcic->dev->config + addr));
+      case 0x1c0:
+        return pcic->par;
+      case 0x220:
+        return pci_data_read(pcic->bus, pcic->par, 4);
+    }
+    return 0;
+}
+
+static void sh_pci_data_write (SHPCIC *pcic, target_phys_addr_t addr,
+                               uint32_t val, int size)
+{
+    pci_data_write(pcic->bus, addr - pcic->membase + pcic->mbr, val, size);
+}
+
+static uint32_t sh_pci_mem_read (SHPCIC *pcic, target_phys_addr_t addr,
+                                 int size)
+{
+    return pci_data_read(pcic->bus, addr - pcic->membase + pcic->mbr, size);
+}
+
+static void sh_pci_writeb (void *p, target_phys_addr_t addr, uint32_t val)
+{
+    sh_pci_data_write(p, addr, val, 1);
+}
+
+static void sh_pci_writew (void *p, target_phys_addr_t addr, uint32_t val)
+{
+    sh_pci_data_write(p, addr, val, 2);
+}
+
+static void sh_pci_writel (void *p, target_phys_addr_t addr, uint32_t val)
+{
+    sh_pci_data_write(p, addr, val, 4);
+}
+
+static uint32_t sh_pci_readb (void *p, target_phys_addr_t addr)
+{
+    return sh_pci_mem_read(p, addr, 1);
+}
+
+static uint32_t sh_pci_readw (void *p, target_phys_addr_t addr)
+{
+    return sh_pci_mem_read(p, addr, 2);
+}
+
+static uint32_t sh_pci_readl (void *p, target_phys_addr_t addr)
+{
+    return sh_pci_mem_read(p, addr, 4);
+}
+
+static int sh_pci_addr2port(SHPCIC *pcic, target_phys_addr_t addr)
+{
+    return addr - pcic->iopbase + pcic->iobr;
+}
+
+static void sh_pci_outb (void *p, target_phys_addr_t addr, uint32_t val)
+{
+    cpu_outb(NULL, sh_pci_addr2port(p, addr), val);
+}
+
+static void sh_pci_outw (void *p, target_phys_addr_t addr, uint32_t val)
+{
+    cpu_outw(NULL, sh_pci_addr2port(p, addr), val);
+}
+
+static void sh_pci_outl (void *p, target_phys_addr_t addr, uint32_t val)
+{
+    cpu_outl(NULL, sh_pci_addr2port(p, addr), val);
+}
+
+static uint32_t sh_pci_inb (void *p, target_phys_addr_t addr)
+{
+    return cpu_inb(NULL, sh_pci_addr2port(p, addr));
+}
+
+static uint32_t sh_pci_inw (void *p, target_phys_addr_t addr)
+{
+    return cpu_inw(NULL, sh_pci_addr2port(p, addr));
+}
+
+static uint32_t sh_pci_inl (void *p, target_phys_addr_t addr)
+{
+    return cpu_inl(NULL, sh_pci_addr2port(p, addr));
+}
+
+typedef struct {
+    CPUReadMemoryFunc *r[3];
+    CPUWriteMemoryFunc *w[3];
+} MemOp;
+
+static MemOp sh_pci_reg = {
+    { NULL, NULL, sh_pci_reg_read },
+    { NULL, NULL, sh_pci_reg_write },
+};
+
+static MemOp sh_pci_mem = {
+    { sh_pci_readb, sh_pci_readw, sh_pci_readl },
+    { sh_pci_writeb, sh_pci_writew, sh_pci_writel },
+};
+
+static MemOp sh_pci_iop = {
+    { sh_pci_inb, sh_pci_inw, sh_pci_inl },
+    { sh_pci_outb, sh_pci_outw, sh_pci_outl },
+};
+
+PCIBus *sh_pci_register_bus(pci_set_irq_fn set_irq, pci_map_irq_fn map_irq,
+                            qemu_irq *pic, int devfn_min, int nirq)
+{
+    SHPCIC *p;
+    int mem, reg, iop;
+
+    p = qemu_mallocz(sizeof(SHPCIC));
+    p->bus = pci_register_bus(set_irq, map_irq, pic, devfn_min, nirq);
+
+    p->dev = pci_register_device(p->bus, "SH PCIC", sizeof(PCIDevice),
+                                 -1, NULL, NULL);
+    p->regbase = 0x1e200000;
+    p->iopbase = 0x1e240000;
+    p->membase = 0xfd000000;
+    reg = cpu_register_io_memory(0, sh_pci_reg.r, sh_pci_reg.w, p);
+    mem = cpu_register_io_memory(0, sh_pci_mem.r, sh_pci_mem.w, p);
+    iop = cpu_register_io_memory(0, sh_pci_iop.r, sh_pci_iop.w, p);
+    cpu_register_physical_memory(p->regbase, 0x224, reg);
+    cpu_register_physical_memory(p->iopbase, 0x40000, iop);
+    cpu_register_physical_memory(p->membase, 0x1000000, mem);
+
+    p->dev->config[0x00] = 0x54; // HITACHI
+    p->dev->config[0x01] = 0x10; //
+    p->dev->config[0x02] = 0x0e; // SH7751R
+    p->dev->config[0x03] = 0x35; //
+    p->dev->config[0x04] = 0x80;
+    p->dev->config[0x05] = 0x00;
+    p->dev->config[0x06] = 0x90;
+    p->dev->config[0x07] = 0x02;
+
+    return p->bus;
+}
+
Index: trunk/hw/sh.h
===================================================================
--- trunk/hw/sh.h       (revision 5786)
+++ trunk/hw/sh.h       (working copy)
@@ -42,7 +42,14 @@
                     qemu_irq tei_source,
                     qemu_irq bri_source);
 
+/* sh7750.c */
+qemu_irq sh7750_irl(struct SH7750State *s);
+
 /* tc58128.c */
 int tc58128_init(struct SH7750State *s, const char *zone1, const char *zone2);
 
+/* ide.c */
+void mmio_ide_init(target_phys_addr_t membase, target_phys_addr_t membase2,
+                   qemu_irq irq, int shift,
+                   BlockDriverState *hd0, BlockDriverState *hd1);
 #endif
Index: trunk/hw/sh7750.c
===================================================================
--- trunk/hw/sh7750.c   (revision 5786)
+++ trunk/hw/sh7750.c   (working copy)
@@ -41,6 +41,8 @@
     /* Peripheral frequency in Hz */
     uint32_t periph_freq;
     /* SDRAM controller */
+    uint32_t bcr1;
+    uint32_t bcr2;
     uint16_t rfcr;
     /* IO ports */
     uint16_t gpioic;
@@ -208,6 +210,8 @@
     SH7750State *s = opaque;
 
     switch (addr) {
+    case SH7750_BCR2_A7:
+       return s->bcr2;
     case SH7750_FRQCR_A7:
        return 0;
     case SH7750_RFCR_A7:
@@ -231,6 +235,15 @@
     SH7750State *s = opaque;
 
     switch (addr) {
+    case SH7750_BCR1_A7:
+       return s->bcr1;
+    case SH7750_BCR4_A7:
+    case SH7750_WCR1_A7:
+    case SH7750_WCR2_A7:
+    case SH7750_WCR3_A7:
+    case SH7750_MCR_A7:
+       ignore_access("long read", addr);
+       return 0;
     case SH7750_MMUCR_A7:
        return s->cpu->mmucr;
     case SH7750_PTEH_A7:
@@ -285,6 +298,8 @@
     switch (addr) {
        /* SDRAM controller */
     case SH7750_BCR2_A7:
+       s->bcr2 = mem_value;
+       return;
     case SH7750_BCR3_A7:
     case SH7750_RTCOR_A7:
     case SH7750_RTCNT_A7:
@@ -331,6 +346,8 @@
     switch (addr) {
        /* SDRAM controller */
     case SH7750_BCR1_A7:
+       s->bcr1 = mem_value;
+        return;
     case SH7750_BCR4_A7:
     case SH7750_WCR1_A7:
     case SH7750_WCR2_A7:
@@ -412,7 +429,9 @@
        UNUSED = 0,
 
        /* interrupt sources */
-       IRL0, IRL1, IRL2, IRL3, /* only IRLM mode supported */
+       IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7,
+       IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E,
+       IRL0, IRL1, IRL2, IRL3,
        HUDI, GPIOI,
        DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
        DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
@@ -428,6 +447,8 @@
 
        /* interrupt groups */
        DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
+       /* irl bundle */
+       IRL,
 
        NR_SOURCES,
 };
@@ -529,6 +550,29 @@
                   PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
 };
 
+static struct intc_vect vectors_irl[] = {
+       INTC_VECT(IRL_0, 0x200),
+       INTC_VECT(IRL_1, 0x220),
+       INTC_VECT(IRL_2, 0x240),
+       INTC_VECT(IRL_3, 0x260),
+       INTC_VECT(IRL_4, 0x280),
+       INTC_VECT(IRL_5, 0x2a0),
+       INTC_VECT(IRL_6, 0x2c0),
+       INTC_VECT(IRL_7, 0x2e0),
+       INTC_VECT(IRL_8, 0x300),
+       INTC_VECT(IRL_9, 0x320),
+       INTC_VECT(IRL_A, 0x340),
+       INTC_VECT(IRL_B, 0x360),
+       INTC_VECT(IRL_C, 0x380),
+       INTC_VECT(IRL_D, 0x3a0),
+       INTC_VECT(IRL_E, 0x3c0),
+};
+
+static struct intc_group groups_irl[] = {
+       INTC_GROUP(IRL, IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6,
+               IRL_7, IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E),
+};
+
 /**********************************************************************
  Memory mapped cache and TLB
 **********************************************************************/
@@ -717,5 +761,16 @@
                                 NULL, 0);
     }
 
+    sh_intc_register_sources(&s->intc,
+                               _INTC_ARRAY(vectors_irl),
+                               _INTC_ARRAY(groups_irl));
     return s;
 }
+
+qemu_irq sh7750_irl(SH7750State *s)
+{
+    sh_intc_toggle_source(sh_intc_source(&s->intc, IRL), 1, 0); /* enable */
+    return qemu_allocate_irqs(sh_intc_set_irl, sh_intc_source(&s->intc, IRL),
+                               1)[0];
+}
+
Index: trunk/hw/ide.c
===================================================================
--- trunk/hw/ide.c      (revision 5786)
+++ trunk/hw/ide.c      (working copy)
@@ -3514,6 +3514,98 @@
 }
 
 /***********************************************************/
+/* MMIO based ide port
+ * This emulates IDE device connected directly to the CPU bus without
+ * dedicated ide controller, which is often seen on embedded boards.
+ */
+
+typedef struct {
+    void *dev;
+    int shift;
+} MMIOState;
+
+static uint32_t mmio_ide_read (void *opaque, target_phys_addr_t addr)
+{
+    MMIOState *s = (MMIOState*)opaque;
+    IDEState *ide = (IDEState*)s->dev;
+    addr >>= s->shift;
+    if (addr & 7)
+        return ide_ioport_read(ide, addr);
+    else
+        return ide_data_readw(ide, 0);
+}
+
+static void mmio_ide_write (void *opaque, target_phys_addr_t addr,
+       uint32_t val)
+{
+    MMIOState *s = (MMIOState*)opaque;
+    IDEState *ide = (IDEState*)s->dev;
+    addr >>= s->shift;
+    if (addr & 7)
+        ide_ioport_write(ide, addr, val);
+    else
+        ide_data_writew(ide, 0, val);
+}
+
+static CPUReadMemoryFunc *mmio_ide_reads[] = {
+    mmio_ide_read,
+    mmio_ide_read,
+    mmio_ide_read,
+};
+
+static CPUWriteMemoryFunc *mmio_ide_writes[] = {
+    mmio_ide_write,
+    mmio_ide_write,
+    mmio_ide_write,
+};
+
+static uint32_t mmio_ide_status_read (void *opaque, target_phys_addr_t addr)
+{
+    MMIOState *s= (MMIOState*)opaque;
+    IDEState *ide = (IDEState*)s->dev;
+    return ide_status_read(ide, 0);
+}
+
+static void mmio_ide_cmd_write (void *opaque, target_phys_addr_t addr,
+       uint32_t val)
+{
+    MMIOState *s = (MMIOState*)opaque;
+    IDEState *ide = (IDEState*)s->dev;
+    ide_cmd_write(ide, 0, val);
+}
+
+static CPUReadMemoryFunc *mmio_ide_status[] = {
+    mmio_ide_status_read,
+    mmio_ide_status_read,
+    mmio_ide_status_read,
+};
+
+static CPUWriteMemoryFunc *mmio_ide_cmd[] = {
+    mmio_ide_cmd_write,
+    mmio_ide_cmd_write,
+    mmio_ide_cmd_write,
+};
+
+void mmio_ide_init (target_phys_addr_t membase, target_phys_addr_t membase2, 
+                   qemu_irq irq, int shift,
+                    BlockDriverState *hd0, BlockDriverState *hd1)
+{
+    MMIOState *s = qemu_mallocz(sizeof(MMIOState));
+    IDEState *ide = qemu_mallocz(sizeof(IDEState) * 2);
+    int mem1, mem2;
+
+    ide_init2(ide, hd0, hd1, irq);
+
+    s->dev = ide;
+    s->shift = shift;
+
+    mem1 = cpu_register_io_memory(0, mmio_ide_reads, mmio_ide_writes, s);
+    mem2 = cpu_register_io_memory(0, mmio_ide_status, mmio_ide_cmd, s);
+    cpu_register_physical_memory(membase, 16<<shift, mem1);
+    cpu_register_physical_memory(membase2, 2<<shift, mem2);
+}
+
+/***********************************************************/
 /* CF-ATA Microdrive */
 
 #define METADATA_SIZE  0x20
Index: trunk/hw/sh_intc.c
===================================================================
--- trunk/hw/sh_intc.c  (revision 5786)
+++ trunk/hw/sh_intc.c  (working copy)
@@ -464,3 +464,18 @@
 
     return 0;
 }
+
+/* Assert level <n> IRL interrupt. 
+   0:deassert. 1:lowest priority,... 15:highest priority. */
+void sh_intc_set_irl(void *opaque, int n, int level)
+{
+    struct intc_source *s = opaque;
+    int i, irl = level ^ 15;
+    for (i = 0; (s = sh_intc_source(s->parent, s->next_enum_id)); i++) {
+       if (i == irl)
+           sh_intc_toggle_source(s, s->enable_count?0:1, s->asserted?0:1);
+       else
+           if (s->asserted)
+               sh_intc_toggle_source(s, 0, -1);
+    }
+}
Index: trunk/hw/sh_intc.h
===================================================================
--- trunk/hw/sh_intc.h  (revision 5786)
+++ trunk/hw/sh_intc.h  (working copy)
@@ -75,4 +75,6 @@
                 struct intc_prio_reg *prio_regs,
                 int nr_prio_regs);
 
+void sh_intc_set_irl(void *opaque, int n, int level);
+
 #endif /* __SH_INTC_H__ */

reply via email to

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