Skip to content

Commit

Permalink
Extracted iPod Touch timer to separate file
Browse files Browse the repository at this point in the history
  • Loading branch information
devos50 committed Sep 4, 2022
1 parent 51aaa2b commit 89214ac
Show file tree
Hide file tree
Showing 6 changed files with 211 additions and 167 deletions.
135 changes: 9 additions & 126 deletions hw/arm/ipod_touch.c
Original file line number Diff line number Diff line change
Expand Up @@ -132,115 +132,6 @@ static void ipod_touch_cpu_reset(void *opaque)
//cpu_set_pc(CPU(cpu), VROM_MEM_BASE);
}

static void s5l8900_st_update(s5l8900_timer_s *s)
{
s->freq_out = 1000000000 / 100;
s->tick_interval = /* bcount1 * get_ticks / freq + ((bcount2 * get_ticks / freq)*/
muldiv64((s->bcount1 < 1000) ? 1000 : s->bcount1, NANOSECONDS_PER_SECOND, s->freq_out);
s->next_planned_tick = 0;
}

static void s5l8900_st_set_timer(s5l8900_timer_s *s)
{
uint64_t last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->base_time;

s->next_planned_tick = last + (s->tick_interval - last % s->tick_interval);
timer_mod(s->st_timer, s->next_planned_tick + s->base_time);
s->last_tick = last;
}

static void s5l8900_st_tick(void *opaque)
{
s5l8900_timer_s *s = (s5l8900_timer_s *)opaque;

if (s->status & TIMER_STATE_START) {
//fprintf(stderr, "%s: Raising irq\n", __func__);
qemu_irq_raise(s->irq);

/* schedule next interrupt */
if(!(s->status & TIMER_STATE_MANUALUPDATE)) {
s5l8900_st_set_timer(s);
}
} else {
s->next_planned_tick = 0;
s->last_tick = 0;
timer_del(s->st_timer);
}
}

static void s5l8900_timer1_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
{
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
s5l8900_timer_s *s = (struct s5l8900_timer_s *) opaque;

switch(addr){

case TIMER_IRQSTAT:
s->irqstat = value;
return;
case TIMER_IRQLATCH:
//fprintf(stderr, "%s: lowering irq\n", __func__);
qemu_irq_lower(s->irq);
return;
case TIMER_4 + TIMER_CONFIG:
s5l8900_st_update(s);
s->config = value;
break;
case TIMER_4 + TIMER_STATE:
if (value & TIMER_STATE_START) {
s->base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
s5l8900_st_update(s);
s5l8900_st_set_timer(s);
} else if (value == TIMER_STATE_STOP) {
timer_del(s->st_timer);
}
s->status = value;
break;
case TIMER_4 + TIMER_COUNT_BUFFER:
s->bcount1 = s->bcreload = value;
break;
case TIMER_4 + TIMER_COUNT_BUFFER2:
s->bcount2 = value;
break;
default:
break;
}
}

static uint64_t s5l8900_timer1_read(void *opaque, hwaddr addr, unsigned size)
{
//fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr);
s5l8900_timer_s *s = (struct s5l8900_timer_s *) opaque;
uint64_t elapsed_ns, ticks;

switch (addr) {
case TIMER_TICKSHIGH: // needs to be fixed so that read from low first works as well

elapsed_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ticks = clock_ns_to_ticks(s->sysclk, elapsed_ns);
//printf("TICKS: %lld\n", ticks);
s->ticks_high = (ticks >> 32);
s->ticks_low = (ticks & 0xFFFFFFFF);
return s->ticks_high;
case TIMER_TICKSLOW:
return s->ticks_low;
case TIMER_IRQSTAT:
return ~0; // s->irqstat;
case TIMER_IRQLATCH:
return 0xffffffff;

default:
break;
}
return 0;
}

static const MemoryRegionOps timer1_ops = {
.read = s5l8900_timer1_read,
.write = s5l8900_timer1_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};

/*
CLOCK
*/
Expand Down Expand Up @@ -436,20 +327,6 @@ static void ipod_touch_init_clock(MachineState *machine, MemoryRegion *sysmem)
memory_region_add_subregion(sysmem, CLOCK1_MEM_BASE, iomem);
}

static void ipod_touch_init_timer(MachineState *machine, MemoryRegion *sysmem)
{
IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine);
nms->timer1 = (s5l8900_timer_s *) g_malloc0(sizeof(struct s5l8900_timer_s));
nms->timer1->sysclk = nms->sysclk;
nms->timer1->irq = nms->irq[0][7];
nms->timer1->base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
nms->timer1->st_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s5l8900_st_tick, nms->timer1);

MemoryRegion *iomem = g_new(MemoryRegion, 1);
memory_region_init_io(iomem, OBJECT(nms), &timer1_ops, nms->timer1, "timer1", 0x10001);
memory_region_add_subregion(sysmem, TIMER1_MEM_BASE, iomem);
}

static void ipod_touch_memory_setup(MachineState *machine, MemoryRegion *sysmem, AddressSpace *nsas)
{
IPodTouchMachineState *nms = IPOD_TOUCH_MACHINE(machine);
Expand Down Expand Up @@ -568,15 +445,21 @@ static void ipod_touch_machine_init(MachineState *machine)
// init clock
ipod_touch_init_clock(machine, sysmem);

// init timer
ipod_touch_init_timer(machine, sysmem);
// init the timer
dev = qdev_new("ipodtouch.timer");
IPodTouchTimerState *timer_state = IPOD_TOUCH_TIMER(dev);
nms->timer1 = timer_state;
memory_region_add_subregion(sysmem, TIMER1_MEM_BASE, &timer_state->iomem);
SysBusDevice *busdev = SYS_BUS_DEVICE(dev);
sysbus_connect_irq(busdev, 0, s5l8900_get_irq(nms, S5L8900_TIMER1_IRQ));
timer_state->sysclk = nms->sysclk;

// init sysic
dev = qdev_new("ipodtouch.sysic");
IPodTouchSYSICState *sysic_state = IPOD_TOUCH_SYSIC(dev);
nms->sysic = (IPodTouchSYSICState *) g_malloc0(sizeof(struct IPodTouchSYSICState));
memory_region_add_subregion(sysmem, SYSIC_MEM_BASE, &sysic_state->iomem);
SysBusDevice *busdev = SYS_BUS_DEVICE(dev);
busdev = SYS_BUS_DEVICE(dev);
for(int grp = 0; grp < GPIO_NUMINTGROUPS; grp++) {
sysbus_connect_irq(busdev, grp, s5l8900_get_irq(nms, S5L8900_GPIO_IRQS[grp]));
}
Expand Down
4 changes: 2 additions & 2 deletions hw/arm/ipod_touch_nand.c
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ static void itnand_write(void *opaque, hwaddr addr, uint64_t val, unsigned size)

// flush the page buffer to the disk
uint32_t vpn = s->buffered_page * 8 + s->buffered_bank;
printf("Flushing page %d, bank %d, vpn %d\n", s->buffered_page, s->buffered_bank, vpn);
printf("INIT? %d, pb: %d\n", s->lock.initialized, s->page_buffer);
//printf("Flushing page %d, bank %d, vpn %d\n", s->buffered_page, s->buffered_bank, vpn);
//printf("INIT? %d, pb: %d\n", s->lock.initialized, s->page_buffer);
qemu_mutex_lock(&s->lock);
qemu_mutex_unlock(&s->lock);
// if(vpn >= FILESYSTEM_START_VPN && vpn < (FILESYSTEM_START_VPN + FILESYSTEM_NUM_PAGES)) {
Expand Down
143 changes: 143 additions & 0 deletions hw/arm/ipod_touch_timer.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
#include "hw/arm/ipod_touch_timer.h"

static void s5l8900_st_update(IPodTouchTimerState *s)
{
s->freq_out = 1000000000 / 100;
s->tick_interval = /* bcount1 * get_ticks / freq + ((bcount2 * get_ticks / freq)*/
muldiv64((s->bcount1 < 1000) ? 1000 : s->bcount1, NANOSECONDS_PER_SECOND, s->freq_out);
s->next_planned_tick = 0;
}

static void s5l8900_st_set_timer(IPodTouchTimerState *s)
{
uint64_t last = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) - s->base_time;

s->next_planned_tick = last + (s->tick_interval - last % s->tick_interval);
timer_mod(s->st_timer, s->next_planned_tick + s->base_time);
s->last_tick = last;
}

static void s5l8900_st_tick(void *opaque)
{
IPodTouchTimerState *s = (IPodTouchTimerState *)opaque;

if (s->status & TIMER_STATE_START) {
//fprintf(stderr, "%s: Raising irq\n", __func__);
qemu_irq_raise(s->irq);

/* schedule next interrupt */
if(!(s->status & TIMER_STATE_MANUALUPDATE)) {
s5l8900_st_set_timer(s);
}
} else {
s->next_planned_tick = 0;
s->last_tick = 0;
timer_del(s->st_timer);
}
}

static void s5l8900_timer1_write(void *opaque, hwaddr addr, uint64_t value, unsigned size)
{
//fprintf(stderr, "%s: writing 0x%08x to 0x%08x\n", __func__, value, addr);
IPodTouchTimerState *s = (struct IPodTouchTimerState *) opaque;

switch(addr){

case TIMER_IRQSTAT:
s->irqstat = value;
return;
case TIMER_IRQLATCH:
//fprintf(stderr, "%s: lowering irq\n", __func__);
qemu_irq_lower(s->irq);
return;
case TIMER_4 + TIMER_CONFIG:
s5l8900_st_update(s);
s->config = value;
break;
case TIMER_4 + TIMER_STATE:
if (value & TIMER_STATE_START) {
s->base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
s5l8900_st_update(s);
s5l8900_st_set_timer(s);
} else if (value == TIMER_STATE_STOP) {
timer_del(s->st_timer);
}
s->status = value;
break;
case TIMER_4 + TIMER_COUNT_BUFFER:
s->bcount1 = s->bcreload = value;
break;
case TIMER_4 + TIMER_COUNT_BUFFER2:
s->bcount2 = value;
break;
default:
break;
}
}

static uint64_t s5l8900_timer1_read(void *opaque, hwaddr addr, unsigned size)
{
//fprintf(stderr, "%s: read from location 0x%08x\n", __func__, addr);
IPodTouchTimerState *s = (struct IPodTouchTimerState *) opaque;
uint64_t elapsed_ns, ticks;

switch (addr) {
case TIMER_TICKSHIGH: // needs to be fixed so that read from low first works as well

elapsed_ns = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
ticks = clock_ns_to_ticks(s->sysclk, elapsed_ns);
//printf("TICKS: %lld\n", ticks);
s->ticks_high = (ticks >> 32);
s->ticks_low = (ticks & 0xFFFFFFFF);
return s->ticks_high;
case TIMER_TICKSLOW:
return s->ticks_low;
case TIMER_IRQSTAT:
return ~0; // s->irqstat;
case TIMER_IRQLATCH:
return 0xffffffff;

default:
break;
}
return 0;
}

static const MemoryRegionOps timer1_ops = {
.read = s5l8900_timer1_read,
.write = s5l8900_timer1_write,
.endianness = DEVICE_NATIVE_ENDIAN,
};

static void s5l8900_timer_init(Object *obj)
{
SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
DeviceState *dev = DEVICE(sbd);
IPodTouchTimerState *s = IPOD_TOUCH_TIMER(dev);

memory_region_init_io(&s->iomem, obj, &timer1_ops, s, "timer1", 0x10001);
sysbus_init_irq(sbd, &s->irq);

s->base_time = qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL);
s->st_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL, s5l8900_st_tick, s);
}

static void s5l8900_timer_class_init(ObjectClass *klass, void *data)
{

}

static const TypeInfo ipod_touch_timer_info = {
.name = TYPE_IPOD_TOUCH_TIMER,
.parent = TYPE_SYS_BUS_DEVICE,
.instance_size = sizeof(IPodTouchTimerState),
.instance_init = s5l8900_timer_init,
.class_init = s5l8900_timer_class_init,
};

static void ipod_touch_machine_types(void)
{
type_register_static(&ipod_touch_timer_info);
}

type_init(ipod_touch_machine_types)
2 changes: 1 addition & 1 deletion hw/arm/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,6 @@ arm_ss.add(when: 'CONFIG_FSL_IMX7', if_true: files('fsl-imx7.c', 'mcimx7d-sabre.
arm_ss.add(when: 'CONFIG_ARM_SMMUV3', if_true: files('smmu-common.c', 'smmuv3.c'))
arm_ss.add(when: 'CONFIG_FSL_IMX6UL', if_true: files('fsl-imx6ul.c', 'mcimx6ul-evk.c'))
arm_ss.add(when: 'CONFIG_NRF51_SOC', if_true: files('nrf51_soc.c'))
arm_ss.add(when: 'CONFIG_IPOD_TOUCH', if_true: files('ipod_touch.c', 'ipod_touch_spi.c', 'ipod_touch_sysic.c', 'ipod_touch_aes.c', 'ipod_touch_sha1.c', 'ipod_touch_usb_otg.c', 'ipod_touch_8900_engine.c', 'ipod_touch_nand.c', 'ipod_touch_nand_ecc.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_adm.c', 'ipod_touch_chipid.c', 'ipod_touch_tvout.c', 'ipod_touch_lcd_panel.c', 'ipod_touch_multitouch.c', 'ipod_touch_lcd.c', 'ipod_touch_lis302dl.c', 'ipod_touch_aes.c', 'ipod_touch_sha1.c'))
arm_ss.add(when: 'CONFIG_IPOD_TOUCH', if_true: files('ipod_touch.c', 'ipod_touch_spi.c', 'ipod_touch_sysic.c', 'ipod_touch_aes.c', 'ipod_touch_sha1.c', 'ipod_touch_usb_otg.c', 'ipod_touch_8900_engine.c', 'ipod_touch_nand.c', 'ipod_touch_nand_ecc.c', 'ipod_touch_pcf50633_pmu.c', 'ipod_touch_adm.c', 'ipod_touch_chipid.c', 'ipod_touch_tvout.c', 'ipod_touch_lcd_panel.c', 'ipod_touch_multitouch.c', 'ipod_touch_lcd.c', 'ipod_touch_lis302dl.c', 'ipod_touch_aes.c', 'ipod_touch_sha1.c', 'ipod_touch_timer.c'))

hw_arch += {'arm': arm_ss}
42 changes: 4 additions & 38 deletions include/hw/arm/ipod_touch.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "hw/boards.h"
#include "hw/arm/boot.h"
#include "hw/intc/pl192.h"
#include "hw/arm/ipod_touch_timer.h"
#include "hw/arm/ipod_touch_spi.h"
#include "hw/arm/ipod_touch_aes.h"
#include "hw/arm/ipod_touch_sha1.h"
Expand Down Expand Up @@ -38,25 +39,12 @@
#define CLOCK1_PLLLOCK 0x40
#define CLOCK1_PLLMODE 0x44

// timer stuff
#define TIMER_IRQSTAT 0x10000
#define TIMER_IRQLATCH 0xF8
#define TIMER_TICKSHIGH 0x80
#define TIMER_TICKSLOW 0x84
#define TIMER_STATE_START 1
#define TIMER_STATE_STOP 0
#define TIMER_STATE_MANUALUPDATE 2
#define NUM_TIMERS 7
#define TIMER_4 0xA0
#define TIMER_CONFIG 0
#define TIMER_STATE 0x4
#define TIMER_COUNT_BUFFER 0x8
#define TIMER_COUNT_BUFFER2 0xC

// VIC
#define S5L8900_VIC_N 2
#define S5L8900_VIC_SIZE 32

#define S5L8900_TIMER1_IRQ 0x7

#define S5L8900_SPI0_IRQ 0x9
#define S5L8900_SPI1_IRQ 0xA
#define S5L8900_SPI2_IRQ 0xB
Expand Down Expand Up @@ -113,36 +101,14 @@ typedef struct s5l8900_usb_phys_s

} s5l8900_usb_phys_s;

typedef struct s5l8900_timer_s
{
uint32_t ticks_high;
uint32_t ticks_low;
uint32_t status;
uint32_t config;
uint32_t bcount1;
uint32_t bcount2;
uint32_t prescaler;
uint32_t irqstat;
QEMUTimer *st_timer;
Clock *sysclk;
uint32_t bcreload;
uint32_t freq_out;
uint64_t tick_interval;
uint64_t last_tick;
uint64_t next_planned_tick;
uint64_t base_time;
qemu_irq irq;

} s5l8900_timer_s;

typedef struct {
MachineState parent;
qemu_irq **irq;
PL192State *vic0;
PL192State *vic1;
synopsys_usb_state *usb_otg;
s5l8900_clk1_s *clock1;
s5l8900_timer_s *timer1;
IPodTouchTimerState *timer1;
IPodTouchSYSICState *sysic;
S5L8900SPIState *spi2_state;
s5l8900_usb_phys_s *usb_phys;
Expand Down
Loading

0 comments on commit 89214ac

Please sign in to comment.