📄 cuda.c
字号:
/* * QEMU CUDA support * * Copyright (c) 2004 Fabrice Bellard * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */#include "vl.h"/* XXX: implement all timer modes *///#define DEBUG_CUDA//#define DEBUG_CUDA_PACKET/* Bits in B data register: all active low */#define TREQ 0x08 /* Transfer request (input) */#define TACK 0x10 /* Transfer acknowledge (output) */#define TIP 0x20 /* Transfer in progress (output) *//* Bits in ACR */#define SR_CTRL 0x1c /* Shift register control bits */#define SR_EXT 0x0c /* Shift on external clock */#define SR_OUT 0x10 /* Shift out if 1 *//* Bits in IFR and IER */#define IER_SET 0x80 /* set bits in IER */#define IER_CLR 0 /* clear bits in IER */#define SR_INT 0x04 /* Shift register full/empty */#define T1_INT 0x40 /* Timer 1 interrupt */#define T2_INT 0x20 /* Timer 2 interrupt *//* Bits in ACR */#define T1MODE 0xc0 /* Timer 1 mode */#define T1MODE_CONT 0x40 /* continuous interrupts *//* commands (1st byte) */#define ADB_PACKET 0#define CUDA_PACKET 1#define ERROR_PACKET 2#define TIMER_PACKET 3#define POWER_PACKET 4#define MACIIC_PACKET 5#define PMU_PACKET 6/* CUDA commands (2nd byte) */#define CUDA_WARM_START 0x0#define CUDA_AUTOPOLL 0x1#define CUDA_GET_6805_ADDR 0x2#define CUDA_GET_TIME 0x3#define CUDA_GET_PRAM 0x7#define CUDA_SET_6805_ADDR 0x8#define CUDA_SET_TIME 0x9#define CUDA_POWERDOWN 0xa#define CUDA_POWERUP_TIME 0xb#define CUDA_SET_PRAM 0xc#define CUDA_MS_RESET 0xd#define CUDA_SEND_DFAC 0xe#define CUDA_BATTERY_SWAP_SENSE 0x10#define CUDA_RESET_SYSTEM 0x11#define CUDA_SET_IPL 0x12#define CUDA_FILE_SERVER_FLAG 0x13#define CUDA_SET_AUTO_RATE 0x14#define CUDA_GET_AUTO_RATE 0x16#define CUDA_SET_DEVICE_LIST 0x19#define CUDA_GET_DEVICE_LIST 0x1a#define CUDA_SET_ONE_SECOND_MODE 0x1b#define CUDA_SET_POWER_MESSAGES 0x21#define CUDA_GET_SET_IIC 0x22#define CUDA_WAKEUP 0x23#define CUDA_TIMER_TICKLE 0x24#define CUDA_COMBINED_FORMAT_IIC 0x25#define CUDA_TIMER_FREQ (4700000 / 6)#define CUDA_ADB_POLL_FREQ 50/* CUDA returns time_t's offset from Jan 1, 1904, not 1970 */#define RTC_OFFSET 2082844800typedef struct CUDATimer { int index; uint16_t latch; uint16_t counter_value; /* counter value at load time */ int64_t load_time; int64_t next_irq_time; QEMUTimer *timer;} CUDATimer;typedef struct CUDAState { /* cuda registers */ uint8_t b; /* B-side data */ uint8_t a; /* A-side data */ uint8_t dirb; /* B-side direction (1=output) */ uint8_t dira; /* A-side direction (1=output) */ uint8_t sr; /* Shift register */ uint8_t acr; /* Auxiliary control register */ uint8_t pcr; /* Peripheral control register */ uint8_t ifr; /* Interrupt flag register */ uint8_t ier; /* Interrupt enable register */ uint8_t anh; /* A-side data, no handshake */ CUDATimer timers[2]; uint8_t last_b; /* last value of B register */ uint8_t last_acr; /* last value of B register */ int data_in_size; int data_in_index; int data_out_index; SetIRQFunc *set_irq; int irq; void *irq_opaque; uint8_t autopoll; uint8_t data_in[128]; uint8_t data_out[16]; QEMUTimer *adb_poll_timer;} CUDAState;static CUDAState cuda_state;ADBBusState adb_bus;static void cuda_update(CUDAState *s);static void cuda_receive_packet_from_host(CUDAState *s, const uint8_t *data, int len);static void cuda_timer_update(CUDAState *s, CUDATimer *ti, int64_t current_time);static void cuda_update_irq(CUDAState *s){ if (s->ifr & s->ier & (SR_INT | T1_INT)) { s->set_irq(s->irq_opaque, s->irq, 1); } else { s->set_irq(s->irq_opaque, s->irq, 0); }}static unsigned int get_counter(CUDATimer *s){ int64_t d; unsigned int counter; d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); if (s->index == 0) { /* the timer goes down from latch to -1 (period of latch + 2) */ if (d <= (s->counter_value + 1)) { counter = (s->counter_value - d) & 0xffff; } else { counter = (d - (s->counter_value + 1)) % (s->latch + 2); counter = (s->latch - counter) & 0xffff; } } else { counter = (s->counter_value - d) & 0xffff; } return counter;}static void set_counter(CUDAState *s, CUDATimer *ti, unsigned int val){#ifdef DEBUG_CUDA printf("cuda: T%d.counter=%d\n", 1 + (ti->timer == NULL), val);#endif ti->load_time = qemu_get_clock(vm_clock); ti->counter_value = val; cuda_timer_update(s, ti, ti->load_time);}static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time){ int64_t d, next_time; unsigned int counter; /* current counter value */ d = muldiv64(current_time - s->load_time, CUDA_TIMER_FREQ, ticks_per_sec); /* the timer goes down from latch to -1 (period of latch + 2) */ if (d <= (s->counter_value + 1)) { counter = (s->counter_value - d) & 0xffff; } else { counter = (d - (s->counter_value + 1)) % (s->latch + 2); counter = (s->latch - counter) & 0xffff; } /* Note: we consider the irq is raised on 0 */ if (counter == 0xffff) { next_time = d + s->latch + 1; } else if (counter == 0) { next_time = d + s->latch + 2; } else { next_time = d + counter; }#if 0#ifdef DEBUG_CUDA printf("latch=%d counter=%" PRId64 " delta_next=%" PRId64 "\n", s->latch, d, next_time - d);#endif#endif next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + s->load_time; if (next_time <= current_time) next_time = current_time + 1; return next_time;}static void cuda_timer_update(CUDAState *s, CUDATimer *ti, int64_t current_time){ if (!ti->timer) return; if ((s->acr & T1MODE) != T1MODE_CONT) { qemu_del_timer(ti->timer); } else { ti->next_irq_time = get_next_irq_time(ti, current_time); qemu_mod_timer(ti->timer, ti->next_irq_time); }}static void cuda_timer1(void *opaque){ CUDAState *s = opaque; CUDATimer *ti = &s->timers[0]; cuda_timer_update(s, ti, ti->next_irq_time); s->ifr |= T1_INT; cuda_update_irq(s);}static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr){ CUDAState *s = opaque; uint32_t val; addr = (addr >> 9) & 0xf; switch(addr) { case 0: val = s->b; break; case 1: val = s->a; break; case 2: val = s->dirb; break; case 3: val = s->dira; break; case 4: val = get_counter(&s->timers[0]) & 0xff; s->ifr &= ~T1_INT; cuda_update_irq(s); break; case 5: val = get_counter(&s->timers[0]) >> 8; cuda_update_irq(s); break; case 6: val = s->timers[0].latch & 0xff; break; case 7: /* XXX: check this */ val = (s->timers[0].latch >> 8) & 0xff; break; case 8: val = get_counter(&s->timers[1]) & 0xff; s->ifr &= ~T2_INT; break; case 9: val = get_counter(&s->timers[1]) >> 8; break; case 10: val = s->sr; s->ifr &= ~SR_INT; cuda_update_irq(s); break; case 11: val = s->acr; break; case 12: val = s->pcr; break; case 13: val = s->ifr; if (s->ifr & s->ier) val |= 0x80; break; case 14: val = s->ier | 0x80; break; default: case 15: val = s->anh; break; }#ifdef DEBUG_CUDA if (addr != 13 || val != 0) printf("cuda: read: reg=0x%x val=%02x\n", addr, val);#endif return val;}static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val){ CUDAState *s = opaque; addr = (addr >> 9) & 0xf;#ifdef DEBUG_CUDA printf("cuda: write: reg=0x%x val=%02x\n", addr, val);#endif switch(addr) { case 0:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -