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