{sh_timer_state*s=(sh_timer_state*)opaque;switch(offset>>2){case0:returns->tcor;case1:returnptimer_get_count(s->timer);case2:returns->tcr|(s->int_level?TIMER_TCR_UNF:0);case3:if(s->feat&TIMER_FEAT_CAPT)returns->tcpr;default:cpu_abort(cpu_single_env,"sh_timer_read: Bad offset %x\n",(int)offset);return0;}}staticvoidsh_timer_write(void*opaque,target_phys_addr_toffset,uint32_tvalue){sh_timer_state*s=(sh_timer_state*)opaque;intfreq;switch(offset>>2){case0:s->tcor=value;ptimer_set_limit(s->timer,s->tcor,0);break;case1:s->tcnt=value;ptimer_set_count(s->timer,s->tcnt);break;case2:if(s->enabled){/*Pausethetimerifitisrunning.Thismaycausesomeinaccuracyduretorounding,butavoidsawholelotofothermessyness.*/ptimer_stop(s->timer);}freq=s->freq;/* ??? Need to recalculate expiry time after changing divisor. */switch(value&TIMER_TCR_TPSC){case0:freq>>=2;break;case1:freq>>=4;break;case2:freq>>=6;break;case3:freq>>=8;break;case4:freq>>=10;break;case6:case7:if(s->feat&TIMER_FEAT_EXTCLK)break;default:cpu_abort(cpu_single_env,"sh_timer_write: Reserved TPSC value\n");break;}switch((value&TIMER_TCR_CKEG)>>3){case0:break;case1:case2:case3:if(s->feat&TIMER_FEAT_EXTCLK)break;default:cpu_abort(cpu_single_env,"sh_timer_write: Reserved CKEG value\n");break;}switch((value&TIMER_TCR_ICPE)>>6){case0:break;case2:case3:if(s->feat&TIMER_FEAT_CAPT)break;default:cpu_abort(cpu_single_env,"sh_timer_write: Reserved ICPE value\n");break;}if((value&TIMER_TCR_UNF)==0)s->int_level=0;value&=~TIMER_TCR_UNF;if((value&TIMER_TCR_ICPF)&&(!(s->feat&TIMER_FEAT_CAPT)))cpu_abort(cpu_single_env,"sh_timer_write: Reserved ICPF value\n");value&=~TIMER_TCR_ICPF;/* capture not supported */if(value&TIMER_TCR_RESERVED)cpu_abort(cpu_single_env,"sh_timer_write: Reserved TCR bits set\n");s->tcr=value;ptimer_set_limit(s->timer,s->tcor,0);ptimer_set_freq(s->timer,freq);if(s->enabled){/* Restart the timer if still enabled. */ptimer_run(s->timer,0);}break;case3:if(s->feat&TIMER_FEAT_CAPT){s->tcpr=value;break;}default:cpu_abort(cpu_single_env,"sh_timer_write: Bad offset %x\n",(int)offset);}sh_timer_update(s);}staticvoidsh_timer_start_stop(void*opaque,intenable){sh_timer_state*s=(sh_timer_state*)opaque;#ifdefDEBUG_TIMERprintf("sh_timer_start_stop %d (%d)\n",enable,s->enabled);#endifif(s->enabled&&!enable){ptimer_stop(s->timer);}if(!s->enabled&&enable){ptimer_run(s->timer,0);}s->enabled=!!enable;#ifdefDEBUG_TIMERprintf("sh_timer_start_stop done %d\n",s->enabled);#endif}staticvoidsh_timer_tick(void*opaque){sh_timer_state*s=(sh_timer_state*)opaque;s->int_level=s->enabled;sh_timer_update(s);}
bh=qemu_bh_new(sh_timer_tick,s);s->timer=ptimer_init(bh);/* ??? Save/restore. */returns;}typedefstruct{void*timer[3];intlevel[3];uint32_ttocr;uint32_ttstr;target_phys_addr_tbase;intfeat;}tmu012_state;staticuint32_ttmu012_read(void*opaque,target_phys_addr_toffset){tmu012_state*s=(tmu012_state*)opaque;#ifdefDEBUG_TIMERprintf("tmu012_read 0x%lx\n",(unsignedlong)offset);#endifoffset-=s->base;if(offset>=0x20){if(!(s->feat&TMU012_FEAT_3CHAN))cpu_abort(cpu_single_env,"tmu012_write: Bad channel offset %x\n",(int)offset);returnsh_timer_read(s->timer[2],offset-0x20);}if(offset>=0x14)returnsh_timer_read(s->timer[1],offset-0x14);if(offset>=0x08)returnsh_timer_read(s->timer[0],offset-0x08);if(offset==4)returns->tstr;if((s->feat&TMU012_FEAT_TOCR)&&offset==0)returns->tocr;cpu_abort(cpu_single_env,"tmu012_write: Bad offset %x\n",(int)offset);return0;}staticvoidtmu012_write(void*opaque,target_phys_addr_toffset,uint32_tvalue){tmu012_state*s=(tmu012_state*)opaque;#ifdefDEBUG_TIMERprintf("tmu012_write 0x%lx 0x%08x\n",(unsignedlong)offset,value);#endifoffset-=s->base;if(offset>=0x20){if(!(s->feat&TMU012_FEAT_3CHAN))cpu_abort(cpu_single_env,"tmu012_write: Bad channel offset %x\n",(int)offset);sh_timer_write(s->timer[2],offset-0x20,value);return;}if(offset>=0x14){sh_timer_write(s->timer[1],offset-0x14,value);return;}if(offset>=0x08){sh_timer_write(s->timer[0],offset-0x08,value);return;}if(offset==4){sh_timer_start_stop(s->timer[0],value&(1<<0));sh_timer_start_stop(s->timer[1],value&(1<<1));if(s->feat&TMU012_FEAT_3CHAN)sh_timer_start_stop(s->timer[2],value&(1<<2));elseif(value&(1<<2))cpu_abort(cpu_single_env,"tmu012_write: Bad channel\n");s->tstr=value;return;}if((s->feat&TMU012_FEAT_TOCR)&&offset==0){s->tocr=value&(1<<0);}}staticCPUReadMemoryFunc*tmu012_readfn[]={tmu012_read,tmu012_read,tmu012_read};staticCPUWriteMemoryFunc*tmu012_writefn[]={tmu012_write,tmu012_write,tmu012_write};