qemu/hw/sh4/sh7750.c
<<
>>
Prefs
   1/*
   2 * SH7750 device
   3 *
   4 * Copyright (c) 2007 Magnus Damm
   5 * Copyright (c) 2005 Samuel Tardieu
   6 *
   7 * Permission is hereby granted, free of charge, to any person obtaining a copy
   8 * of this software and associated documentation files (the "Software"), to deal
   9 * in the Software without restriction, including without limitation the rights
  10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11 * copies of the Software, and to permit persons to whom the Software is
  12 * furnished to do so, subject to the following conditions:
  13 *
  14 * The above copyright notice and this permission notice shall be included in
  15 * all copies or substantial portions of the Software.
  16 *
  17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  23 * THE SOFTWARE.
  24 */
  25
  26#include "qemu/osdep.h"
  27#include "qapi/error.h"
  28#include "hw/sysbus.h"
  29#include "hw/irq.h"
  30#include "hw/sh4/sh.h"
  31#include "sysemu/sysemu.h"
  32#include "hw/qdev-properties.h"
  33#include "hw/qdev-properties-system.h"
  34#include "sh7750_regs.h"
  35#include "sh7750_regnames.h"
  36#include "hw/sh4/sh_intc.h"
  37#include "hw/timer/tmu012.h"
  38#include "exec/exec-all.h"
  39#include "trace.h"
  40
  41#define NB_DEVICES 4
  42
  43typedef struct SH7750State {
  44    MemoryRegion iomem;
  45    MemoryRegion iomem_1f0;
  46    MemoryRegion iomem_ff0;
  47    MemoryRegion iomem_1f8;
  48    MemoryRegion iomem_ff8;
  49    MemoryRegion iomem_1fc;
  50    MemoryRegion iomem_ffc;
  51    MemoryRegion mmct_iomem;
  52    /* CPU */
  53    SuperHCPU *cpu;
  54    /* Peripheral frequency in Hz */
  55    uint32_t periph_freq;
  56    /* SDRAM controller */
  57    uint32_t bcr1;
  58    uint16_t bcr2;
  59    uint16_t bcr3;
  60    uint32_t bcr4;
  61    uint16_t rfcr;
  62    /* PCMCIA controller */
  63    uint16_t pcr;
  64    /* IO ports */
  65    uint16_t gpioic;
  66    uint32_t pctra;
  67    uint32_t pctrb;
  68    uint16_t portdira;        /* Cached */
  69    uint16_t portpullupa;     /* Cached */
  70    uint16_t portdirb;        /* Cached */
  71    uint16_t portpullupb;     /* Cached */
  72    uint16_t pdtra;
  73    uint16_t pdtrb;
  74    uint16_t periph_pdtra;    /* Imposed by the peripherals */
  75    uint16_t periph_portdira; /* Direction seen from the peripherals */
  76    uint16_t periph_pdtrb;    /* Imposed by the peripherals */
  77    uint16_t periph_portdirb; /* Direction seen from the peripherals */
  78    sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */
  79
  80    /* Cache */
  81    uint32_t ccr;
  82
  83    struct intc_desc intc;
  84} SH7750State;
  85
  86static inline int has_bcr3_and_bcr4(SH7750State *s)
  87{
  88    return s->cpu->env.features & SH_FEATURE_BCR3_AND_BCR4;
  89}
  90
  91/*
  92 * I/O ports
  93 */
  94
  95int sh7750_register_io_device(SH7750State *s, sh7750_io_device *device)
  96{
  97    int i;
  98
  99    for (i = 0; i < NB_DEVICES; i++) {
 100        if (s->devices[i] == NULL) {
 101            s->devices[i] = device;
 102            return 0;
 103        }
 104    }
 105    return -1;
 106}
 107
 108static uint16_t portdir(uint32_t v)
 109{
 110#define EVENPORTMASK(n) ((v & (1 << ((n) << 1))) >> (n))
 111    return
 112        EVENPORTMASK(15) | EVENPORTMASK(14) | EVENPORTMASK(13) |
 113        EVENPORTMASK(12) | EVENPORTMASK(11) | EVENPORTMASK(10) |
 114        EVENPORTMASK(9) | EVENPORTMASK(8) | EVENPORTMASK(7) |
 115        EVENPORTMASK(6) | EVENPORTMASK(5) | EVENPORTMASK(4) |
 116        EVENPORTMASK(3) | EVENPORTMASK(2) | EVENPORTMASK(1) |
 117        EVENPORTMASK(0);
 118}
 119
 120static uint16_t portpullup(uint32_t v)
 121{
 122#define ODDPORTMASK(n) ((v & (1 << (((n) << 1) + 1))) >> (n))
 123    return
 124        ODDPORTMASK(15) | ODDPORTMASK(14) | ODDPORTMASK(13) |
 125        ODDPORTMASK(12) | ODDPORTMASK(11) | ODDPORTMASK(10) |
 126        ODDPORTMASK(9) | ODDPORTMASK(8) | ODDPORTMASK(7) | ODDPORTMASK(6) |
 127        ODDPORTMASK(5) | ODDPORTMASK(4) | ODDPORTMASK(3) | ODDPORTMASK(2) |
 128        ODDPORTMASK(1) | ODDPORTMASK(0);
 129}
 130
 131static uint16_t porta_lines(SH7750State *s)
 132{
 133    return (s->portdira & s->pdtra) | /* CPU */
 134        (s->periph_portdira & s->periph_pdtra) | /* Peripherals */
 135        (~(s->portdira | s->periph_portdira) & s->portpullupa); /* Pullups */
 136}
 137
 138static uint16_t portb_lines(SH7750State *s)
 139{
 140    return (s->portdirb & s->pdtrb) | /* CPU */
 141        (s->periph_portdirb & s->periph_pdtrb) | /* Peripherals */
 142        (~(s->portdirb | s->periph_portdirb) & s->portpullupb); /* Pullups */
 143}
 144
 145static void gen_port_interrupts(SH7750State *s)
 146{
 147    /* XXXXX interrupts not generated */
 148}
 149
 150static void porta_changed(SH7750State *s, uint16_t prev)
 151{
 152    uint16_t currenta, changes;
 153    int i, r = 0;
 154
 155    currenta = porta_lines(s);
 156    if (currenta == prev) {
 157        return;
 158    }
 159    trace_sh7750_porta(prev, currenta, s->pdtra, s->pctra);
 160    changes = currenta ^ prev;
 161
 162    for (i = 0; i < NB_DEVICES; i++) {
 163        if (s->devices[i] && (s->devices[i]->portamask_trigger & changes)) {
 164            r |= s->devices[i]->port_change_cb(currenta, portb_lines(s),
 165                                               &s->periph_pdtra,
 166                                               &s->periph_portdira,
 167                                               &s->periph_pdtrb,
 168                                               &s->periph_portdirb);
 169        }
 170    }
 171
 172    if (r) {
 173        gen_port_interrupts(s);
 174    }
 175}
 176
 177static void portb_changed(SH7750State *s, uint16_t prev)
 178{
 179    uint16_t currentb, changes;
 180    int i, r = 0;
 181
 182    currentb = portb_lines(s);
 183    if (currentb == prev) {
 184        return;
 185    }
 186    trace_sh7750_portb(prev, currentb, s->pdtrb, s->pctrb);
 187    changes = currentb ^ prev;
 188
 189    for (i = 0; i < NB_DEVICES; i++) {
 190        if (s->devices[i] && (s->devices[i]->portbmask_trigger & changes)) {
 191            r |= s->devices[i]->port_change_cb(portb_lines(s), currentb,
 192                                               &s->periph_pdtra,
 193                                               &s->periph_portdira,
 194                                               &s->periph_pdtrb,
 195                                               &s->periph_portdirb);
 196        }
 197    }
 198
 199    if (r) {
 200        gen_port_interrupts(s);
 201    }
 202}
 203
 204/*
 205 * Memory
 206 */
 207
 208static void error_access(const char *kind, hwaddr addr)
 209{
 210    fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") not supported\n",
 211            kind, regname(addr), addr);
 212}
 213
 214static void ignore_access(const char *kind, hwaddr addr)
 215{
 216    fprintf(stderr, "%s to %s (0x" TARGET_FMT_plx ") ignored\n",
 217            kind, regname(addr), addr);
 218}
 219
 220static uint32_t sh7750_mem_readb(void *opaque, hwaddr addr)
 221{
 222    switch (addr) {
 223    default:
 224        error_access("byte read", addr);
 225        abort();
 226    }
 227}
 228
 229static uint32_t sh7750_mem_readw(void *opaque, hwaddr addr)
 230{
 231    SH7750State *s = opaque;
 232
 233    switch (addr) {
 234    case SH7750_BCR2_A7:
 235        return s->bcr2;
 236    case SH7750_BCR3_A7:
 237        if (!has_bcr3_and_bcr4(s)) {
 238            error_access("word read", addr);
 239        }
 240        return s->bcr3;
 241    case SH7750_FRQCR_A7:
 242        return 0;
 243    case SH7750_PCR_A7:
 244        return s->pcr;
 245    case SH7750_RFCR_A7:
 246        fprintf(stderr,
 247                "Read access to refresh count register, incrementing\n");
 248        return s->rfcr++;
 249    case SH7750_PDTRA_A7:
 250        return porta_lines(s);
 251    case SH7750_PDTRB_A7:
 252        return portb_lines(s);
 253    case SH7750_RTCOR_A7:
 254    case SH7750_RTCNT_A7:
 255    case SH7750_RTCSR_A7:
 256        ignore_access("word read", addr);
 257        return 0;
 258    default:
 259        error_access("word read", addr);
 260        abort();
 261    }
 262}
 263
 264static uint32_t sh7750_mem_readl(void *opaque, hwaddr addr)
 265{
 266    SH7750State *s = opaque;
 267    SuperHCPUClass *scc;
 268
 269    switch (addr) {
 270    case SH7750_BCR1_A7:
 271        return s->bcr1;
 272    case SH7750_BCR4_A7:
 273        if (!has_bcr3_and_bcr4(s)) {
 274            error_access("long read", addr);
 275        }
 276        return s->bcr4;
 277    case SH7750_WCR1_A7:
 278    case SH7750_WCR2_A7:
 279    case SH7750_WCR3_A7:
 280    case SH7750_MCR_A7:
 281        ignore_access("long read", addr);
 282        return 0;
 283    case SH7750_MMUCR_A7:
 284        return s->cpu->env.mmucr;
 285    case SH7750_PTEH_A7:
 286        return s->cpu->env.pteh;
 287    case SH7750_PTEL_A7:
 288        return s->cpu->env.ptel;
 289    case SH7750_TTB_A7:
 290        return s->cpu->env.ttb;
 291    case SH7750_TEA_A7:
 292        return s->cpu->env.tea;
 293    case SH7750_TRA_A7:
 294        return s->cpu->env.tra;
 295    case SH7750_EXPEVT_A7:
 296        return s->cpu->env.expevt;
 297    case SH7750_INTEVT_A7:
 298        return s->cpu->env.intevt;
 299    case SH7750_CCR_A7:
 300        return s->ccr;
 301    case 0x1f000030: /* Processor version */
 302        scc = SUPERH_CPU_GET_CLASS(s->cpu);
 303        return scc->pvr;
 304    case 0x1f000040: /* Cache version */
 305        scc = SUPERH_CPU_GET_CLASS(s->cpu);
 306        return scc->cvr;
 307    case 0x1f000044: /* Processor revision */
 308        scc = SUPERH_CPU_GET_CLASS(s->cpu);
 309        return scc->prr;
 310    default:
 311        error_access("long read", addr);
 312        abort();
 313    }
 314}
 315
 316#define is_in_sdrmx(a, x) (a >= SH7750_SDMR ## x ## _A7 \
 317                        && a <= (SH7750_SDMR ## x ## _A7 + SH7750_SDMR ## x ## _REGNB))
 318static void sh7750_mem_writeb(void *opaque, hwaddr addr,
 319                              uint32_t mem_value)
 320{
 321
 322    if (is_in_sdrmx(addr, 2) || is_in_sdrmx(addr, 3)) {
 323        ignore_access("byte write", addr);
 324        return;
 325    }
 326
 327    error_access("byte write", addr);
 328    abort();
 329}
 330
 331static void sh7750_mem_writew(void *opaque, hwaddr addr,
 332                              uint32_t mem_value)
 333{
 334    SH7750State *s = opaque;
 335    uint16_t temp;
 336
 337    switch (addr) {
 338        /* SDRAM controller */
 339    case SH7750_BCR2_A7:
 340        s->bcr2 = mem_value;
 341        return;
 342    case SH7750_BCR3_A7:
 343        if (!has_bcr3_and_bcr4(s)) {
 344            error_access("word write", addr);
 345        }
 346        s->bcr3 = mem_value;
 347        return;
 348    case SH7750_PCR_A7:
 349        s->pcr = mem_value;
 350        return;
 351    case SH7750_RTCNT_A7:
 352    case SH7750_RTCOR_A7:
 353    case SH7750_RTCSR_A7:
 354        ignore_access("word write", addr);
 355        return;
 356        /* IO ports */
 357    case SH7750_PDTRA_A7:
 358        temp = porta_lines(s);
 359        s->pdtra = mem_value;
 360        porta_changed(s, temp);
 361        return;
 362    case SH7750_PDTRB_A7:
 363        temp = portb_lines(s);
 364        s->pdtrb = mem_value;
 365        portb_changed(s, temp);
 366        return;
 367    case SH7750_RFCR_A7:
 368        fprintf(stderr, "Write access to refresh count register\n");
 369        s->rfcr = mem_value;
 370        return;
 371    case SH7750_GPIOIC_A7:
 372        s->gpioic = mem_value;
 373        if (mem_value != 0) {
 374            fprintf(stderr, "I/O interrupts not implemented\n");
 375            abort();
 376        }
 377        return;
 378    default:
 379        error_access("word write", addr);
 380        abort();
 381    }
 382}
 383
 384static void sh7750_mem_writel(void *opaque, hwaddr addr,
 385                              uint32_t mem_value)
 386{
 387    SH7750State *s = opaque;
 388    uint16_t temp;
 389
 390    switch (addr) {
 391        /* SDRAM controller */
 392    case SH7750_BCR1_A7:
 393        s->bcr1 = mem_value;
 394        return;
 395    case SH7750_BCR4_A7:
 396        if (!has_bcr3_and_bcr4(s)) {
 397            error_access("long write", addr);
 398        }
 399        s->bcr4 = mem_value;
 400        return;
 401    case SH7750_WCR1_A7:
 402    case SH7750_WCR2_A7:
 403    case SH7750_WCR3_A7:
 404    case SH7750_MCR_A7:
 405        ignore_access("long write", addr);
 406        return;
 407        /* IO ports */
 408    case SH7750_PCTRA_A7:
 409        temp = porta_lines(s);
 410        s->pctra = mem_value;
 411        s->portdira = portdir(mem_value);
 412        s->portpullupa = portpullup(mem_value);
 413        porta_changed(s, temp);
 414        return;
 415    case SH7750_PCTRB_A7:
 416        temp = portb_lines(s);
 417        s->pctrb = mem_value;
 418        s->portdirb = portdir(mem_value);
 419        s->portpullupb = portpullup(mem_value);
 420        portb_changed(s, temp);
 421        return;
 422    case SH7750_MMUCR_A7:
 423        if (mem_value & MMUCR_TI) {
 424            cpu_sh4_invalidate_tlb(&s->cpu->env);
 425        }
 426        s->cpu->env.mmucr = mem_value & ~MMUCR_TI;
 427        return;
 428    case SH7750_PTEH_A7:
 429        /* If asid changes, clear all registered tlb entries. */
 430        if ((s->cpu->env.pteh & 0xff) != (mem_value & 0xff)) {
 431            tlb_flush(CPU(s->cpu));
 432        }
 433        s->cpu->env.pteh = mem_value;
 434        return;
 435    case SH7750_PTEL_A7:
 436        s->cpu->env.ptel = mem_value;
 437        return;
 438    case SH7750_PTEA_A7:
 439        s->cpu->env.ptea = mem_value & 0x0000000f;
 440        return;
 441    case SH7750_TTB_A7:
 442        s->cpu->env.ttb = mem_value;
 443        return;
 444    case SH7750_TEA_A7:
 445        s->cpu->env.tea = mem_value;
 446        return;
 447    case SH7750_TRA_A7:
 448        s->cpu->env.tra = mem_value & 0x000007ff;
 449        return;
 450    case SH7750_EXPEVT_A7:
 451        s->cpu->env.expevt = mem_value & 0x000007ff;
 452        return;
 453    case SH7750_INTEVT_A7:
 454        s->cpu->env.intevt = mem_value & 0x000007ff;
 455        return;
 456    case SH7750_CCR_A7:
 457        s->ccr = mem_value;
 458        return;
 459    default:
 460        error_access("long write", addr);
 461        abort();
 462    }
 463}
 464
 465static uint64_t sh7750_mem_readfn(void *opaque, hwaddr addr, unsigned size)
 466{
 467    switch (size) {
 468    case 1:
 469        return sh7750_mem_readb(opaque, addr);
 470    case 2:
 471        return sh7750_mem_readw(opaque, addr);
 472    case 4:
 473        return sh7750_mem_readl(opaque, addr);
 474    default:
 475        g_assert_not_reached();
 476    }
 477}
 478
 479static void sh7750_mem_writefn(void *opaque, hwaddr addr,
 480                               uint64_t value, unsigned size)
 481{
 482    switch (size) {
 483    case 1:
 484        sh7750_mem_writeb(opaque, addr, value);
 485        break;
 486    case 2:
 487        sh7750_mem_writew(opaque, addr, value);
 488        break;
 489    case 4:
 490        sh7750_mem_writel(opaque, addr, value);
 491        break;
 492    default:
 493        g_assert_not_reached();
 494    }
 495}
 496
 497static const MemoryRegionOps sh7750_mem_ops = {
 498    .read = sh7750_mem_readfn,
 499    .write = sh7750_mem_writefn,
 500    .valid.min_access_size = 1,
 501    .valid.max_access_size = 4,
 502    .endianness = DEVICE_NATIVE_ENDIAN,
 503};
 504
 505/*
 506 * sh775x interrupt controller tables for sh_intc.c
 507 * stolen from linux/arch/sh/kernel/cpu/sh4/setup-sh7750.c
 508 */
 509
 510enum {
 511    UNUSED = 0,
 512
 513    /* interrupt sources */
 514    IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6, IRL_7,
 515    IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E,
 516    IRL0, IRL1, IRL2, IRL3,
 517    HUDI, GPIOI,
 518    DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2, DMAC_DMTE3,
 519    DMAC_DMTE4, DMAC_DMTE5, DMAC_DMTE6, DMAC_DMTE7,
 520    DMAC_DMAE,
 521    PCIC0_PCISERR, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
 522    PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3,
 523    TMU3, TMU4, TMU0, TMU1, TMU2_TUNI, TMU2_TICPI,
 524    RTC_ATI, RTC_PRI, RTC_CUI,
 525    SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI,
 526    SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI,
 527    WDT,
 528    REF_RCMI, REF_ROVI,
 529
 530    /* interrupt groups */
 531    DMAC, PCIC1, TMU2, RTC, SCI1, SCIF, REF,
 532    /* irl bundle */
 533    IRL,
 534
 535    NR_SOURCES,
 536};
 537
 538static struct intc_vect vectors[] = {
 539    INTC_VECT(HUDI, 0x600), INTC_VECT(GPIOI, 0x620),
 540    INTC_VECT(TMU0, 0x400), INTC_VECT(TMU1, 0x420),
 541    INTC_VECT(TMU2_TUNI, 0x440), INTC_VECT(TMU2_TICPI, 0x460),
 542    INTC_VECT(RTC_ATI, 0x480), INTC_VECT(RTC_PRI, 0x4a0),
 543    INTC_VECT(RTC_CUI, 0x4c0),
 544    INTC_VECT(SCI1_ERI, 0x4e0), INTC_VECT(SCI1_RXI, 0x500),
 545    INTC_VECT(SCI1_TXI, 0x520), INTC_VECT(SCI1_TEI, 0x540),
 546    INTC_VECT(SCIF_ERI, 0x700), INTC_VECT(SCIF_RXI, 0x720),
 547    INTC_VECT(SCIF_BRI, 0x740), INTC_VECT(SCIF_TXI, 0x760),
 548    INTC_VECT(WDT, 0x560),
 549    INTC_VECT(REF_RCMI, 0x580), INTC_VECT(REF_ROVI, 0x5a0),
 550};
 551
 552static struct intc_group groups[] = {
 553    INTC_GROUP(TMU2, TMU2_TUNI, TMU2_TICPI),
 554    INTC_GROUP(RTC, RTC_ATI, RTC_PRI, RTC_CUI),
 555    INTC_GROUP(SCI1, SCI1_ERI, SCI1_RXI, SCI1_TXI, SCI1_TEI),
 556    INTC_GROUP(SCIF, SCIF_ERI, SCIF_RXI, SCIF_BRI, SCIF_TXI),
 557    INTC_GROUP(REF, REF_RCMI, REF_ROVI),
 558};
 559
 560static struct intc_prio_reg prio_registers[] = {
 561    { 0xffd00004, 0, 16, 4, /* IPRA */ { TMU0, TMU1, TMU2, RTC } },
 562    { 0xffd00008, 0, 16, 4, /* IPRB */ { WDT, REF, SCI1, 0 } },
 563    { 0xffd0000c, 0, 16, 4, /* IPRC */ { GPIOI, DMAC, SCIF, HUDI } },
 564    { 0xffd00010, 0, 16, 4, /* IPRD */ { IRL0, IRL1, IRL2, IRL3 } },
 565    { 0xfe080000, 0, 32, 4, /* INTPRI00 */ { 0, 0, 0, 0, TMU4, TMU3,
 566                                             PCIC1, PCIC0_PCISERR } },
 567};
 568
 569/* SH7750, SH7750S, SH7751 and SH7091 all have 4-channel DMA controllers */
 570
 571static struct intc_vect vectors_dma4[] = {
 572    INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
 573    INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
 574    INTC_VECT(DMAC_DMAE, 0x6c0),
 575};
 576
 577static struct intc_group groups_dma4[] = {
 578    INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
 579               DMAC_DMTE3, DMAC_DMAE),
 580};
 581
 582/* SH7750R and SH7751R both have 8-channel DMA controllers */
 583
 584static struct intc_vect vectors_dma8[] = {
 585    INTC_VECT(DMAC_DMTE0, 0x640), INTC_VECT(DMAC_DMTE1, 0x660),
 586    INTC_VECT(DMAC_DMTE2, 0x680), INTC_VECT(DMAC_DMTE3, 0x6a0),
 587    INTC_VECT(DMAC_DMTE4, 0x780), INTC_VECT(DMAC_DMTE5, 0x7a0),
 588    INTC_VECT(DMAC_DMTE6, 0x7c0), INTC_VECT(DMAC_DMTE7, 0x7e0),
 589    INTC_VECT(DMAC_DMAE, 0x6c0),
 590};
 591
 592static struct intc_group groups_dma8[] = {
 593    INTC_GROUP(DMAC, DMAC_DMTE0, DMAC_DMTE1, DMAC_DMTE2,
 594               DMAC_DMTE3, DMAC_DMTE4, DMAC_DMTE5,
 595               DMAC_DMTE6, DMAC_DMTE7, DMAC_DMAE),
 596};
 597
 598/* SH7750R, SH7751 and SH7751R all have two extra timer channels */
 599
 600static struct intc_vect vectors_tmu34[] = {
 601    INTC_VECT(TMU3, 0xb00), INTC_VECT(TMU4, 0xb80),
 602};
 603
 604static struct intc_mask_reg mask_registers[] = {
 605    { 0xfe080040, 0xfe080060, 32, /* INTMSK00 / INTMSKCLR00 */
 606      { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
 607        0, 0, 0, 0, 0, 0, TMU4, TMU3,
 608        PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
 609        PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2,
 610        PCIC1_PCIDMA3, PCIC0_PCISERR } },
 611};
 612
 613/* SH7750S, SH7750R, SH7751 and SH7751R all have IRLM priority registers */
 614
 615static struct intc_vect vectors_irlm[] = {
 616    INTC_VECT(IRL0, 0x240), INTC_VECT(IRL1, 0x2a0),
 617    INTC_VECT(IRL2, 0x300), INTC_VECT(IRL3, 0x360),
 618};
 619
 620/* SH7751 and SH7751R both have PCI */
 621
 622static struct intc_vect vectors_pci[] = {
 623    INTC_VECT(PCIC0_PCISERR, 0xa00), INTC_VECT(PCIC1_PCIERR, 0xae0),
 624    INTC_VECT(PCIC1_PCIPWDWN, 0xac0), INTC_VECT(PCIC1_PCIPWON, 0xaa0),
 625    INTC_VECT(PCIC1_PCIDMA0, 0xa80), INTC_VECT(PCIC1_PCIDMA1, 0xa60),
 626    INTC_VECT(PCIC1_PCIDMA2, 0xa40), INTC_VECT(PCIC1_PCIDMA3, 0xa20),
 627};
 628
 629static struct intc_group groups_pci[] = {
 630    INTC_GROUP(PCIC1, PCIC1_PCIERR, PCIC1_PCIPWDWN, PCIC1_PCIPWON,
 631               PCIC1_PCIDMA0, PCIC1_PCIDMA1, PCIC1_PCIDMA2, PCIC1_PCIDMA3),
 632};
 633
 634static struct intc_vect vectors_irl[] = {
 635    INTC_VECT(IRL_0, 0x200),
 636    INTC_VECT(IRL_1, 0x220),
 637    INTC_VECT(IRL_2, 0x240),
 638    INTC_VECT(IRL_3, 0x260),
 639    INTC_VECT(IRL_4, 0x280),
 640    INTC_VECT(IRL_5, 0x2a0),
 641    INTC_VECT(IRL_6, 0x2c0),
 642    INTC_VECT(IRL_7, 0x2e0),
 643    INTC_VECT(IRL_8, 0x300),
 644    INTC_VECT(IRL_9, 0x320),
 645    INTC_VECT(IRL_A, 0x340),
 646    INTC_VECT(IRL_B, 0x360),
 647    INTC_VECT(IRL_C, 0x380),
 648    INTC_VECT(IRL_D, 0x3a0),
 649    INTC_VECT(IRL_E, 0x3c0),
 650};
 651
 652static struct intc_group groups_irl[] = {
 653    INTC_GROUP(IRL, IRL_0, IRL_1, IRL_2, IRL_3, IRL_4, IRL_5, IRL_6,
 654        IRL_7, IRL_8, IRL_9, IRL_A, IRL_B, IRL_C, IRL_D, IRL_E),
 655};
 656
 657/*
 658 * Memory mapped cache and TLB
 659 */
 660
 661#define MM_REGION_MASK   0x07000000
 662#define MM_ICACHE_ADDR   (0)
 663#define MM_ICACHE_DATA   (1)
 664#define MM_ITLB_ADDR     (2)
 665#define MM_ITLB_DATA     (3)
 666#define MM_OCACHE_ADDR   (4)
 667#define MM_OCACHE_DATA   (5)
 668#define MM_UTLB_ADDR     (6)
 669#define MM_UTLB_DATA     (7)
 670#define MM_REGION_TYPE(addr)  ((addr & MM_REGION_MASK) >> 24)
 671
 672static uint64_t invalid_read(void *opaque, hwaddr addr)
 673{
 674    abort();
 675
 676    return 0;
 677}
 678
 679static uint64_t sh7750_mmct_read(void *opaque, hwaddr addr,
 680                                 unsigned size)
 681{
 682    SH7750State *s = opaque;
 683    uint32_t ret = 0;
 684
 685    if (size != 4) {
 686        return invalid_read(opaque, addr);
 687    }
 688
 689    switch (MM_REGION_TYPE(addr)) {
 690    case MM_ICACHE_ADDR:
 691    case MM_ICACHE_DATA:
 692        /* do nothing */
 693        break;
 694    case MM_ITLB_ADDR:
 695        ret = cpu_sh4_read_mmaped_itlb_addr(&s->cpu->env, addr);
 696        break;
 697    case MM_ITLB_DATA:
 698        ret = cpu_sh4_read_mmaped_itlb_data(&s->cpu->env, addr);
 699        break;
 700    case MM_OCACHE_ADDR:
 701    case MM_OCACHE_DATA:
 702        /* do nothing */
 703        break;
 704    case MM_UTLB_ADDR:
 705        ret = cpu_sh4_read_mmaped_utlb_addr(&s->cpu->env, addr);
 706        break;
 707    case MM_UTLB_DATA:
 708        ret = cpu_sh4_read_mmaped_utlb_data(&s->cpu->env, addr);
 709        break;
 710    default:
 711        abort();
 712    }
 713
 714    return ret;
 715}
 716
 717static void invalid_write(void *opaque, hwaddr addr,
 718                          uint64_t mem_value)
 719{
 720    abort();
 721}
 722
 723static void sh7750_mmct_write(void *opaque, hwaddr addr,
 724                              uint64_t mem_value, unsigned size)
 725{
 726    SH7750State *s = opaque;
 727
 728    if (size != 4) {
 729        invalid_write(opaque, addr, mem_value);
 730    }
 731
 732    switch (MM_REGION_TYPE(addr)) {
 733    case MM_ICACHE_ADDR:
 734    case MM_ICACHE_DATA:
 735        /* do nothing */
 736        break;
 737    case MM_ITLB_ADDR:
 738        cpu_sh4_write_mmaped_itlb_addr(&s->cpu->env, addr, mem_value);
 739        break;
 740    case MM_ITLB_DATA:
 741        cpu_sh4_write_mmaped_itlb_data(&s->cpu->env, addr, mem_value);
 742        abort();
 743        break;
 744    case MM_OCACHE_ADDR:
 745    case MM_OCACHE_DATA:
 746        /* do nothing */
 747        break;
 748    case MM_UTLB_ADDR:
 749        cpu_sh4_write_mmaped_utlb_addr(&s->cpu->env, addr, mem_value);
 750        break;
 751    case MM_UTLB_DATA:
 752        cpu_sh4_write_mmaped_utlb_data(&s->cpu->env, addr, mem_value);
 753        break;
 754    default:
 755        abort();
 756        break;
 757    }
 758}
 759
 760static const MemoryRegionOps sh7750_mmct_ops = {
 761    .read = sh7750_mmct_read,
 762    .write = sh7750_mmct_write,
 763    .endianness = DEVICE_NATIVE_ENDIAN,
 764};
 765
 766SH7750State *sh7750_init(SuperHCPU *cpu, MemoryRegion *sysmem)
 767{
 768    SH7750State *s;
 769    DeviceState *dev;
 770    SysBusDevice *sb;
 771    MemoryRegion *mr, *alias;
 772
 773    s = g_new0(SH7750State, 1);
 774    s->cpu = cpu;
 775    s->periph_freq = 60000000; /* 60MHz */
 776    memory_region_init_io(&s->iomem, NULL, &sh7750_mem_ops, s,
 777                          "memory", 0x1fc01000);
 778
 779    memory_region_init_alias(&s->iomem_1f0, NULL, "memory-1f0",
 780                             &s->iomem, 0x1f000000, 0x1000);
 781    memory_region_add_subregion(sysmem, 0x1f000000, &s->iomem_1f0);
 782
 783    memory_region_init_alias(&s->iomem_ff0, NULL, "memory-ff0",
 784                             &s->iomem, 0x1f000000, 0x1000);
 785    memory_region_add_subregion(sysmem, 0xff000000, &s->iomem_ff0);
 786
 787    memory_region_init_alias(&s->iomem_1f8, NULL, "memory-1f8",
 788                             &s->iomem, 0x1f800000, 0x1000);
 789    memory_region_add_subregion(sysmem, 0x1f800000, &s->iomem_1f8);
 790
 791    memory_region_init_alias(&s->iomem_ff8, NULL, "memory-ff8",
 792                             &s->iomem, 0x1f800000, 0x1000);
 793    memory_region_add_subregion(sysmem, 0xff800000, &s->iomem_ff8);
 794
 795    memory_region_init_alias(&s->iomem_1fc, NULL, "memory-1fc",
 796                             &s->iomem, 0x1fc00000, 0x1000);
 797    memory_region_add_subregion(sysmem, 0x1fc00000, &s->iomem_1fc);
 798
 799    memory_region_init_alias(&s->iomem_ffc, NULL, "memory-ffc",
 800                             &s->iomem, 0x1fc00000, 0x1000);
 801    memory_region_add_subregion(sysmem, 0xffc00000, &s->iomem_ffc);
 802
 803    memory_region_init_io(&s->mmct_iomem, NULL, &sh7750_mmct_ops, s,
 804                          "cache-and-tlb", 0x08000000);
 805    memory_region_add_subregion(sysmem, 0xf0000000, &s->mmct_iomem);
 806
 807    sh_intc_init(sysmem, &s->intc, NR_SOURCES,
 808                 _INTC_ARRAY(mask_registers),
 809                 _INTC_ARRAY(prio_registers));
 810
 811    sh_intc_register_sources(&s->intc,
 812                             _INTC_ARRAY(vectors),
 813                             _INTC_ARRAY(groups));
 814
 815    cpu->env.intc_handle = &s->intc;
 816
 817    /* SCI */
 818    dev = qdev_new(TYPE_SH_SERIAL);
 819    dev->id = g_strdup("sci");
 820    qdev_prop_set_chr(dev, "chardev", serial_hd(0));
 821    sb = SYS_BUS_DEVICE(dev);
 822    sysbus_realize_and_unref(sb, &error_fatal);
 823    sysbus_mmio_map(sb, 0, 0xffe00000);
 824    alias = g_malloc(sizeof(*alias));
 825    mr = sysbus_mmio_get_region(sb, 0);
 826    memory_region_init_alias(alias, OBJECT(dev), "sci-a7", mr,
 827                             0, memory_region_size(mr));
 828    memory_region_add_subregion(sysmem, A7ADDR(0xffe00000), alias);
 829    qdev_connect_gpio_out_named(dev, "eri", 0, s->intc.irqs[SCI1_ERI]);
 830    qdev_connect_gpio_out_named(dev, "rxi", 0, s->intc.irqs[SCI1_RXI]);
 831    qdev_connect_gpio_out_named(dev, "txi", 0, s->intc.irqs[SCI1_TXI]);
 832    qdev_connect_gpio_out_named(dev, "tei", 0, s->intc.irqs[SCI1_TEI]);
 833
 834    /* SCIF */
 835    dev = qdev_new(TYPE_SH_SERIAL);
 836    dev->id = g_strdup("scif");
 837    qdev_prop_set_chr(dev, "chardev", serial_hd(1));
 838    qdev_prop_set_uint8(dev, "features", SH_SERIAL_FEAT_SCIF);
 839    sb = SYS_BUS_DEVICE(dev);
 840    sysbus_realize_and_unref(sb, &error_fatal);
 841    sysbus_mmio_map(sb, 0, 0xffe80000);
 842    alias = g_malloc(sizeof(*alias));
 843    mr = sysbus_mmio_get_region(sb, 0);
 844    memory_region_init_alias(alias, OBJECT(dev), "scif-a7", mr,
 845                             0, memory_region_size(mr));
 846    memory_region_add_subregion(sysmem, A7ADDR(0xffe80000), alias);
 847    qdev_connect_gpio_out_named(dev, "eri", 0, s->intc.irqs[SCIF_ERI]);
 848    qdev_connect_gpio_out_named(dev, "rxi", 0, s->intc.irqs[SCIF_RXI]);
 849    qdev_connect_gpio_out_named(dev, "txi", 0, s->intc.irqs[SCIF_TXI]);
 850    qdev_connect_gpio_out_named(dev, "bri", 0, s->intc.irqs[SCIF_BRI]);
 851
 852    tmu012_init(sysmem, 0x1fd80000,
 853                TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK,
 854                s->periph_freq,
 855                s->intc.irqs[TMU0],
 856                s->intc.irqs[TMU1],
 857                s->intc.irqs[TMU2_TUNI],
 858                s->intc.irqs[TMU2_TICPI]);
 859
 860    if (cpu->env.id & (SH_CPU_SH7750 | SH_CPU_SH7750S | SH_CPU_SH7751)) {
 861        sh_intc_register_sources(&s->intc,
 862                                 _INTC_ARRAY(vectors_dma4),
 863                                 _INTC_ARRAY(groups_dma4));
 864    }
 865
 866    if (cpu->env.id & (SH_CPU_SH7750R | SH_CPU_SH7751R)) {
 867        sh_intc_register_sources(&s->intc,
 868                                 _INTC_ARRAY(vectors_dma8),
 869                                 _INTC_ARRAY(groups_dma8));
 870    }
 871
 872    if (cpu->env.id & (SH_CPU_SH7750R | SH_CPU_SH7751 | SH_CPU_SH7751R)) {
 873        sh_intc_register_sources(&s->intc,
 874                                 _INTC_ARRAY(vectors_tmu34),
 875                                 NULL, 0);
 876        tmu012_init(sysmem, 0x1e100000, 0, s->periph_freq,
 877                    s->intc.irqs[TMU3],
 878                    s->intc.irqs[TMU4],
 879                    NULL, NULL);
 880    }
 881
 882    if (cpu->env.id & (SH_CPU_SH7751_ALL)) {
 883        sh_intc_register_sources(&s->intc,
 884                                 _INTC_ARRAY(vectors_pci),
 885                                 _INTC_ARRAY(groups_pci));
 886    }
 887
 888    if (cpu->env.id & (SH_CPU_SH7750S | SH_CPU_SH7750R | SH_CPU_SH7751_ALL)) {
 889        sh_intc_register_sources(&s->intc,
 890                                 _INTC_ARRAY(vectors_irlm),
 891                                 NULL, 0);
 892    }
 893
 894    sh_intc_register_sources(&s->intc,
 895                                _INTC_ARRAY(vectors_irl),
 896                                _INTC_ARRAY(groups_irl));
 897    return s;
 898}
 899
 900qemu_irq sh7750_irl(SH7750State *s)
 901{
 902    sh_intc_toggle_source(&s->intc.sources[IRL], 1, 0); /* enable */
 903    return qemu_allocate_irq(sh_intc_set_irl, &s->intc.sources[IRL], 0);
 904}
 905