/**
 * AVR8 Clock
 * Part of AVR8js
 * Reference: http://ww1.microchip.com/downloads/en/DeviceDoc/ATmega48A-PA-88A-PA-168A-PA-328-P-DS-DS40002061A.pdf
 *
 * Copyright (C) 2020, Uri Shaked
 */ import { CPU } from '../cpu/cpu' ; import { u32 , u8 } from '../types' ; const CLKPCE = 128 ; export interface AVRClockConfig { CLKPR : u8 ; } export const clockConfig = { CLKPR : 0x61 , } ; const prescalers = [ 1 , 2 , 4 , 8 , 16 , 32 , 64 , 128 , 256 , 2 , 4 , 8 , 16 , 32 , 64 , 128 , ] ; export class AVRClock { private clockEnabledCycles = 0 ; private prescalerValue = 1 ; cyclesDelta = 0 ; constructor ( private cpu , private baseFreqHz , private config = clockConfig ) { this . cpu . writeHooks [ this . config . CLKPR ] = ( clkpr ) => { if ( ( ! this . clockEnabledCycles || this . clockEnabledCycles < cpu . cycles ) && clkpr === CLKPCE ) { this . clockEnabledCycles = this . cpu . cycles + 4 ; } else if ( this . clockEnabledCycles && this . clockEnabledCycles >= cpu . cycles ) { this . clockEnabledCycles = 0 ; const index = clkpr & 0xf ; const oldPrescaler = this . prescalerValue ; this . prescalerValue = prescalers [ index ] ; this . cpu . data [ this . config . CLKPR ] = index ; if ( oldPrescaler !== this . prescalerValue ) { this . cyclesDelta = ( cpu . cycles + this . cyclesDelta ) * ( oldPrescaler / this . prescalerValue ) - cpu . cycles ; } } return true ; } ; } get frequency ( ) { return this . baseFreqHz / this . prescalerValue ; } get prescaler ( ) { return this . prescalerValue ; } get timeNanos ( ) { return ( ( this . cpu . cycles + this . cyclesDelta ) / this . frequency ) * 1e9 ; } get timeMicros ( ) { return ( ( this . cpu . cycles + this . cyclesDelta ) / this . frequency ) * 1e6 ; } get timeMillis ( ) { return ( ( this . cpu . cycles + this . cyclesDelta ) / this . frequency ) * 1e3 ; } }