1- import { getCurrentMicroseconds } from '../utils/time' ;
2- import { LoggingPeripheral , Peripheral } from './peripheral' ;
1+ import { IClock , IClockTimer } from '../clock/clock' ;
2+ import { RP2040 } from '../rp2040' ;
3+ import { BasePeripheral , Peripheral } from './peripheral' ;
34
45const TIMEHR = 0x08 ;
56const TIMELR = 0x0c ;
67const TIMERAWH = 0x24 ;
78const TIMERAWL = 0x28 ;
9+ const ALARM0 = 0x10 ;
10+ const ALARM1 = 0x14 ;
11+ const ALARM2 = 0x18 ;
12+ const ALARM3 = 0x1c ;
13+ const ARMED = 0x20 ;
14+ const PAUSE = 0x30 ;
15+ const INTR = 0x34 ;
16+ const INTE = 0x38 ;
17+ const INTF = 0x3c ;
18+ const INTS = 0x40 ;
819
920/* eslint-disable @typescript-eslint/no-unused-vars */
1021const ALARM_0 = 1 << 0 ;
@@ -13,11 +24,39 @@ const ALARM_2 = 1 << 2;
1324const ALARM_3 = 1 << 3 ;
1425/* eslint-enable @typescript-eslint/no-unused-vars */
1526
16- export class RPTimer extends LoggingPeripheral implements Peripheral {
17- latchedTimeHigh = 0 ;
27+ class RPTimerAlarm {
28+ armed = false ;
29+ targetMicros = 0 ;
30+ timer : IClockTimer | null = null ;
31+
32+ constructor ( readonly name : string , readonly bitValue : number ) { }
33+ }
34+
35+ export class RPTimer extends BasePeripheral implements Peripheral {
36+ private readonly clock : IClock ;
37+ private latchedTimeHigh = 0 ;
38+ private readonly alarms = [
39+ new RPTimerAlarm ( 'Alarm 0' , ALARM_0 ) ,
40+ new RPTimerAlarm ( 'Alarm 1' , ALARM_1 ) ,
41+ new RPTimerAlarm ( 'Alarm 2' , ALARM_2 ) ,
42+ new RPTimerAlarm ( 'Alarm 3' , ALARM_3 ) ,
43+ ] ;
44+ private intRaw = 0 ;
45+ private intEnable = 0 ;
46+ private intForce = 0 ;
47+ private paused = false ;
48+
49+ constructor ( rp2040 : RP2040 , name : string ) {
50+ super ( rp2040 , name ) ;
51+ this . clock = rp2040 . clock ;
52+ }
53+
54+ get intStatus ( ) {
55+ return ( this . intRaw | this . intForce ) & this . intEnable ;
56+ }
1857
1958 readUint32 ( offset : number ) {
20- const time = getCurrentMicroseconds ( ) ;
59+ const time = this . clock . micros ;
2160
2261 switch ( offset ) {
2362 case TIMEHR :
@@ -32,14 +71,104 @@ export class RPTimer extends LoggingPeripheral implements Peripheral {
3271
3372 case TIMERAWL :
3473 return time >>> 0 ;
74+
75+ case ALARM0 :
76+ return this . alarms [ 0 ] . targetMicros ;
77+ case ALARM1 :
78+ return this . alarms [ 1 ] . targetMicros ;
79+ case ALARM2 :
80+ return this . alarms [ 2 ] . targetMicros ;
81+ case ALARM3 :
82+ return this . alarms [ 3 ] . targetMicros ;
83+
84+ case PAUSE :
85+ return this . paused ? 1 : 0 ;
86+
87+ case INTR :
88+ return this . intRaw ;
89+ case INTE :
90+ return this . intEnable ;
91+ case INTF :
92+ return this . intForce ;
93+ case INTS :
94+ return this . intStatus ;
95+
96+ case ARMED :
97+ return (
98+ ( this . alarms [ 0 ] . armed ? this . alarms [ 0 ] . bitValue : 0 ) |
99+ ( this . alarms [ 1 ] . armed ? this . alarms [ 1 ] . bitValue : 0 ) |
100+ ( this . alarms [ 2 ] . armed ? this . alarms [ 2 ] . bitValue : 0 ) |
101+ ( this . alarms [ 3 ] . armed ? this . alarms [ 3 ] . bitValue : 0 )
102+ ) ;
35103 }
36104 return super . readUint32 ( offset ) ;
37105 }
38106
39107 writeUint32 ( offset : number , value : number ) {
40108 switch ( offset ) {
109+ case ALARM0 :
110+ case ALARM1 :
111+ case ALARM2 :
112+ case ALARM3 : {
113+ const alarmIndex = ( offset - ALARM0 ) / 4 ;
114+ const alarm = this . alarms [ alarmIndex ] ;
115+ const delta = ( value - this . clock . micros ) >>> 0 ;
116+ this . disarmAlarm ( alarm ) ;
117+ alarm . armed = true ;
118+ alarm . targetMicros = value ;
119+ alarm . timer = this . clock . createTimer ( delta , ( ) => this . fireAlarm ( alarmIndex ) ) ;
120+ break ;
121+ }
122+ case ARMED :
123+ for ( const alarm of this . alarms ) {
124+ if ( this . rawWriteValue & alarm . bitValue ) {
125+ this . disarmAlarm ( alarm ) ;
126+ }
127+ }
128+ break ;
129+ case PAUSE :
130+ this . paused = ! ! ( value & 1 ) ;
131+ if ( this . paused ) {
132+ console . warn ( 'Unimplemented Timer Pause' ) ;
133+ }
134+ // TODO actually pause the timer
135+ break ;
136+ case INTR :
137+ this . intRaw &= ~ this . rawWriteValue ;
138+ this . checkInterrupts ( ) ;
139+ break ;
140+ case INTE :
141+ this . intEnable = value & 0xf ;
142+ this . checkInterrupts ( ) ;
143+ break ;
144+ case INTF :
145+ this . intForce = value & 0xf ;
146+ this . checkInterrupts ( ) ;
147+ break ;
41148 default :
42149 super . writeUint32 ( offset , value ) ;
43150 }
44151 }
152+
153+ private fireAlarm ( index : number ) {
154+ const alarm = this . alarms [ index ] ;
155+ this . disarmAlarm ( alarm ) ;
156+ this . intRaw |= alarm . bitValue ;
157+ this . checkInterrupts ( ) ;
158+ }
159+
160+ private checkInterrupts ( ) {
161+ const { intStatus } = this ;
162+ for ( let i = 0 ; i < this . alarms . length ; i ++ ) {
163+ this . rp2040 . setInterrupt ( i , ! ! ( intStatus & ( 1 << i ) ) ) ;
164+ }
165+ }
166+
167+ private disarmAlarm ( alarm : RPTimerAlarm ) {
168+ if ( alarm . timer ) {
169+ this . clock . deleteTimer ( alarm . timer ) ;
170+ alarm . timer = null ;
171+ }
172+ alarm . armed = false ;
173+ }
45174}
0 commit comments