English Amiga Board


Go Back   English Amiga Board > Coders > Coders. Asm / Hardware

 
 
Thread Tools
Old 03 July 2013, 16:08   #1
Apollo
Registered User

Apollo's Avatar
 
Join Date: Sep 2008
Location: Germany
Age: 45
Posts: 126
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
Apollo is offline  
Old 04 July 2013, 07:40   #2
xArtx
Registered User
 
Join Date: Jun 2013
Location: Australia
Posts: 679
That's nice.
I assume because both chips are driven by the same clock,
that those two timers can't go out of sync?
xArtx is offline  
Old 04 July 2013, 09:39   #3
phx
Natteravn

phx's Avatar
 
Join Date: Nov 2009
Location: Herford / Germany
Posts: 1,449
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
Quote:
Originally Posted by xArtx View Post
I assume because both chips are driven by the same clock,
that those two timers can't go out of sync?
Yes. All timers use the same 02 clock (0.7 MHz). Alternatively you can let the timers count positive CNT transitions on the serial port. And timer B can also count timer A underflows.

Last edited by prowler; 04 July 2013 at 21:19. Reason: Back-to-back posts merged.
phx is offline  
Old 05 July 2013, 08:40   #4
xArtx
Registered User
 
Join Date: Jun 2013
Location: Australia
Posts: 679
Quote:
Originally Posted by phx View Post
Nice example.

Yes. All timers use the same 02 clock (0.7 MHz). Alternatively you can let the timers count positive CNT transitions on the serial port. And timer B can also count timer A underflows.
Ah, then you can make one wider timer.
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
xArtx is offline  
 


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

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT +2. The time now is 05:06.


Powered by vBulletin® Version 3.8.11
Copyright ©2000 - 2019, vBulletin Solutions Inc.
Page generated in 0.05979 seconds with 13 queries