View Single Post
Old 03 July 2013, 16:08   #1
Apollo
Registered User
 
Apollo's Avatar
 
Join Date: Sep 2008
Location: Germany
Age: 49
Posts: 138
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  
 
Page generated in 0.04719 seconds with 11 queries