Commit cd1a3f6840e9f4b57860ee0d151347e6ade73d11
1 parent
0d78f544
Stand-alone TMU emulation code, by Magnus Damm.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@3269 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
6 changed files
with
336 additions
and
196 deletions
Makefile.target
| ... | ... | @@ -476,6 +476,7 @@ CPPFLAGS += -DHAS_AUDIO |
| 476 | 476 | endif |
| 477 | 477 | ifeq ($(TARGET_BASE_ARCH), sh4) |
| 478 | 478 | VL_OBJS+= shix.o r2d.o sh7750.o sh7750_regnames.o tc58128.o |
| 479 | +VL_OBJS+= sh_timer.o ptimer.o | |
| 479 | 480 | endif |
| 480 | 481 | ifeq ($(TARGET_BASE_ARCH), m68k) |
| 481 | 482 | VL_OBJS+= an5206.o mcf5206.o ptimer.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o | ... | ... |
hw/sh7750.c
| ... | ... | @@ -64,13 +64,6 @@ typedef struct SH7750State { |
| 64 | 64 | uint8_t scbrr2; |
| 65 | 65 | fifo serial2_receive_fifo; |
| 66 | 66 | fifo serial2_transmit_fifo; |
| 67 | - /* Timers */ | |
| 68 | - uint8_t tstr; | |
| 69 | - /* Timer 0 */ | |
| 70 | - QEMUTimer *timer0; | |
| 71 | - uint16_t tcr0; | |
| 72 | - uint32_t tcor0; | |
| 73 | - uint32_t tcnt0; | |
| 74 | 67 | /* IO ports */ |
| 75 | 68 | uint16_t gpioic; |
| 76 | 69 | uint32_t pctra; |
| ... | ... | @@ -88,83 +81,8 @@ typedef struct SH7750State { |
| 88 | 81 | sh7750_io_device *devices[NB_DEVICES]; /* External peripherals */ |
| 89 | 82 | /* Cache */ |
| 90 | 83 | uint32_t ccr; |
| 91 | -} SH7750State; | |
| 92 | - | |
| 93 | -/********************************************************************** | |
| 94 | - Timers | |
| 95 | -**********************************************************************/ | |
| 96 | - | |
| 97 | -/* XXXXX At this time, timer0 works in underflow only mode, that is | |
| 98 | - the value of tcnt0 is read at alarm computation time and cannot | |
| 99 | - be read back by the guest OS */ | |
| 100 | - | |
| 101 | -static void start_timer0(SH7750State * s) | |
| 102 | -{ | |
| 103 | - uint64_t now, next, prescaler; | |
| 104 | - | |
| 105 | - if ((s->tcr0 & 6) == 6) { | |
| 106 | - fprintf(stderr, "rtc clock for timer 0 not supported\n"); | |
| 107 | - assert(0); | |
| 108 | - } | |
| 109 | 84 | |
| 110 | - if ((s->tcr0 & 7) == 5) { | |
| 111 | - fprintf(stderr, "timer 0 configuration not supported\n"); | |
| 112 | - assert(0); | |
| 113 | - } | |
| 114 | - | |
| 115 | - if ((s->tcr0 & 4) == 4) | |
| 116 | - prescaler = 1024; | |
| 117 | - else | |
| 118 | - prescaler = 4 << (s->tcr0 & 3); | |
| 119 | - | |
| 120 | - now = qemu_get_clock(vm_clock); | |
| 121 | - /* XXXXX */ | |
| 122 | - next = | |
| 123 | - now + muldiv64(prescaler * s->tcnt0, ticks_per_sec, | |
| 124 | - s->periph_freq); | |
| 125 | - if (next == now) | |
| 126 | - next = now + 1; | |
| 127 | - fprintf(stderr, "now=%016" PRIx64 ", next=%016" PRIx64 "\n", now, next); | |
| 128 | - fprintf(stderr, "timer will underflow in %f seconds\n", | |
| 129 | - (float) (next - now) / (float) ticks_per_sec); | |
| 130 | - | |
| 131 | - qemu_mod_timer(s->timer0, next); | |
| 132 | -} | |
| 133 | - | |
| 134 | -static void timer_start_changed(SH7750State * s) | |
| 135 | -{ | |
| 136 | - if (s->tstr & SH7750_TSTR_STR0) { | |
| 137 | - start_timer0(s); | |
| 138 | - } else { | |
| 139 | - fprintf(stderr, "timer 0 is stopped\n"); | |
| 140 | - qemu_del_timer(s->timer0); | |
| 141 | - } | |
| 142 | -} | |
| 143 | - | |
| 144 | -static void timer0_cb(void *opaque) | |
| 145 | -{ | |
| 146 | - SH7750State *s = opaque; | |
| 147 | - | |
| 148 | - s->tcnt0 = (uint32_t) 0; /* XXXXX */ | |
| 149 | - if (--s->tcnt0 == (uint32_t) - 1) { | |
| 150 | - fprintf(stderr, "timer 0 underflow\n"); | |
| 151 | - s->tcnt0 = s->tcor0; | |
| 152 | - s->tcr0 |= SH7750_TCR_UNF; | |
| 153 | - if (s->tcr0 & SH7750_TCR_UNIE) { | |
| 154 | - fprintf(stderr, | |
| 155 | - "interrupt generation for timer 0 not supported\n"); | |
| 156 | - assert(0); | |
| 157 | - } | |
| 158 | - } | |
| 159 | - start_timer0(s); | |
| 160 | -} | |
| 161 | - | |
| 162 | -static void init_timers(SH7750State * s) | |
| 163 | -{ | |
| 164 | - s->tcor0 = 0xffffffff; | |
| 165 | - s->tcnt0 = 0xffffffff; | |
| 166 | - s->timer0 = qemu_new_timer(vm_clock, &timer0_cb, s); | |
| 167 | -} | |
| 85 | +} SH7750State; | |
| 168 | 86 | |
| 169 | 87 | /********************************************************************** |
| 170 | 88 | First serial port |
| ... | ... | @@ -581,8 +499,6 @@ static uint32_t sh7750_mem_readw(void *opaque, target_phys_addr_t addr) |
| 581 | 499 | fprintf(stderr, |
| 582 | 500 | "Read access to refresh count register, incrementing\n"); |
| 583 | 501 | return s->rfcr++; |
| 584 | - case SH7750_TCR0_A7: | |
| 585 | - return s->tcr0; | |
| 586 | 502 | case SH7750_SCLSR2_A7: |
| 587 | 503 | /* Read and clear overflow bit */ |
| 588 | 504 | r = s->sclsr2; |
| ... | ... | @@ -649,10 +565,6 @@ static void sh7750_mem_writeb(void *opaque, target_phys_addr_t addr, |
| 649 | 565 | case SH7750_SCBRR2_A7: |
| 650 | 566 | s->scbrr2 = mem_value; |
| 651 | 567 | return; |
| 652 | - case SH7750_TSTR_A7: | |
| 653 | - s->tstr = mem_value; | |
| 654 | - timer_start_changed(s); | |
| 655 | - return; | |
| 656 | 568 | case SH7750_SCSCR1_A7: |
| 657 | 569 | s->scscr1 = mem_value; |
| 658 | 570 | scscr1_changed(s); |
| ... | ... | @@ -721,9 +633,6 @@ static void sh7750_mem_writew(void *opaque, target_phys_addr_t addr, |
| 721 | 633 | case SH7750_SCSMR2_A7: |
| 722 | 634 | s->scsmr2 = mem_value; |
| 723 | 635 | return; |
| 724 | - case SH7750_TCR0_A7: | |
| 725 | - s->tcr0 = mem_value; | |
| 726 | - return; | |
| 727 | 636 | case SH7750_GPIOIC_A7: |
| 728 | 637 | s->gpioic = mem_value; |
| 729 | 638 | if (mem_value != 0) { |
| ... | ... | @@ -768,9 +677,6 @@ static void sh7750_mem_writel(void *opaque, target_phys_addr_t addr, |
| 768 | 677 | s->portpullupb = portpullup(mem_value); |
| 769 | 678 | portb_changed(s, temp); |
| 770 | 679 | return; |
| 771 | - case SH7750_TCNT0_A7: | |
| 772 | - s->tcnt0 = mem_value & 0xf; | |
| 773 | - return; | |
| 774 | 680 | case SH7750_MMUCR_A7: |
| 775 | 681 | s->cpu->mmucr = mem_value; |
| 776 | 682 | return; |
| ... | ... | @@ -828,7 +734,11 @@ SH7750State *sh7750_init(CPUSH4State * cpu) |
| 828 | 734 | sh7750_mem_read, |
| 829 | 735 | sh7750_mem_write, s); |
| 830 | 736 | cpu_register_physical_memory(0x1c000000, 0x04000000, sh7750_io_memory); |
| 831 | - init_timers(s); | |
| 832 | 737 | init_serial_ports(s); |
| 738 | + | |
| 739 | + tmu012_init(0x1fd80000, | |
| 740 | + TMU012_FEAT_TOCR | TMU012_FEAT_3CHAN | TMU012_FEAT_EXTCLK, | |
| 741 | + s->periph_freq); | |
| 742 | + tmu012_init(0x1e100000, 0, s->periph_freq); | |
| 833 | 743 | return s; |
| 834 | 744 | } | ... | ... |
hw/sh7750_regnames.c
| ... | ... | @@ -42,18 +42,6 @@ static regname_t regnames[] = { |
| 42 | 42 | REGNAME(SH7750_RMONAR_A7) |
| 43 | 43 | REGNAME(SH7750_RCR1_A7) |
| 44 | 44 | REGNAME(SH7750_RCR2_A7) |
| 45 | - REGNAME(SH7750_TOCR_A7) | |
| 46 | - REGNAME(SH7750_TSTR_A7) | |
| 47 | - REGNAME(SH7750_TCOR0_A7) | |
| 48 | - REGNAME(SH7750_TCOR1_A7) | |
| 49 | - REGNAME(SH7750_TCOR2_A7) | |
| 50 | - REGNAME(SH7750_TCNT0_A7) | |
| 51 | - REGNAME(SH7750_TCNT1_A7) | |
| 52 | - REGNAME(SH7750_TCNT2_A7) | |
| 53 | - REGNAME(SH7750_TCR0_A7) | |
| 54 | - REGNAME(SH7750_TCR1_A7) | |
| 55 | - REGNAME(SH7750_TCR2_A7) | |
| 56 | - REGNAME(SH7750_TCPR2_A7) | |
| 57 | 45 | REGNAME(SH7750_BCR1_A7) |
| 58 | 46 | REGNAME(SH7750_BCR2_A7) |
| 59 | 47 | REGNAME(SH7750_WCR1_A7) | ... | ... |
hw/sh7750_regs.h
| ... | ... | @@ -524,94 +524,6 @@ |
| 524 | 524 | year counters are stopped |
| 525 | 525 | 1 - sec, min, hr, day-of-week, month, |
| 526 | 526 | year counters operate normally */ |
| 527 | - | |
| 528 | - | |
| 529 | -/* | |
| 530 | - * Timer Unit (TMU) | |
| 531 | - */ | |
| 532 | -/* Timer Output Control Register (byte) - TOCR */ | |
| 533 | -#define SH7750_TOCR_REGOFS 0xD80000 /* offset */ | |
| 534 | -#define SH7750_TOCR SH7750_P4_REG32(SH7750_TOCR_REGOFS) | |
| 535 | -#define SH7750_TOCR_A7 SH7750_A7_REG32(SH7750_TOCR_REGOFS) | |
| 536 | -#define SH7750_TOCR_TCOE 0x01 /* Timer Clock Pin Control: | |
| 537 | - 0 - TCLK is used as external clock | |
| 538 | - input or input capture control | |
| 539 | - 1 - TCLK is used as on-chip RTC | |
| 540 | - output clock pin */ | |
| 541 | - | |
| 542 | -/* Timer Start Register (byte) - TSTR */ | |
| 543 | -#define SH7750_TSTR_REGOFS 0xD80004 /* offset */ | |
| 544 | -#define SH7750_TSTR SH7750_P4_REG32(SH7750_TSTR_REGOFS) | |
| 545 | -#define SH7750_TSTR_A7 SH7750_A7_REG32(SH7750_TSTR_REGOFS) | |
| 546 | -#define SH7750_TSTR_STR2 0x04 /* TCNT2 performs count operations */ | |
| 547 | -#define SH7750_TSTR_STR1 0x02 /* TCNT1 performs count operations */ | |
| 548 | -#define SH7750_TSTR_STR0 0x01 /* TCNT0 performs count operations */ | |
| 549 | -#define SH7750_TSTR_STR(n) (1 << (n)) | |
| 550 | - | |
| 551 | -/* Timer Constant Register - TCOR0, TCOR1, TCOR2 */ | |
| 552 | -#define SH7750_TCOR_REGOFS(n) (0xD80008 + ((n)*12)) /* offset */ | |
| 553 | -#define SH7750_TCOR(n) SH7750_P4_REG32(SH7750_TCOR_REGOFS(n)) | |
| 554 | -#define SH7750_TCOR_A7(n) SH7750_A7_REG32(SH7750_TCOR_REGOFS(n)) | |
| 555 | -#define SH7750_TCOR0 SH7750_TCOR(0) | |
| 556 | -#define SH7750_TCOR1 SH7750_TCOR(1) | |
| 557 | -#define SH7750_TCOR2 SH7750_TCOR(2) | |
| 558 | -#define SH7750_TCOR0_A7 SH7750_TCOR_A7(0) | |
| 559 | -#define SH7750_TCOR1_A7 SH7750_TCOR_A7(1) | |
| 560 | -#define SH7750_TCOR2_A7 SH7750_TCOR_A7(2) | |
| 561 | - | |
| 562 | -/* Timer Counter Register - TCNT0, TCNT1, TCNT2 */ | |
| 563 | -#define SH7750_TCNT_REGOFS(n) (0xD8000C + ((n)*12)) /* offset */ | |
| 564 | -#define SH7750_TCNT(n) SH7750_P4_REG32(SH7750_TCNT_REGOFS(n)) | |
| 565 | -#define SH7750_TCNT_A7(n) SH7750_A7_REG32(SH7750_TCNT_REGOFS(n)) | |
| 566 | -#define SH7750_TCNT0 SH7750_TCNT(0) | |
| 567 | -#define SH7750_TCNT1 SH7750_TCNT(1) | |
| 568 | -#define SH7750_TCNT2 SH7750_TCNT(2) | |
| 569 | -#define SH7750_TCNT0_A7 SH7750_TCNT_A7(0) | |
| 570 | -#define SH7750_TCNT1_A7 SH7750_TCNT_A7(1) | |
| 571 | -#define SH7750_TCNT2_A7 SH7750_TCNT_A7(2) | |
| 572 | - | |
| 573 | -/* Timer Control Register (half) - TCR0, TCR1, TCR2 */ | |
| 574 | -#define SH7750_TCR_REGOFS(n) (0xD80010 + ((n)*12)) /* offset */ | |
| 575 | -#define SH7750_TCR(n) SH7750_P4_REG32(SH7750_TCR_REGOFS(n)) | |
| 576 | -#define SH7750_TCR_A7(n) SH7750_A7_REG32(SH7750_TCR_REGOFS(n)) | |
| 577 | -#define SH7750_TCR0 SH7750_TCR(0) | |
| 578 | -#define SH7750_TCR1 SH7750_TCR(1) | |
| 579 | -#define SH7750_TCR2 SH7750_TCR(2) | |
| 580 | -#define SH7750_TCR0_A7 SH7750_TCR_A7(0) | |
| 581 | -#define SH7750_TCR1_A7 SH7750_TCR_A7(1) | |
| 582 | -#define SH7750_TCR2_A7 SH7750_TCR_A7(2) | |
| 583 | - | |
| 584 | -#define SH7750_TCR2_ICPF 0x200 /* Input Capture Interrupt Flag | |
| 585 | - (1 - input capture has occured) */ | |
| 586 | -#define SH7750_TCR_UNF 0x100 /* Underflow flag */ | |
| 587 | -#define SH7750_TCR2_ICPE 0x0C0 /* Input Capture Control: */ | |
| 588 | -#define SH7750_TCR2_ICPE_DIS 0x000 /* Input Capture function is not used */ | |
| 589 | -#define SH7750_TCR2_ICPE_NOINT 0x080 /* Input Capture function is used, but | |
| 590 | - input capture interrupt is not | |
| 591 | - enabled */ | |
| 592 | -#define SH7750_TCR2_ICPE_INT 0x0C0 /* Input Capture function is used, | |
| 593 | - input capture interrupt enabled */ | |
| 594 | -#define SH7750_TCR_UNIE 0x020 /* Underflow Interrupt Control | |
| 595 | - (1 - underflow interrupt enabled) */ | |
| 596 | -#define SH7750_TCR_CKEG 0x018 /* Clock Edge selection: */ | |
| 597 | -#define SH7750_TCR_CKEG_RAISE 0x000 /* Count/capture on rising edge */ | |
| 598 | -#define SH7750_TCR_CKEG_FALL 0x008 /* Count/capture on falling edge */ | |
| 599 | -#define SH7750_TCR_CKEG_BOTH 0x018 /* Count/capture on both rising and | |
| 600 | - falling edges */ | |
| 601 | -#define SH7750_TCR_TPSC 0x007 /* Timer prescaler */ | |
| 602 | -#define SH7750_TCR_TPSC_DIV4 0x000 /* Counts on peripheral clock/4 */ | |
| 603 | -#define SH7750_TCR_TPSC_DIV16 0x001 /* Counts on peripheral clock/16 */ | |
| 604 | -#define SH7750_TCR_TPSC_DIV64 0x002 /* Counts on peripheral clock/64 */ | |
| 605 | -#define SH7750_TCR_TPSC_DIV256 0x003 /* Counts on peripheral clock/256 */ | |
| 606 | -#define SH7750_TCR_TPSC_DIV1024 0x004 /* Counts on peripheral clock/1024 */ | |
| 607 | -#define SH7750_TCR_TPSC_RTC 0x006 /* Counts on on-chip RTC output clk */ | |
| 608 | -#define SH7750_TCR_TPSC_EXT 0x007 /* Counts on external clock */ | |
| 609 | - | |
| 610 | -/* Input Capture Register (read-only) - TCPR2 */ | |
| 611 | -#define SH7750_TCPR2_REGOFS 0xD8002C /* offset */ | |
| 612 | -#define SH7750_TCPR2 SH7750_P4_REG32(SH7750_TCPR2_REGOFS) | |
| 613 | -#define SH7750_TCPR2_A7 SH7750_A7_REG32(SH7750_TCPR2_REGOFS) | |
| 614 | - | |
| 615 | 527 | /* |
| 616 | 528 | * Bus State Controller - BSC |
| 617 | 529 | */ | ... | ... |
hw/sh_timer.c
0 โ 100644
| 1 | +/* | |
| 2 | + * SuperH Timer modules. | |
| 3 | + * | |
| 4 | + * Copyright (c) 2007 Magnus Damm | |
| 5 | + * Based on arm_timer.c by Paul Brook | |
| 6 | + * Copyright (c) 2005-2006 CodeSourcery. | |
| 7 | + * | |
| 8 | + * This code is licenced under the GPL. | |
| 9 | + */ | |
| 10 | + | |
| 11 | +#include "vl.h" | |
| 12 | + | |
| 13 | +//#define DEBUG_TIMER | |
| 14 | + | |
| 15 | +#define TIMER_TCR_TPSC (7 << 0) | |
| 16 | +#define TIMER_TCR_CKEG (3 << 3) | |
| 17 | +#define TIMER_TCR_UNIE (1 << 5) | |
| 18 | +#define TIMER_TCR_ICPE (3 << 6) | |
| 19 | +#define TIMER_TCR_UNF (1 << 8) | |
| 20 | +#define TIMER_TCR_ICPF (1 << 9) | |
| 21 | +#define TIMER_TCR_RESERVED (0x3f << 10) | |
| 22 | + | |
| 23 | +#define TIMER_FEAT_CAPT (1 << 0) | |
| 24 | +#define TIMER_FEAT_EXTCLK (1 << 1) | |
| 25 | + | |
| 26 | +typedef struct { | |
| 27 | + ptimer_state *timer; | |
| 28 | + uint32_t tcnt; | |
| 29 | + uint32_t tcor; | |
| 30 | + uint32_t tcr; | |
| 31 | + uint32_t tcpr; | |
| 32 | + int freq; | |
| 33 | + int int_level; | |
| 34 | + int feat; | |
| 35 | + int enabled; | |
| 36 | + qemu_irq irq; | |
| 37 | +} sh_timer_state; | |
| 38 | + | |
| 39 | +/* Check all active timers, and schedule the next timer interrupt. */ | |
| 40 | + | |
| 41 | +static void sh_timer_update(sh_timer_state *s) | |
| 42 | +{ | |
| 43 | +#if 0 /* not yet */ | |
| 44 | + /* Update interrupts. */ | |
| 45 | + if (s->int_level && (s->tcr & TIMER_TCR_UNIE)) { | |
| 46 | + qemu_irq_raise(s->irq); | |
| 47 | + } else { | |
| 48 | + qemu_irq_lower(s->irq); | |
| 49 | + } | |
| 50 | +#endif | |
| 51 | +} | |
| 52 | + | |
| 53 | +uint32_t sh_timer_read(void *opaque, target_phys_addr_t offset) | |
| 54 | +{ | |
| 55 | + sh_timer_state *s = (sh_timer_state *)opaque; | |
| 56 | + | |
| 57 | + switch (offset >> 2) { | |
| 58 | + case 0: | |
| 59 | + return s->tcor; | |
| 60 | + case 1: | |
| 61 | + return ptimer_get_count(s->timer); | |
| 62 | + case 2: | |
| 63 | + return s->tcr | (s->int_level ? TIMER_TCR_UNF : 0); | |
| 64 | + case 3: | |
| 65 | + if (s->feat & TIMER_FEAT_CAPT) | |
| 66 | + return s->tcpr; | |
| 67 | + default: | |
| 68 | + cpu_abort (cpu_single_env, "sh_timer_read: Bad offset %x\n", | |
| 69 | + (int)offset); | |
| 70 | + return 0; | |
| 71 | + } | |
| 72 | +} | |
| 73 | + | |
| 74 | +static void sh_timer_write(void *opaque, target_phys_addr_t offset, | |
| 75 | + uint32_t value) | |
| 76 | +{ | |
| 77 | + sh_timer_state *s = (sh_timer_state *)opaque; | |
| 78 | + int freq; | |
| 79 | + | |
| 80 | + switch (offset >> 2) { | |
| 81 | + case 0: | |
| 82 | + s->tcor = value; | |
| 83 | + ptimer_set_limit(s->timer, s->tcor, 0); | |
| 84 | + break; | |
| 85 | + case 1: | |
| 86 | + s->tcnt = value; | |
| 87 | + ptimer_set_count(s->timer, s->tcnt); | |
| 88 | + break; | |
| 89 | + case 2: | |
| 90 | + if (s->enabled) { | |
| 91 | + /* Pause the timer if it is running. This may cause some | |
| 92 | + inaccuracy dure to rounding, but avoids a whole lot of other | |
| 93 | + messyness. */ | |
| 94 | + ptimer_stop(s->timer); | |
| 95 | + } | |
| 96 | + freq = s->freq; | |
| 97 | + /* ??? Need to recalculate expiry time after changing divisor. */ | |
| 98 | + switch (value & TIMER_TCR_TPSC) { | |
| 99 | + case 0: freq >>= 2; break; | |
| 100 | + case 1: freq >>= 4; break; | |
| 101 | + case 2: freq >>= 6; break; | |
| 102 | + case 3: freq >>= 8; break; | |
| 103 | + case 4: freq >>= 10; break; | |
| 104 | + case 6: | |
| 105 | + case 7: if (s->feat & TIMER_FEAT_EXTCLK) break; | |
| 106 | + default: cpu_abort (cpu_single_env, | |
| 107 | + "sh_timer_write: Reserved TPSC value\n"); break; | |
| 108 | + } | |
| 109 | + switch ((value & TIMER_TCR_CKEG) >> 3) { | |
| 110 | + case 0: break; | |
| 111 | + case 1: | |
| 112 | + case 2: | |
| 113 | + case 3: if (s->feat & TIMER_FEAT_EXTCLK) break; | |
| 114 | + default: cpu_abort (cpu_single_env, | |
| 115 | + "sh_timer_write: Reserved CKEG value\n"); break; | |
| 116 | + } | |
| 117 | + switch ((value & TIMER_TCR_ICPE) >> 6) { | |
| 118 | + case 0: break; | |
| 119 | + case 2: | |
| 120 | + case 3: if (s->feat & TIMER_FEAT_CAPT) break; | |
| 121 | + default: cpu_abort (cpu_single_env, | |
| 122 | + "sh_timer_write: Reserved ICPE value\n"); break; | |
| 123 | + } | |
| 124 | + if ((value & TIMER_TCR_UNF) == 0) | |
| 125 | + s->int_level = 0; | |
| 126 | + | |
| 127 | + value &= ~TIMER_TCR_UNF; | |
| 128 | + | |
| 129 | + if ((value & TIMER_TCR_ICPF) && (!(s->feat & TIMER_FEAT_CAPT))) | |
| 130 | + cpu_abort (cpu_single_env, | |
| 131 | + "sh_timer_write: Reserved ICPF value\n"); | |
| 132 | + | |
| 133 | + value &= ~TIMER_TCR_ICPF; /* capture not supported */ | |
| 134 | + | |
| 135 | + if (value & TIMER_TCR_RESERVED) | |
| 136 | + cpu_abort (cpu_single_env, | |
| 137 | + "sh_timer_write: Reserved TCR bits set\n"); | |
| 138 | + s->tcr = value; | |
| 139 | + ptimer_set_limit(s->timer, s->tcor, 0); | |
| 140 | + ptimer_set_freq(s->timer, freq); | |
| 141 | + if (s->enabled) { | |
| 142 | + /* Restart the timer if still enabled. */ | |
| 143 | + ptimer_run(s->timer, 0); | |
| 144 | + } | |
| 145 | + break; | |
| 146 | + case 3: | |
| 147 | + if (s->feat & TIMER_FEAT_CAPT) { | |
| 148 | + s->tcpr = value; | |
| 149 | + break; | |
| 150 | + } | |
| 151 | + default: | |
| 152 | + cpu_abort (cpu_single_env, "sh_timer_write: Bad offset %x\n", | |
| 153 | + (int)offset); | |
| 154 | + } | |
| 155 | + sh_timer_update(s); | |
| 156 | +} | |
| 157 | + | |
| 158 | +static void sh_timer_start_stop(void *opaque, int enable) | |
| 159 | +{ | |
| 160 | + sh_timer_state *s = (sh_timer_state *)opaque; | |
| 161 | + | |
| 162 | +#ifdef DEBUG_TIMER | |
| 163 | + printf("sh_timer_start_stop %d (%d)\n", enable, s->enabled); | |
| 164 | +#endif | |
| 165 | + | |
| 166 | + if (s->enabled && !enable) { | |
| 167 | + ptimer_stop(s->timer); | |
| 168 | + } | |
| 169 | + if (!s->enabled && enable) { | |
| 170 | + ptimer_run(s->timer, 0); | |
| 171 | + } | |
| 172 | + s->enabled = !!enable; | |
| 173 | + | |
| 174 | +#ifdef DEBUG_TIMER | |
| 175 | + printf("sh_timer_start_stop done %d\n", s->enabled); | |
| 176 | +#endif | |
| 177 | +} | |
| 178 | + | |
| 179 | +static void sh_timer_tick(void *opaque) | |
| 180 | +{ | |
| 181 | + sh_timer_state *s = (sh_timer_state *)opaque; | |
| 182 | + s->int_level = s->enabled; | |
| 183 | + sh_timer_update(s); | |
| 184 | +} | |
| 185 | + | |
| 186 | +static void *sh_timer_init(uint32_t freq, int feat) | |
| 187 | +{ | |
| 188 | + sh_timer_state *s; | |
| 189 | + QEMUBH *bh; | |
| 190 | + | |
| 191 | + s = (sh_timer_state *)qemu_mallocz(sizeof(sh_timer_state)); | |
| 192 | + s->freq = freq; | |
| 193 | + s->feat = feat; | |
| 194 | + s->tcor = 0xffffffff; | |
| 195 | + s->tcnt = 0xffffffff; | |
| 196 | + s->tcpr = 0xdeadbeef; | |
| 197 | + s->tcor = 0; | |
| 198 | + s->enabled = 0; | |
| 199 | + | |
| 200 | + bh = qemu_bh_new(sh_timer_tick, s); | |
| 201 | + s->timer = ptimer_init(bh); | |
| 202 | + /* ??? Save/restore. */ | |
| 203 | + return s; | |
| 204 | +} | |
| 205 | + | |
| 206 | +typedef struct { | |
| 207 | + void *timer[3]; | |
| 208 | + int level[3]; | |
| 209 | + uint32_t tocr; | |
| 210 | + uint32_t tstr; | |
| 211 | + target_phys_addr_t base; | |
| 212 | + int feat; | |
| 213 | +} tmu012_state; | |
| 214 | + | |
| 215 | +static uint32_t tmu012_read(void *opaque, target_phys_addr_t offset) | |
| 216 | +{ | |
| 217 | + tmu012_state *s = (tmu012_state *)opaque; | |
| 218 | + | |
| 219 | +#ifdef DEBUG_TIMER | |
| 220 | + printf("tmu012_read 0x%lx\n", (unsigned long) offset); | |
| 221 | +#endif | |
| 222 | + offset -= s->base; | |
| 223 | + | |
| 224 | + if (offset >= 0x20) { | |
| 225 | + if (!(s->feat & TMU012_FEAT_3CHAN)) | |
| 226 | + cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n", | |
| 227 | + (int)offset); | |
| 228 | + return sh_timer_read(s->timer[2], offset - 0x20); | |
| 229 | + } | |
| 230 | + | |
| 231 | + if (offset >= 0x14) | |
| 232 | + return sh_timer_read(s->timer[1], offset - 0x14); | |
| 233 | + | |
| 234 | + if (offset >= 0x08) | |
| 235 | + return sh_timer_read(s->timer[0], offset - 0x08); | |
| 236 | + | |
| 237 | + if (offset == 4) | |
| 238 | + return s->tstr; | |
| 239 | + | |
| 240 | + if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) | |
| 241 | + return s->tocr; | |
| 242 | + | |
| 243 | + cpu_abort (cpu_single_env, "tmu012_write: Bad offset %x\n", | |
| 244 | + (int)offset); | |
| 245 | + return 0; | |
| 246 | +} | |
| 247 | + | |
| 248 | +static void tmu012_write(void *opaque, target_phys_addr_t offset, | |
| 249 | + uint32_t value) | |
| 250 | +{ | |
| 251 | + tmu012_state *s = (tmu012_state *)opaque; | |
| 252 | + | |
| 253 | +#ifdef DEBUG_TIMER | |
| 254 | + printf("tmu012_write 0x%lx 0x%08x\n", (unsigned long) offset, value); | |
| 255 | +#endif | |
| 256 | + offset -= s->base; | |
| 257 | + | |
| 258 | + if (offset >= 0x20) { | |
| 259 | + if (!(s->feat & TMU012_FEAT_3CHAN)) | |
| 260 | + cpu_abort (cpu_single_env, "tmu012_write: Bad channel offset %x\n", | |
| 261 | + (int)offset); | |
| 262 | + sh_timer_write(s->timer[2], offset - 0x20, value); | |
| 263 | + return; | |
| 264 | + } | |
| 265 | + | |
| 266 | + if (offset >= 0x14) { | |
| 267 | + sh_timer_write(s->timer[1], offset - 0x14, value); | |
| 268 | + return; | |
| 269 | + } | |
| 270 | + | |
| 271 | + if (offset >= 0x08) { | |
| 272 | + sh_timer_write(s->timer[0], offset - 0x08, value); | |
| 273 | + return; | |
| 274 | + } | |
| 275 | + | |
| 276 | + if (offset == 4) { | |
| 277 | + sh_timer_start_stop(s->timer[0], value & (1 << 0)); | |
| 278 | + sh_timer_start_stop(s->timer[1], value & (1 << 1)); | |
| 279 | + if (s->feat & TMU012_FEAT_3CHAN) | |
| 280 | + sh_timer_start_stop(s->timer[2], value & (1 << 2)); | |
| 281 | + else | |
| 282 | + if (value & (1 << 2)) | |
| 283 | + cpu_abort (cpu_single_env, "tmu012_write: Bad channel\n"); | |
| 284 | + | |
| 285 | + s->tstr = value; | |
| 286 | + return; | |
| 287 | + } | |
| 288 | + | |
| 289 | + if ((s->feat & TMU012_FEAT_TOCR) && offset == 0) { | |
| 290 | + s->tocr = value & (1 << 0); | |
| 291 | + } | |
| 292 | +} | |
| 293 | + | |
| 294 | +static CPUReadMemoryFunc *tmu012_readfn[] = { | |
| 295 | + tmu012_read, | |
| 296 | + tmu012_read, | |
| 297 | + tmu012_read | |
| 298 | +}; | |
| 299 | + | |
| 300 | +static CPUWriteMemoryFunc *tmu012_writefn[] = { | |
| 301 | + tmu012_write, | |
| 302 | + tmu012_write, | |
| 303 | + tmu012_write | |
| 304 | +}; | |
| 305 | + | |
| 306 | +void tmu012_init(uint32_t base, int feat, uint32_t freq) | |
| 307 | +{ | |
| 308 | + int iomemtype; | |
| 309 | + tmu012_state *s; | |
| 310 | + int timer_feat = (feat & TMU012_FEAT_EXTCLK) ? TIMER_FEAT_EXTCLK : 0; | |
| 311 | + | |
| 312 | + s = (tmu012_state *)qemu_mallocz(sizeof(tmu012_state)); | |
| 313 | + s->base = base; | |
| 314 | + s->feat = feat; | |
| 315 | + s->timer[0] = sh_timer_init(freq, timer_feat); | |
| 316 | + s->timer[1] = sh_timer_init(freq, timer_feat); | |
| 317 | + if (feat & TMU012_FEAT_3CHAN) | |
| 318 | + s->timer[2] = sh_timer_init(freq, timer_feat | TIMER_FEAT_CAPT); | |
| 319 | + iomemtype = cpu_register_io_memory(0, tmu012_readfn, | |
| 320 | + tmu012_writefn, s); | |
| 321 | + cpu_register_physical_memory(base, 0x00001000, iomemtype); | |
| 322 | + /* ??? Save/restore. */ | |
| 323 | +} | ... | ... |
vl.h
| ... | ... | @@ -1517,6 +1517,12 @@ typedef struct { |
| 1517 | 1517 | |
| 1518 | 1518 | int sh7750_register_io_device(struct SH7750State *s, |
| 1519 | 1519 | sh7750_io_device * device); |
| 1520 | +/* sh_timer.c */ | |
| 1521 | +#define TMU012_FEAT_TOCR (1 << 0) | |
| 1522 | +#define TMU012_FEAT_3CHAN (1 << 1) | |
| 1523 | +#define TMU012_FEAT_EXTCLK (1 << 2) | |
| 1524 | +void tmu012_init(uint32_t base, int feat, uint32_t freq); | |
| 1525 | + | |
| 1520 | 1526 | /* tc58128.c */ |
| 1521 | 1527 | int tc58128_init(struct SH7750State *s, char *zone1, char *zone2); |
| 1522 | 1528 | ... | ... |