03 July 2013, 16:08 | #1 |
Registered User
Join Date: Sep 2008
Location: Germany
Age: 50
Posts: 139
|
example of a CIA timer interrupt in assembler using cia.resource
Back in the early 90s I failed writing (and understanding) a CIA timer interrupt. This bugged me ever since.
Now with the help of the internet and especially some posts of this board finally I got it done. For this reason I want to share these bits. May it help others. This code lacks of proper error checking and it could be more elegant. It only tries to allocate the timers from CIA-B. Code:
; a os friendly CIA timer interrupt ; roughly translated from the example in the reference manual ; main loop switches the power led in a 1s interval ; tab-size = 4 include "exec/types.i" include "exec/funcdef.i" ; keep code simple and include "exec/exec.i" ; the includes! include "exec/exec_lib.i" include "exec/io.i" include "exec/nodes.i" include "exec/tasks.i" include "exec/interrupts.i" include "resources/cia.i" include "hardware/cia.i" execbase equ 4 ciab equ $bfd000 AddICRVector equ -6 RemICRVector equ -12 AbleICR equ -18 SetICR equ -24 CLEAR equ 0 section code _start: bsr myTimerInstall tst.l d0 ; 0 = successful bne.b .error_exit move.l t10ms,d7 ; we start .loop1: move.l t10ms,d0 sub.l d7,d0 ; substract now from start cmp.l #100,d0 ; 100*10ms = 1s blt.b .next bchg #1,$bfe001 move.l t10ms,d7 ; a new start .next: btst #6,$bfe001 bne.b .loop1 bsr myTimerRemove .clean_exit: moveq #0,d0 rts .error_exit: moveq #20,d0 rts ;------------------------------------------------------------------------------- ; CIA-A ($bfe001) serial/keyboard and timer.device ; CIA-B ($bfd000) both timer are free ; CIA-B is interrupt Level 6! ; one tick = 1.396825ms (clock interval is 279.365 nanoseconds) ; .715909 Mhz NTSC; .709379 Mhz PAL ; PAL 7093,79 ~ 7094 = 10ms | NTSC 7159,09 ~ 7159 = 10ms TIMER_INTERVAL equ 7094 ;TIMER_INTERVAL equ 16000 myTimerInstall: move.l execbase.w,a6 moveq #0,d0 lea ciab_name,a1 ; "ciab.resource" jsr _LVOOpenResource(a6) ; obtain ciab resource tst.l d0 ; 0 = error beq .exit move.l d0,cia_resource move.l d0,a6 moveq #2,d5 ; which timer moveq #CIAICRB_TB,d0 ; timer B lea myTimerInterruptStruct,a1 ; my interrupt struct lea myTimerInterruptName,a5 ; store name move.l a5,LN_NAME(a1) lea myTimerInterrupt,a5 ; store ptr to my routine move.l a5,IS_CODE(a1) jsr AddICRVector(a6) ; install interrupt (not starting) tst.l d0 ; 0 = successful beq.b .set_timer moveq #1,d5 moveq #CIAICRB_TA,d0 ; try timer A lea myTimerInterruptStruct,a1 jsr AddICRVector(a6) tst.l d0 ; 0 = succesful bne.b .error_exit ; now set timer .set_timer: move.w d5,cia_timer ; which timer do we got? lea ciab,a5 ; $bfd000 cmp.w #1,d5 ; 1 = timer A | 2 = timer B bgt.b .set_timer_b .set_timer_a: move.b #TIMER_INTERVAL&$ff,ciatalo(a5) ; low byte move.b #TIMER_INTERVAL>>8,ciatahi(a5) ; high byte bra.b .exit .set_timer_b: move.b #TIMER_INTERVAL&$ff,ciatblo(a5) ; low byte move.b #TIMER_INTERVAL>>8,ciatbhi(a5) ; high byte .exit: bsr StartTimer moveq #0,d0 rts .error_exit: moveq #-1,d0 rts ;------------------------------------------------------------------------------- StartTimer move.l cia_resource,a6 ; ciab.resource lea ciab,a5 ; $bfd000 move.w cia_timer,d0 cmp.w #1,d0 bgt.b .timer_b .timer_a: bclr #CIACRAB_RUNMODE,ciacra(a5) ; continous bset #CIACRAB_START,ciacra(a5) move.w #CLEAR|CIAICRF_TA,d0 jsr SetICR(a6) move.w #CIAICRF_SETCLR|CIAICRF_TA,d0 jsr AbleICR(a6) bra.b .exit .timer_b: bclr #CIACRBB_RUNMODE,ciacrb(a5) ; continous bset #CIACRBB_START,ciacrb(a5) move.w #CLEAR|CIAICRF_TB,d0 jsr SetICR(a6) move.w #CIAICRF_SETCLR|CIAICRF_TB,d0 jsr AbleICR(a6) .exit: rts ;------------------------------------------------------------------------------- StopTimer move.l cia_resource,a6 ; ciab.resource lea ciab,a5 ; $bfd000 move.w cia_timer,d0 cmp.w #1,d0 bgt.b .timer_b .timer_a: move.w #CLEAR|CIAICRF_TA,d0 ; stop timer A jsr AbleICR(a6) move.b #CIACRAF_START,d0 not.b d0 and.b d0,ciacra(a5) ; clear start bit in CRA bra.b .exit .timer_b: move.w #CLEAR|CIAICRF_TB,d0 ; stop timer B jsr AbleICR(a6) move.b #CIACRAF_START,d0 not.b d0 and.b d0,ciacrb(a5) ; clear start bit in CRB .exit: rts ;------------------------------------------------------------------------------- ; timer should be stopped before myTimerRemove: bsr StopTimer move.l cia_resource,a6 ; ciab.resource lea ciab,a5 ; $bfd000 move.w cia_timer,d0 cmp.w #1,d0 bgt.b .timer_b .timer_a: moveq #CIAICRB_TA,d0 ; try timer A lea myTimerInterruptStruct,a1 ; my interrupt struct jsr RemICRVector(a6) bra.b .exit .timer_b: moveq #CIAICRB_TB,d0 ; try timer A lea myTimerInterruptStruct,a1 ; my interrupt struct jsr RemICRVector(a6) .exit: rts ;------------------------------------------------------------------------------- ; FINALLY, it works - 29-06-13 myTimerInterrupt: ;tst.w 8(a1) ;beq.b .exit movem.l d2-d7/a2-a6,-(sp) add.l #1,t10ms movem.l (sp)+,d2-d7/a2-a6 moveq #1,d0 .exit: rts section data cia_resource: dc.l 0 cia_timer: dc.w 0 ; 1 = timer A, 2 = timer B ciab_name: CIABNAME cnop 0,4 myTimerInterruptName: dc.b "HPN timer",0,0 cnop 0,4 myTimerInterruptStruct: dc.l 0 ; LN_SUCC dc.l 0 ; LN_PRED dc.b NT_INTERRUPT ; LN_TYPE dc.b 127 ; LN_PRI dc.l 0 ; LN_NAME ID String c-string dc.l 0 ; IS_DATA dc.l 0 ; IS_CODE t10ms: dc.l 0 ; every 10ms a tick |
04 July 2013, 07:40 | #2 |
Registered User
Join Date: Jun 2013
Location: Australia
Posts: 685
|
That's nice.
I assume because both chips are driven by the same clock, that those two timers can't go out of sync? |
04 July 2013, 09:39 | #3 |
Natteravn
Join Date: Nov 2009
Location: Herford / Germany
Posts: 2,581
|
Nice example.
Although in a real program you should avoid to save and restore registers which don't change. This wastes a lot of time each interrupt: Code:
myTimerInterrupt: ;tst.w 8(a1) ;beq.b .exit movem.l d2-d7/a2-a6,-(sp) add.l #1,t10ms movem.l (sp)+,d2-d7/a2-a6 moveq #1,d0 .exit: rts Last edited by prowler; 04 July 2013 at 21:19. Reason: Back-to-back posts merged. |
05 July 2013, 08:40 | #4 | |
Registered User
Join Date: Jun 2013
Location: Australia
Posts: 685
|
Quote:
I had the timers mixed up for the time of day clocks that the CIAs both have, and wondered if there was any use they could be put to other than tricking Action Replay cartridges. The best I can think of is a small memory, by setting differences between the two, that requires more memory for the routine that decodes it, than the extra memory it provides |
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
CIA chips | Yakumo9275 | support.Hardware | 3 | 23 March 2013 18:56 |
[WinUAE/A500] CIA A - Timer A INT2 problem | leoha | Coders. Asm / Hardware | 2 | 22 October 2012 10:18 |
A1200 possible CIA fault | edimax | support.Hardware | 11 | 20 May 2012 23:16 |
CIA timer interrupt handler called twice during mod playback | absence | Coders. General | 5 | 16 March 2009 18:55 |
CIA test | Toni Wilen | Coders. General | 13 | 03 March 2007 22:14 |
|
|