--- trunk/src/devices/dev_sh4.c 2007/10/08 16:20:58 32 +++ trunk/src/devices/dev_sh4.c 2007/10/08 16:21:34 36 @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Anders Gavare. All rights reserved. + * Copyright (C) 2006-2007 Anders Gavare. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: @@ -25,9 +25,11 @@ * SUCH DAMAGE. * * - * $Id: dev_sh4.c,v 1.21 2006/11/02 05:43:44 debug Exp $ + * $Id: dev_sh4.c,v 1.32 2007/03/16 18:47:26 debug Exp $ * * SH4 processor specific memory mapped registers (0xf0000000 - 0xffffffff). + * + * TODO: Lots and lots of stuff. */ #include @@ -38,6 +40,7 @@ #include "cpu.h" #include "device.h" #include "devices.h" +#include "interrupt.h" #include "machine.h" #include "memory.h" #include "misc.h" @@ -45,9 +48,11 @@ #include "sh4_bscreg.h" #include "sh4_cache.h" +#include "sh4_dmacreg.h" #include "sh4_exception.h" #include "sh4_intcreg.h" #include "sh4_mmu.h" +#include "sh4_rtcreg.h" #include "sh4_scifreg.h" #include "sh4_tmureg.h" @@ -56,17 +61,53 @@ #define SH4_TICK_SHIFT 14 #define N_SH4_TIMERS 3 +/* General-purpose I/O stuff: */ +#define SH4_PCTRA 0xff80002c +#define SH4_PDTRA 0xff800030 +#define SH4_PCTRB 0xff800040 +#define SH4_PDTRB 0xff800044 +#define SH4_GPIOIC 0xff800048 + +#ifdef UNSTABLE_DEVEL +#define SH4_DEGUG /* #define debug fatal */ +#endif struct sh4_data { + /* SCIF (Serial controller): */ + uint16_t scif_smr; + uint8_t scif_brr; + uint16_t scif_scr; + uint16_t scif_ssr; + uint16_t scif_fcr; + int scif_delayed_tx; int scif_console_handle; + struct interrupt scif_tx_irq; + struct interrupt scif_rx_irq; /* Bus State Controller: */ - uint32_t unknown_2c; - uint32_t unknown_30; + uint32_t bsc_bcr1; + uint16_t bsc_bcr2; + uint32_t bsc_wcr1; + uint32_t bsc_wcr2; + uint32_t bsc_mcr; + uint16_t bsc_rtcsr; + uint16_t bsc_rtcor; + uint16_t bsc_rfcr; + + /* GPIO: */ + uint32_t pctra; /* Port Control Register A */ + uint32_t pdtra; /* Port Data Register A */ + uint32_t pctrb; /* Port Control Register B */ + uint32_t pdtrb; /* Port Data Register B */ + + /* SD-RAM: */ + uint16_t sdmr2; + uint16_t sdmr3; /* Timer Management Unit: */ struct timer *sh4_timer; + struct interrupt timer_irq[4]; uint32_t tocr; uint32_t tstr; uint32_t tcnt[N_SH4_TIMERS]; @@ -74,6 +115,10 @@ uint32_t tcr[N_SH4_TIMERS]; int timer_interrupts_pending[N_SH4_TIMERS]; double timer_hz[N_SH4_TIMERS]; + + /* RTC: */ + uint32_t rtc_reg[14]; /* Excluding rcr1 and 2 */ + uint8_t rtc_rcr1; }; @@ -86,12 +131,23 @@ * This function is called SH4_PSEUDO_TIMER_HZ times per real-world second. * Its job is to update the SH4 timer counters, and if necessary, increase * the number of pending interrupts. + * + * Also, RAM Refresh is also faked here. */ static void sh4_timer_tick(struct timer *t, void *extra) { struct sh4_data *d = (struct sh4_data *) extra; int i; + /* Fake RAM refresh: */ + d->bsc_rfcr ++; + if (d->bsc_rtcsr & (RTCSR_CMIE | RTCSR_OVIE)) { + fatal("sh4: RTCSR_CMIE | RTCSR_OVIE: TODO\n"); + /* TODO: Implement refresh interrupts etc. */ + exit(1); + } + + /* Timer interrupts: */ for (i=0; itcnt[i]; @@ -128,14 +184,45 @@ } +static void scif_reassert_interrupts(struct sh4_data *d) +{ + if (d->scif_scr & SCSCR2_RIE) { + if (d->scif_ssr & SCSSR2_DR) + INTERRUPT_ASSERT(d->scif_rx_irq); + } else { + INTERRUPT_DEASSERT(d->scif_rx_irq); + } + if (d->scif_scr & SCSCR2_TIE) { + if (d->scif_ssr & (SCSSR2_TDFE | SCSSR2_TEND)) + INTERRUPT_ASSERT(d->scif_tx_irq); + } else { + INTERRUPT_DEASSERT(d->scif_tx_irq); + } +} + + DEVICE_TICK(sh4) { struct sh4_data *d = (struct sh4_data *) extra; int i; + /* Serial controller interrupts: */ + /* TODO: Which bits go to which interrupt? */ + if (console_charavail(d->scif_console_handle)) + d->scif_ssr |= SCSSR2_DR; + else + d->scif_ssr &= SCSSR2_DR; + if (d->scif_delayed_tx) { + if (--d->scif_delayed_tx == 0) + d->scif_ssr |= SCSSR2_TDFE | SCSSR2_TEND; + } + + scif_reassert_interrupts(d); + + /* Timer interrupts: */ for (i=0; itimer_interrupts_pending[i] > 0) { - cpu_interrupt(cpu, SH_INTEVT_TMU0_TUNI0 + 0x20 * i); + INTERRUPT_ASSERT(d->timer_irq[i]); d->tcr[i] |= TCR_UNF; } } @@ -161,12 +248,18 @@ if (idata & SH4_ITLB_AA_V) cpu->cd.sh.itlb_lo[e] |= SH4_PTEL_V; - if (safe_to_invalidate) - cpu->invalidate_translation_caches(cpu, - old_hi & ~0xfff, INVALIDATE_VADDR); - else - cpu->invalidate_translation_caches(cpu, - 0, INVALIDATE_ALL); + /* Invalidate if this ITLB entry previously belonged to the + currently running process, or if it was shared: */ + if (cpu->cd.sh.ptel & SH4_PTEL_SH || + (old_hi & SH4_ITLB_AA_ASID_MASK) == + (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) { + if (safe_to_invalidate) + cpu->invalidate_translation_caches(cpu, + old_hi & ~0xfff, INVALIDATE_VADDR); + else + cpu->invalidate_translation_caches(cpu, + 0, INVALIDATE_ALL); + } } else { odata = cpu->cd.sh.itlb_hi[e] & (SH4_ITLB_AA_VPN_MASK | SH4_ITLB_AA_ASID_MASK); @@ -192,6 +285,7 @@ } if (writeflag == MEM_WRITE) { + uint32_t old_lo = cpu->cd.sh.itlb_lo[e]; int safe_to_invalidate = 0; if ((cpu->cd.sh.itlb_lo[e] & SH4_PTEL_SZ_MASK)==SH4_PTEL_SZ_4K) safe_to_invalidate = 1; @@ -200,12 +294,19 @@ cpu->cd.sh.itlb_lo[e] &= ~mask; cpu->cd.sh.itlb_lo[e] |= (idata & mask); - if (safe_to_invalidate) - cpu->invalidate_translation_caches(cpu, - cpu->cd.sh.itlb_hi[e] & ~0xfff, INVALIDATE_VADDR); - else - cpu->invalidate_translation_caches(cpu, - 0, INVALIDATE_ALL); + /* Invalidate if this ITLB entry belongs to the + currently running process, or if it was shared: */ + if (old_lo & SH4_PTEL_SH || + (cpu->cd.sh.itlb_hi[e] & SH4_ITLB_AA_ASID_MASK) == + (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) { + if (safe_to_invalidate) + cpu->invalidate_translation_caches(cpu, + cpu->cd.sh.itlb_hi[e] & ~0xfff, + INVALIDATE_VADDR); + else + cpu->invalidate_translation_caches(cpu, + 0, INVALIDATE_ALL); + } } else { odata = cpu->cd.sh.itlb_lo[e] & mask; memory_writemax64(cpu, data, len, odata); @@ -313,7 +414,8 @@ cpu->invalidate_translation_caches(cpu, vaddr_to_invalidate, INVALIDATE_VADDR); else - cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); + cpu->invalidate_translation_caches(cpu, 0, + INVALIDATE_ALL); } else { odata = cpu->cd.sh.utlb_hi[e] & (SH4_UTLB_AA_VPN_MASK | SH4_UTLB_AA_ASID_MASK); @@ -341,6 +443,7 @@ } if (writeflag == MEM_WRITE) { + uint32_t old_lo = cpu->cd.sh.utlb_lo[e]; int safe_to_invalidate = 0; if ((cpu->cd.sh.utlb_lo[e] & SH4_PTEL_SZ_MASK)==SH4_PTEL_SZ_4K) safe_to_invalidate = 1; @@ -349,12 +452,19 @@ cpu->cd.sh.utlb_lo[e] &= ~mask; cpu->cd.sh.utlb_lo[e] |= (idata & mask); - if (safe_to_invalidate) - cpu->invalidate_translation_caches(cpu, - cpu->cd.sh.utlb_hi[e] & ~0xfff, INVALIDATE_VADDR); - else - cpu->invalidate_translation_caches(cpu, - 0, INVALIDATE_ALL); + /* Invalidate if this UTLB entry belongs to the + currently running process, or if it was shared: */ + if (old_lo & SH4_PTEL_SH || + (cpu->cd.sh.utlb_hi[e] & SH4_ITLB_AA_ASID_MASK) == + (cpu->cd.sh.pteh & SH4_PTEH_ASID_MASK)) { + if (safe_to_invalidate) + cpu->invalidate_translation_caches(cpu, + cpu->cd.sh.utlb_hi[e] & ~0xfff, + INVALIDATE_VADDR); + else + cpu->invalidate_translation_caches(cpu, + 0, INVALIDATE_ALL); + } } else { odata = cpu->cd.sh.utlb_lo[e] & mask; memory_writemax64(cpu, data, len, odata); @@ -368,13 +478,27 @@ { struct sh4_data *d = (struct sh4_data *) extra; uint64_t idata = 0, odata = 0; - int timer_nr = 0; + int timer_nr = 0, dma_channel = 0; if (writeflag == MEM_WRITE) idata = memory_readmax64(cpu, data, len); relative_addr += SH4_REG_BASE; + /* SD-RAM access uses address only: */ + if (relative_addr >= 0xff900000 && relative_addr <= 0xff97ffff) { + /* Possibly not 100% correct... TODO */ + int v = (relative_addr >> 2) & 0xffff; + if (relative_addr & 0x00040000) + d->sdmr3 = v; + else + d->sdmr2 = v; + debug("[ sh4: sdmr%i set to 0x%04"PRIx16" ]\n", + relative_addr & 0x00040000? 3 : 2, v); + return 1; + } + + switch (relative_addr) { /*************************************************/ @@ -395,7 +519,11 @@ cpu->cd.sh.pteh = idata; if ((idata & SH4_PTEH_ASID_MASK) != old_asid) { - /* TODO: Don't invalidate everything? */ + /* + * TODO: Don't invalidate everything, + * only those pages that belonged to the + * old asid. + */ cpu->invalidate_translation_caches( cpu, 0, INVALIDATE_ALL); } @@ -436,9 +564,15 @@ } else { if (idata & SH4_MMUCR_TI) { /* TLB invalidate. */ + int i; + for (i = 0; i < SH_N_ITLB_ENTRIES; i++) + cpu->cd.sh.itlb_lo[i] &= + ~SH4_PTEL_V; + + for (i = 0; i < SH_N_UTLB_ENTRIES; i++) + cpu->cd.sh.utlb_lo[i] &= + ~SH4_PTEL_V; - /* TODO: Only invalidate something specific? - And not everything? */ cpu->invalidate_translation_caches(cpu, 0, INVALIDATE_ALL); @@ -606,8 +740,7 @@ } if (d->tcr[timer_nr] & TCR_UNF && !(idata & TCR_UNF)) { - cpu_interrupt_ack(cpu, SH_INTEVT_TMU0_TUNI0 - + 0x20 * timer_nr); + INTERRUPT_DEASSERT(d->timer_irq[timer_nr]); if (d->timer_interrupts_pending[timer_nr] > 0) d->timer_interrupts_pending[timer_nr]--; } @@ -618,45 +751,200 @@ /*************************************************/ + /* DMAC: DMA Controller */ + + case SH4_SAR3: + dma_channel ++; + case SH4_SAR2: + dma_channel ++; + case SH4_SAR1: + dma_channel ++; + case SH4_SAR0: + dma_channel ++; + if (writeflag == MEM_READ) + odata = cpu->cd.sh.dmac_sar[dma_channel]; + else + cpu->cd.sh.dmac_sar[dma_channel] = idata; + break; + + case SH4_DAR3: + dma_channel ++; + case SH4_DAR2: + dma_channel ++; + case SH4_DAR1: + dma_channel ++; + case SH4_DAR0: + dma_channel ++; + if (writeflag == MEM_READ) + odata = cpu->cd.sh.dmac_dar[dma_channel]; + else + cpu->cd.sh.dmac_dar[dma_channel] = idata; + break; + + case SH4_DMATCR3: + dma_channel ++; + case SH4_DMATCR2: + dma_channel ++; + case SH4_DMATCR1: + dma_channel ++; + case SH4_DMATCR0: + dma_channel ++; + if (writeflag == MEM_READ) + odata = cpu->cd.sh.dmac_tcr[dma_channel] & 0x00ffffff; + else { + if (idata & ~0x00ffffff) { + fatal("[ SH4 DMA: Attempt to set top 8 " + "bits of the count register? 0x%08" + PRIx32" ]\n", (uint32_t) idata); + exit(1); + } + + /* Special case: writing 0 to the count register + means 16777216: */ + if (idata == 0) + idata = 0x01000000; + cpu->cd.sh.dmac_tcr[dma_channel] = idata; + } + break; + + case SH4_CHCR3: + dma_channel ++; + case SH4_CHCR2: + dma_channel ++; + case SH4_CHCR1: + dma_channel ++; + case SH4_CHCR0: + dma_channel ++; + if (writeflag == MEM_READ) + odata = cpu->cd.sh.dmac_chcr[dma_channel]; + else { + /* IP.BIN sets this to 0x12c0, and I want to know if + some other guest OS uses other values. */ + if (idata != 0x12c0) { + fatal("[ SH4 DMA: Attempt to set chcr " + "to 0x%08"PRIx32" ]\n", (uint32_t) idata); + exit(1); + } + + cpu->cd.sh.dmac_chcr[dma_channel] = idata; + } + break; + + + /*************************************************/ /* BSC: Bus State Controller */ - case SH4_RFCR: - /* TODO */ - fatal("[ SH4_RFCR: TODO ]\n"); - odata = 0x11; + case SH4_BCR1: + if (writeflag == MEM_WRITE) + d->bsc_bcr1 = idata & 0x033efffd; + else { + odata = d->bsc_bcr1; + if (cpu->byte_order == EMUL_LITTLE_ENDIAN) + odata |= BCR1_LITTLE_ENDIAN; + } + break; + + case SH4_BCR2: + if (len != sizeof(uint16_t)) { + fatal("Non-16-bit SH4_BCR2 access?\n"); + exit(1); + } + if (writeflag == MEM_WRITE) + d->bsc_bcr2 = idata & 0x3ffd; + else + odata = d->bsc_bcr2; + break; + + case SH4_WCR1: + if (writeflag == MEM_WRITE) + d->bsc_wcr1 = idata & 0x77777777; + else + odata = d->bsc_wcr1; + break; + + case SH4_WCR2: + if (writeflag == MEM_WRITE) + d->bsc_wcr2 = idata & 0xfffeefff; + else + odata = d->bsc_wcr2; + break; + + case SH4_MCR: + if (writeflag == MEM_WRITE) + d->bsc_mcr = idata & 0xf8bbffff; + else + odata = d->bsc_mcr; break; -#if 0 - case SH4_UNKNOWN_2C: - /* Not really part of the BSC? The 2C and 30 registers - have to do with I/O pins... TODO */ + case SH4_RTCSR: /* - * TODO: Perhaps this isn't actually part of the Bus State - * controller? Marcus Comstedt's video.s tutorial on - * how to output video on the Dreamcast indicates that - * this is a way to sense which video cable is - * connected. + * Refresh Time Control/Status Register. Called RTCSR in + * NetBSD, but RTSCR in the SH7750 manual? */ if (writeflag == MEM_WRITE) { - d->unknown_2c = idata; - d->unknown_30 = idata; + idata &= 0x00ff; + if (idata & RTCSR_CMF) { + idata = (idata & ~RTCSR_CMF) + | (d->bsc_rtcsr & RTCSR_CMF); + } + d->bsc_rtcsr = idata & 0x00ff; } else - odata = d->unknown_2c; + odata = d->bsc_rtcsr; break; -#endif -#if 1 - case SH4_UNKNOWN_30: + case SH4_RTCOR: + /* Refresh Time Constant Register (8 bits): */ if (writeflag == MEM_WRITE) - d->unknown_30 = idata; - else { - odata = d->unknown_30; + d->bsc_rtcor = idata & 0x00ff; + else + odata = d->bsc_rtcor & 0x00ff; + break; + + case SH4_RFCR: + /* Refresh Count Register (10 bits): */ + if (writeflag == MEM_WRITE) + d->bsc_rfcr = idata & 0x03ff; + else + odata = d->bsc_rfcr & 0x03ff; + break; + + + /*******************************************/ + /* GPIO: General-purpose I/O controller */ + + case SH4_PCTRA: + if (writeflag == MEM_WRITE) + d->pctra = idata; + else + odata = d->pctra; + break; - /* SUPER-UGLY HACK! TODO */ - d->unknown_30 ++; + case SH4_PDTRA: + if (writeflag == MEM_WRITE) { + debug("[ sh4: pdtra: write: TODO ]\n"); + d->pdtra = idata; + } else { + debug("[ sh4: pdtra: read: TODO ]\n"); + odata = d->pdtra; + } + break; + + case SH4_PCTRB: + if (writeflag == MEM_WRITE) + d->pctrb = idata; + else + odata = d->pctrb; + break; + + case SH4_PDTRB: + if (writeflag == MEM_WRITE) { + debug("[ sh4: pdtrb: write: TODO ]\n"); + d->pdtrb = idata; + } else { + debug("[ sh4: pdtrb: read: TODO ]\n"); + odata = d->pdtrb; } break; -#endif /*********************************/ @@ -693,20 +981,56 @@ cpu->cd.sh.intc_iprc = idata; break; + case SH4_IPRD: + if (writeflag == MEM_READ) + odata = cpu->cd.sh.intc_iprd; + else + cpu->cd.sh.intc_iprd = idata; + break; + /*************************************************/ /* SCIF: Serial Controller Interface with FIFO */ + case SH4_SCIF_BASE + SCIF_SMR: + if (writeflag == MEM_WRITE) { + d->scif_smr = idata; + } else { + odata = d->scif_smr; + } + break; + + case SH4_SCIF_BASE + SCIF_BRR: + if (writeflag == MEM_WRITE) { + d->scif_brr = idata; + } else { + odata = d->scif_brr; + } + break; + + case SH4_SCIF_BASE + SCIF_SCR: + if (writeflag == MEM_WRITE) { + d->scif_scr = idata; + scif_reassert_interrupts(d); + } else { + odata = d->scif_scr; + } + break; + case SH4_SCIF_BASE + SCIF_FTDR: - if (writeflag == MEM_WRITE) + if (writeflag == MEM_WRITE) { console_putchar(d->scif_console_handle, idata); + d->scif_delayed_tx = 1; + } break; case SH4_SCIF_BASE + SCIF_SSR: - /* TODO: Implement more of this. */ - odata = SCSSR2_TDFE | SCSSR2_TEND; - if (console_charavail(d->scif_console_handle)) - odata |= SCSSR2_DR; + if (writeflag == MEM_READ) { + odata = d->scif_ssr; + } else { + d->scif_ssr &= ~idata; + scif_reassert_interrupts(d); + } break; case SH4_SCIF_BASE + SCIF_FRDR: @@ -715,6 +1039,15 @@ if (x == 13) x = 10; odata = x < 0? 0 : x; + d->scif_ssr &= ~SCSSR2_DR; + } + break; + + case SH4_SCIF_BASE + SCIF_FCR: + if (writeflag == MEM_WRITE) { + d->scif_fcr = idata; + } else { + odata = d->scif_fcr; } break; @@ -722,6 +1055,43 @@ odata = console_charavail(d->scif_console_handle); break; + + /*************************************************/ + + case SH4_RSECCNT: + case SH4_RMINCNT: + case SH4_RHRCNT: + case SH4_RWKCNT: + case SH4_RDAYCNT: + case SH4_RMONCNT: + case SH4_RYRCNT: + case SH4_RSECAR: + case SH4_RMINAR: + case SH4_RHRAR: + case SH4_RWKAR: + case SH4_RDAYAR: + case SH4_RMONAR: + if (writeflag == MEM_WRITE) { + d->rtc_reg[(relative_addr - 0xffc80000) / 4] = idata; + } else { + /* TODO: Update rtc_reg based on host's date/time. */ + odata = d->rtc_reg[(relative_addr - 0xffc80000) / 4]; + } + break; + + case SH4_RCR1: + if (writeflag == MEM_READ) + odata = d->rtc_rcr1; + else { + d->rtc_rcr1 = idata; + if (idata & 0x18) { + fatal("SH4: TODO: RTC interrupt enable\n"); + exit(1); + } + } + break; + + /*************************************************/ default:if (writeflag == MEM_READ) { @@ -731,6 +1101,9 @@ fatal("[ sh4: write to addr 0x%x: 0x%x ]\n", (int)relative_addr, (int)idata); } +#ifdef SH4_DEGUG +// exit(1); +#endif } if (writeflag == MEM_READ) @@ -742,6 +1115,7 @@ DEVINIT(sh4) { + char tmp[200]; struct machine *machine = devinit->machine; struct sh4_data *d = malloc(sizeof(struct sh4_data)); if (d == NULL) { @@ -753,6 +1127,13 @@ d->scif_console_handle = console_start_slave(devinit->machine, "SH4 SCIF", 1); + snprintf(tmp, sizeof(tmp), "%s.irq[0x%x]", + devinit->interrupt_path, SH4_INTEVT_SCIF_RXI); + INTERRUPT_CONNECT(tmp, d->scif_rx_irq); + snprintf(tmp, sizeof(tmp), "%s.irq[0x%x]", + devinit->interrupt_path, SH4_INTEVT_SCIF_TXI); + INTERRUPT_CONNECT(tmp, d->scif_tx_irq); + memory_device_register(machine->memory, devinit->name, SH4_REG_BASE, 0x01000000, dev_sh4_access, d, DM_DEFAULT, NULL); @@ -770,10 +1151,10 @@ * * TODO: Implement more correct cache behaviour? */ - dev_ram_init(machine, SH4_CCIA, SH4_ICACHE_SIZE, DEV_RAM_RAM, 0x0); - dev_ram_init(machine, SH4_CCID, SH4_ICACHE_SIZE, DEV_RAM_RAM, 0x0); - dev_ram_init(machine, SH4_CCDA, SH4_DCACHE_SIZE, DEV_RAM_RAM, 0x0); - dev_ram_init(machine, SH4_CCDD, SH4_DCACHE_SIZE, DEV_RAM_RAM, 0x0); + dev_ram_init(machine, SH4_CCIA, SH4_ICACHE_SIZE * 2, DEV_RAM_RAM, 0x0); + dev_ram_init(machine, SH4_CCID, SH4_ICACHE_SIZE, DEV_RAM_RAM, 0x0); + dev_ram_init(machine, SH4_CCDA, SH4_DCACHE_SIZE * 2, DEV_RAM_RAM, 0x0); + dev_ram_init(machine, SH4_CCDD, SH4_DCACHE_SIZE, DEV_RAM_RAM, 0x0); /* 0xf2000000 SH4_ITLB_AA */ memory_device_register(machine->memory, devinit->name, SH4_ITLB_AA, @@ -800,6 +1181,30 @@ d->tcor[1] = 0xffffffff; d->tcnt[1] = 0xffffffff; d->tcor[2] = 0xffffffff; d->tcnt[2] = 0xffffffff; + snprintf(tmp, sizeof(tmp), "emul[0].machine[0].cpu[0].irq[0x%x]", + SH_INTEVT_TMU0_TUNI0); + if (!interrupt_handler_lookup(tmp, &d->timer_irq[0])) { + fatal("Could not find interrupt '%s'.\n", tmp); + exit(1); + } + snprintf(tmp, sizeof(tmp), "emul[0].machine[0].cpu[0].irq[0x%x]", + SH_INTEVT_TMU1_TUNI1); + if (!interrupt_handler_lookup(tmp, &d->timer_irq[1])) { + fatal("Could not find interrupt '%s'.\n", tmp); + exit(1); + } + snprintf(tmp, sizeof(tmp), "emul[0].machine[0].cpu[0].irq[0x%x]", + SH_INTEVT_TMU2_TUNI2); + if (!interrupt_handler_lookup(tmp, &d->timer_irq[2])) { + fatal("Could not find interrupt '%s'.\n", tmp); + exit(1); + } + + /* Bus State Controller initial values: */ + d->bsc_bcr2 = 0x3ffc; + d->bsc_wcr1 = 0x77777777; + d->bsc_wcr2 = 0xfffeefff; + return 1; }