]> git.sur5r.net Git - cc65/commitdiff
Added condes IRQ routines and a README file.
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 19 Sep 2001 10:01:52 +0000 (10:01 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Wed, 19 Sep 2001 10:01:52 +0000 (10:01 +0000)
Made k_blncur a condes IRQ routine and moved it to cgetc.s.
Added mouse and joystick routines.

git-svn-id: svn://svn.cc65.org/cc65/trunk@951 b7a2c559-68d2-44c3-8de9-860c34a00d81

libsrc/cbm510/Makefile
libsrc/cbm510/README [new file with mode: 0644]
libsrc/cbm510/cgetc.s
libsrc/cbm510/io.inc
libsrc/cbm510/kblncur.s [deleted file]
libsrc/cbm510/kirq.s
libsrc/cbm510/mouse.s [new file with mode: 0644]
libsrc/cbm510/readjoy.s [new file with mode: 0644]

index 50fdf623ca189fe15d198c081f90ee81969b5a0e..3db93aacfd71aa7c7e2b538fcff49f00b00324e9 100644 (file)
@@ -21,13 +21,14 @@ OBJS =      _scrsize.o      \
        cputc.o         \
                crt0.o          \
                kbhit.o         \
-       kblncur.o       \
                kirq.o          \
                kplot.o         \
        kscnkey.o       \
        kudtim.o        \
+       mouse.o         \
        peeksys.o       \
        pokesys.o       \
+       readjoy.o       \
        rs232.o
 
 all:   $(OBJS)
diff --git a/libsrc/cbm510/README b/libsrc/cbm510/README
new file mode 100644 (file)
index 0000000..d22b481
--- /dev/null
@@ -0,0 +1,8 @@
+Implementation notes:
+
+CONDES routines with a type code of 2 are used to implement interrupt
+handlers. Note that these are called as soon as the program is started,
+so they have to cope with this. The indirect segment is set to the 
+system bank when calling interrupt routines, this must must not be changed
+when returning.
+
index 4cb75ccb46a5e296fe83b4e8016d279b836966b4..1e966341d8e4cd97a944b05637af8755048d5b43 100644 (file)
@@ -5,6 +5,7 @@
 ;
 
        .export         _cgetc
+       .condes         k_blncur, 2
        .import         cursor
 
        .include        "zeropage.inc"
@@ -90,6 +91,61 @@ L4:          lda     KeyBuf+1,x      ; Move up the remaining chars
 
 @L9:   sty     CURS_FLAG               ; Cursor on (Y = 0)
        rts
+                                  
+.endproc
+
+
+; ------------------------------------------------------------------------
+; Blink the cursor in the interrupt. A blinking cursor is only available if
+; we use the cgetc() function, so we will export this IRQ handler only in
+; case the module is included into a program.
+
+
+.proc   k_blncur
+
+        lda     CURS_FLAG              ; Is the cursor on?
+        bne     curend                 ; Jump if not
+        dec     CURS_BLINK
+        bne     curend
+
+; Re-initialize the blink counter
+
+        lda     #20                    ; Initial value
+        sta     CURS_BLINK
+
+; Load Y with the cursor X coordinate
+
+       ldy     CURS_X
+
+; Check if the cursor state was on or off before
+
+       lda     CURS_COLOR              ; Load color behind cursor
+       lsr     CURS_STATE              ; Cursor currently displayed?
+       bcs     curset                  ; Jump if yes
+
+; Cursor was off before, switch it on
+
+       inc     CURS_STATE              ; Mark as displayed
+       lda     (CRAM_PTR),y            ; Get color behind cursor...
+       sta     CURS_COLOR              ; ...and remember it
+       lda     CHARCOLOR               ; Use character color
+
+; Set the cursor with color in A
+
+curset:        sta     (CRAM_PTR),y            ; Store cursor color
+       lda     ExecReg
+       sta     IndReg                  ; Switch to our segment
+       lda     (SCREEN_PTR),y
+       eor     #$80                    ; Toggle reverse flag
+       sta     (SCREEN_PTR),y
+
+; Switch back to the system bank
+
+       lda     #$0F
+       sta     IndReg
+
+curend:        rts
 
 .endproc
 
+
index 9f9939d9e03cce63ac415b52981bfd8ffe72be39..3d1422d86ca9874b5c53020ccbd76977f434a986 100644 (file)
@@ -63,58 +63,50 @@ VIC_BG_COLOR3       = $24
 
 ; I/O  $da00: SID 6581
 
-;      sid             =       $da00
-
-       Osc1            =       $00
-       Osc2            =       $07
-       Osc3            =       $0e
-
-       FreqLo          =       $00
-       FreqHi          =       $01
-       PulseF          =       $02
-       PulseC          =       $03
-       OscCtl          =       $04
-       AtkDcy          =       $05
-       SusRel          =       $06
-
-       FiCtlLo         =       $15
-       FiCtlHi         =       $16
-       Resonance       =       $17
-       Volume          =       $18
-       PotX            =       $19
-       PotY            =       $1A
-       Random          =       $1B
-       Env3            =       $1C
-
+SID_S1Lo               = $00
+SID_S1Hi               = $01
+SID_PB1Lo              = $02
+SID_PB1Hi              = $03
+SID_Ctl1               = $04
+SID_AD1                = $05
+SID_SUR1               = $06
+
+SID_S2Lo               = $07
+SID_S2Hi               = $08
+SID_PB2Lo              = $09
+SID_PB2Hi              = $0A
+SID_Ctl2               = $0B
+SID_AD2                = $0C
+SID_SUR2               = $0D
+
+SID_S3Lo               = $0E
+SID_S3Hi               = $0F
+SID_PB3Lo              = $10
+SID_PB3Hi              = $11
+SID_Ctl3               = $12
+SID_AD3                = $13
+SID_SUR3               = $14
+
+SID_FltLo              = $15
+SID_FltHi              = $16
+SID_FltCtl             = $17
+SID_Amp                = $18
+SID_ADConv1            = $19
+SID_ADConv2            = $1A
+SID_Noise              = $1B
+SID_Read3              = $1C
 
 
 ; I/O  $db00: CIA 6526 Inter Process Communication
-
-;      IPCcia          =       $db00
-
-       PortA           =       $00
-       PortB           =       $01
-       DDRA            =       $02
-       DDRB            =       $03
-       TimALo          =       $04
-       TimAHi          =       $05
-       TimBLo          =       $06
-       TimBHi          =       $07
-       TOD10           =       $08
-       TODsec          =       $09
-       TODmin          =       $0A
-       TODhour         =       $0B
-       SerDataReg      =       $0C
-       IntCtrReg       =       $0D
-       CtrlA           =       $0E
-       CtrlB           =       $0F
-
-
-
 ; I/O  $dc00: CIA 6526
 
-;      cia             =       $dc00
-
+CIA_PRA                = $00
+CIA_PRB                = $01
+CIA_DDRA               = $02
+CIA_DDRB       = $03
+CIA_ICR                = $0D
+CIA_CRA                = $0E
+CIA_CRB                = $0F
 
 
 ; I/O  $dd00: ACIA 6551
diff --git a/libsrc/cbm510/kblncur.s b/libsrc/cbm510/kblncur.s
deleted file mode 100644 (file)
index 11b12fa..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-;
-; Ullrich von Bassewitz, 16.09.2001
-;
-
-       .export         k_blncur
-
-       .include        "zeropage.inc"
-
-
-; ------------------------------------------------------------------------
-; Blink the cursor in the interrupt
-
-.proc   k_blncur
-
-        lda     CURS_FLAG              ; Is the cursor on?
-        bne     curend                 ; Jump if not
-        dec     CURS_BLINK
-        bne     curend
-
-; Re-initialize the blink counter
-
-        lda     #20                    ; Initial value
-        sta     CURS_BLINK
-
-; Switch to the system bank, load Y with the cursor X coordinate
-
-       lda     #$0F
-       sta     IndReg                  ; Access system bank
-       ldy     CURS_X
-
-; Check if the cursor state was on or off before
-
-       lda     CURS_COLOR              ; Load color behind cursor
-       lsr     CURS_STATE              ; Cursor currently displayed?
-       bcs     curset                  ; Jump if yes
-
-; Cursor was off before, switch it on
-
-       inc     CURS_STATE              ; Mark as displayed
-       lda     (CRAM_PTR),y            ; Get color behind cursor...
-       sta     CURS_COLOR              ; ...and remember it
-       lda     CHARCOLOR               ; Use character color
-
-; Set the cursor with color in A
-
-curset:        sta     (CRAM_PTR),y            ; Store cursor color
-       lda     ExecReg
-       sta     IndReg                  ; Switch to our segment
-       lda     (SCREEN_PTR),y
-       eor     #$80                    ; Toggle reverse flag
-       sta     (SCREEN_PTR),y
-curend:        rts
-
-.endproc
-
-
index a2a0d2eec63a403e940df08c7255f478aeca4154..cd71693b2cb1b102ac19132941351633b5813fa9 100644 (file)
@@ -5,7 +5,9 @@
 ;
 
        .export         irq, nmi, k_irq, k_nmi
-       .import         k_blncur, k_scnkey, k_udtim, k_rs232
+       .import         k_scnkey, k_udtim, k_rs232
+       .import         condes
+       .import         __IRQFUNC_TABLE__, __IRQFUNC_COUNT__
        .importzp       tpi1
 
        .include        "zeropage.inc"
@@ -40,7 +42,7 @@
        and     #$10                    ; Test break flag
        bne     L1
        jmp     (IRQVec)
-L1:    jmp     (BRKVec)
+L1:    jmp     (BRKVec)
 
 .endproc
 
@@ -70,16 +72,26 @@ k_irq:
 ; -------------------------------------------------------------------------
 ; 50/60Hz interrupt
 
-       cmp     #%00000001              ; ticker irq?
+       cmp     #%00000001              ; ticker irq?
        bne     irq1
-       jsr     k_blncur                ; Blink the cursor
-       jsr     k_scnkey                ; Poll the keyboard
-        jsr    k_udtim                 ; Bump the time
+
+; Call user IRQ handlers if we have any
+
+       ldy     #<(__IRQFUNC_COUNT__*2)
+       beq     @L1
+               lda     #<__IRQFUNC_TABLE__
+       ldx     #>__IRQFUNC_TABLE__
+       jsr     condes                  ; Call the functions
+
+; Call replacement kernal IRQ routines
+
+@L1:   jsr     k_scnkey                ; Poll the keyboard
+        jsr    k_udtim                 ; Bump the time
 
 ; -------------------------------------------------------------------------
 ; UART interrupt
 
-irq1:  cmp     #%00010000              ; interrupt from uart?
+irq1:  cmp     #%00010000              ; interrupt from uart?
        bne     irqend
        jsr     k_rs232                 ; Read character from uart
 
diff --git a/libsrc/cbm510/mouse.s b/libsrc/cbm510/mouse.s
new file mode 100644 (file)
index 0000000..9ff1a4d
--- /dev/null
@@ -0,0 +1,498 @@
+;
+; Ullrich von Bassewitz, 19.09.2001
+;
+; Routines for the 1351 proportional mouse. Parts of the code are from
+; the Commodore 1351 mouse users guide.
+;
+
+       .export         _mouse_init, _mouse_done
+       .export         _mouse_hide, _mouse_show
+       .export         _mouse_box, _mouse_info
+       .export         _mouse_move, _mouse_pos
+       .export         _mouse_buttons, _mouse_info
+       .condes         MouseIRQ, 2
+
+       .import         _readjoy
+       .import         sys_bank, restore_bank
+               .import         popax, addysp1
+       .importzp       vic, sid, ptr1, sp
+
+       .include        "zeropage.inc"
+       .include        "io.inc"
+
+       .macpack        generic
+
+
+.code
+
+; --------------------------------------------------------------------------
+;
+; Constants
+;
+
+SPRITE_HEIGHT          = 21
+SPRITE_WIDTH   = 24
+SCREEN_HEIGHT  = 200
+SCREEN_WIDTH   = 320
+XCORR          = SPRITE_WIDTH
+
+; --------------------------------------------------------------------------
+;
+; unsigned char __fastcall__ mouse_init (unsigned char type);
+;
+
+.proc  _mouse_init
+               lda     Initialized             ; Already initialized?
+               bne     AlreadyInitialized      ; Jump if yes
+
+; Initialize variables
+
+               ldx     #0
+       lda     #XCORR
+               sta     XPos
+       stx     XPos+1
+       stx     YPos
+       stx     YPos+1
+       stx     OldPotX
+       stx     OldPotY
+               stx     XMin
+       stx     XMin+1                  ; XMin = 0
+       lda     #50                     ; ## FIXME: This is the PAL value
+       sta     YCorr
+       sta     YPos
+       stx     YPos+1
+       sec
+        sbc            #SPRITE_HEIGHT          ; Sprite height in pixels
+       sta     YMin
+       stx     YMin+1                  ; YMin = 29
+       lda     #SCREEN_HEIGHT          ; Vertical screen res
+       add     YCorr                   ; Add correction factor
+       sta     YMax
+       stx     YMax+1
+       inx                             ; X = 1
+               stx     Invisible               ; Mouse *not* visible
+       lda     #<(SCREEN_WIDTH + SPRITE_WIDTH)
+       sta     XMax
+       stx     XMax+1                  ; XMax = 320 + sprite width
+
+; Mouse successfully initialized
+
+        lda     #1
+       sta     Initialized
+       rts
+
+AlreadyInitialized:
+       lda     #0                      ; Error
+       rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+;
+; void mouse_done (void);
+;
+
+_mouse_done:
+
+       lda     #0
+               sta     Initialized             ; Reset the initialized flag
+
+; Disable the mouse sprite
+
+DisableSprite:
+
+       ldx     IndReg
+       lda     #$0F
+       sta     IndReg                  ; Switch to the system bank
+
+       ldy     #VIC_SPR_ENA
+       sei                             ; Disable interrupts
+       lda     (vic),y
+       and     #$FE                    ; Clear bit for sprite #0
+       sta     (vic),y                 ; Disable sprite
+       cli                             ; Enable interrupts
+
+       stx     IndReg                  ; Switch back the segment
+       rts
+
+; --------------------------------------------------------------------------
+;
+; void mouse_hide (void);
+;
+
+.proc  _mouse_hide
+
+               lda     Invisible               ; Get the flag
+       bne     @L1                     ; Jump if already invisible
+       jsr     DisableSprite           ; Disabe the mouse sprite
+@L1:   inc     Invisible               ; Set the flag to invisible
+       rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+;
+; void mouse_show (void);
+;
+
+.proc  _mouse_show
+
+       lda     Invisible               ; Mouse invisible?
+       beq     @L1                     ; Jump if no
+               dec     Invisible               ; Set the flag
+       bne     @L1                     ; Jump if still invisible
+
+       jsr     sys_bank                ; Switch to the system bank
+
+               sei                             ; Disable interrupts
+       jsr     MoveSprite1             ; Move the sprite to it's position
+       ldy     #VIC_SPR_ENA
+               lda     (vic),y                 ; Get sprite enable register
+       ora     #$01                    ; Enable sprite #0
+               sta     (vic),y                 ; Write back
+       cli                             ; Enable interrupts
+
+       jsr     restore_bank            ; Switch back the bank
+
+@L1:   rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_box (int minx, int miny, int maxx, int maxy);
+;
+
+.proc  _mouse_box
+
+       ldy     #0                      ; Stack offset
+
+       add     YCorr                   ; Adjust the Y value
+       bcc     @L1
+       inx
+        clc
+@L1:   sei                             ; Disable interrupts
+
+       sta     YMax
+       stx     YMax+1                  ; maxy
+
+       lda     (sp),y
+       adc     #XCORR
+       sta     XMax
+       iny
+       lda     (sp),y
+       adc     #$00
+       sta     XMax+1                  ; maxx
+
+       iny
+       lda     (sp),y
+       add     YCorr
+       sta     YMin
+       iny
+       lda     (sp),y
+       adc     #$00
+       sta     YMin+1                  ; miny
+
+       iny
+       lda     (sp),y
+       add     #XCORR
+       sta     XMin
+       iny
+       lda     (sp),y
+       adc     #$00
+       sta     XMin+1                  ; minx
+
+       cli                             ; Enable interrupts
+
+       jmp     addysp1                 ; Drop params, return
+
+.endproc
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_pos (struct mouse_pos* pos);
+; /* Return the current mouse position */
+;
+
+.proc  _mouse_pos
+
+               sta     ptr1
+       stx     ptr1+1                  ; Remember the argument pointer
+
+       ldy     #0                      ; Structure offset
+       sec                             ; Needed for the SBC later
+
+       sei                             ; Disable interrupts
+       lda     XPos                    ; Transfer the position
+       sbc     #XCORR
+       sta     (ptr1),y
+       lda     XPos+1
+       sbc     #$00
+       iny
+       sta     (ptr1),y
+       lda     YPos
+       ldx     YPos+1
+       cli                             ; Restore initial interrupt state
+
+       sub     YCorr                   ; Apply the Y correction value
+       bcs     @L1
+       dex
+@L1:           iny
+       sta     (ptr1),y                ; Store YPos
+       txa
+       iny
+       sta     (ptr1),y
+
+       rts                             ; Done
+
+.endproc
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_info (struct mouse_info* info);
+; /* Return the state of the mouse buttons and the position of the mouse */
+;
+
+.proc  _mouse_info
+
+; We're cheating here to keep the code smaller: The first fields of the
+; mouse_info struct are identical to the mouse_pos struct, so we will just
+; call _mouse_pos to initialize the struct pointer and fill the position
+; fields.
+
+        jsr    _mouse_pos
+
+; Fill in the button state
+
+       jsr     _mouse_buttons          ; Will not touch ptr1
+       ldy     #4
+       sta     (ptr1),y
+
+       rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+;
+; void __fastcall__ mouse_move (int x, int y);
+;
+
+.proc  _mouse_move
+
+       add     YCorr                   ; Add Y coordinate correction
+       bcc     @L1
+       inx
+       clc
+@L1:   sei
+       sta     YPos
+       stx     YPos+1
+       cli
+
+       jsr     popax                   ; Get X
+       adc     #XCORR                  ; Adjust X coordinate
+       bcc     @L2
+       inx
+@L2:   jsr     sys_bank
+       sei
+       sta     XPos
+       stx     XPos+1                  ; Set new position
+       jsr     MoveSprite              ; Move the sprite to the mouse pos
+       cli                             ; Enable interrupts
+       jsr     restore_bank
+
+       rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+;
+; unsigned char mouse_buttons (void);
+;
+
+.proc  _mouse_buttons
+
+       lda     #$00                    ; Use port #0
+       jmp     _readjoy                ; Same as joystick
+
+.endproc
+
+
+; --------------------------------------------------------------------------
+;
+; Mouse interrupt handler
+;
+
+IRQDone:rts
+
+MouseIRQ:
+       lda     Initialized             ; Mouse initialized?
+               beq     IRQDone                 ; Jump if no
+
+       ldy     #SID_ADConv1
+       lda     (sid),y                 ; Get mouse X movement
+       ldy     OldPotX
+       jsr     MoveCheck               ; Calculate movement vector
+       sty     OldPotX
+
+; Calculate the new X coordinate (--> a/y)
+
+               add     XPos
+       tay                             ; Remember low byte
+       txa
+       adc     XPos+1
+       tax
+
+; Limit the X coordinate to the bounding box
+
+       cpy     XMin
+       sbc     XMin+1
+       bpl     @L1
+               ldy     XMin
+               ldx     XMin+1
+       jmp     @L2
+@L1:   txa
+
+       cpy     XMax
+       sbc     XMax+1
+       bmi     @L2
+       ldy     XMax
+       ldx     XMax+1
+@L2:   sty     XPos
+       stx     XPos+1
+
+; Calculate the Y movement vector
+
+       ldy     #SID_ADConv2
+               lda     (sid),y                 ; Get mouse Y movement
+       ldy     OldPotY
+       jsr     MoveCheck               ; Calculate movement
+       sty     OldPotY
+
+; Calculate the new Y coordinate (--> a/y)
+
+       sta     OldValue
+       lda     YPos
+       sub     OldValue
+       tay
+       stx     OldValue
+       lda     YPos+1
+       sbc     OldValue
+       tax
+
+       cpy     YMin
+       sbc     YMin+1
+       bpl     @L3
+               ldy     YMin
+               ldx     YMin+1
+       jmp     @L4
+@L3:   txa
+
+       cpy     YMax
+       sbc     YMax+1
+       bmi     @L4
+       ldy     YMax
+       ldx     YMax+1
+@L4:   sty     YPos
+       stx     YPos+1
+
+; Move the mouse sprite to the current mouse position. Must be called
+; with interrupts off and the system bank enabled. MoveSprite1 is an entry
+; without checking.
+
+MoveSprite:
+
+       lda     Invisible               ; Mouse visible?
+               bne     Done                    ; Jump if no
+
+; Set the high X bit
+
+MoveSprite1:
+       ldy     #VIC_SPR_HI_X
+               lda     (vic),y                 ; Get high X bits of all sprites
+       and     #$FE                    ; Clear bit for sprite #0
+               ldx     XPos+1                  ; Test Y position
+       beq     @L5
+               ora     #$01                    ; Set high X bit
+@L5:   sta     (vic),y                 ; Set hi X sprite values
+
+; Set the low X byte
+
+       lda     XPos
+       ldy     #VIC_SPR0_X
+       sta     (vic),y                 ; Set low byte
+
+; Set the Y position
+
+               ldy     YPos+1                  ; Negative or too large?
+               bne     Done                    ; Jump if yes
+       lda     YPos
+       ldy     #VIC_SPR0_Y
+               sta     (vic),y                 ; Set Y position
+
+; Done
+
+Done:   rts
+
+; --------------------------------------------------------------------------
+;
+; Move check routine, called for both coordinates.
+;
+; Entry:       y = old value of pot register
+;              a = current value of pot register
+; Exit:                y = value to use for old value
+;              x/a = delta value for position
+;
+
+.proc  MoveCheck
+
+       sty     OldValue
+       sta     NewValue
+       ldx     #$00
+
+       sub     OldValue                ; a = mod64 (new - old)
+       and     #%01111111
+       cmp     #%01000000              ; if (a > 0)
+       bcs     @L1                     ;
+       lsr     a                       ;   a /= 2;
+       beq     @L2                     ;   if (a != 0)
+       ldy     NewValue                ;     y = NewValue
+       rts                             ;   return
+
+@L1:   ora     #%11000000              ; else or in high order bits
+       cmp     #$FF                    ; if (a != -1)
+       beq     @L2
+       sec
+       ror     a                       ;   a /= 2
+               dex                             ;   high byte = -1 (X = $FF)
+       ldy     NewValue
+       rts
+
+@L2:           txa                             ; A = $00
+       rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+; Data
+
+.bss
+
+Initialized:           .res    1               ; True if mouse initialized
+OldInitStatus: .res    1               ; Old IRQ flag value
+OldValue:      .res    1               ; Temp for MoveCheck routine
+NewValue:      .res    1               ; Temp for MoveCheck routine
+YCorr:         .res    1               ; Correction for Y coordinate
+
+Invisible:     .res    1               ; Is the mouse invisible?
+OldPotX:       .res    1               ; Old hw counter values
+OldPotY:       .res    1
+
+XPos:          .res    2               ; Current mouse position, X
+YPos:          .res    2               ; Current mouse position, Y
+
+XMin:          .res    2               ; X1 value of bounding box
+YMin:          .res    2               ; Y1 value of bounding box
+XMax:          .res    2               ; X2 value of bounding box
+YMax:          .res    2               ; Y2 value of bounding box
+
+
diff --git a/libsrc/cbm510/readjoy.s b/libsrc/cbm510/readjoy.s
new file mode 100644 (file)
index 0000000..0bbbd5c
--- /dev/null
@@ -0,0 +1,62 @@
+;
+; Ullrich von Bassewitz, 23.09.1998
+;
+; unsigned readjoy (unsigned char joy);
+;
+
+       .export         _readjoy
+       .import         sys_bank, restore_bank
+       .importzp       cia2, tmp1
+
+       .include        "io.inc"
+
+; ------------------------------------------------------------------------
+; unsigned __fastcall__ readjoy (unsigned char joy);
+
+
+.proc  _readjoy
+
+       jsr     sys_bank        ; Switch to the system bank
+               tax                     ; Save joystick number
+
+; Get the direction bits
+
+       ldy     #CIA_PRB
+       lda     (cia2),y        ; Read joystick inputs
+       sta     tmp1
+
+; Get the fire bits
+
+        ldy     #CIA_PRA
+       lda     (cia2),y
+
+; Make the result value
+
+       cpx     #$00            ; Joystick 0?
+       bne     @L1             ; Jump if no
+
+; Joystick 1, fire is in bit 6, direction in bit 0-3
+
+       asl     a
+       jmp     @L2
+
+; Joystick 2, fire is in bit 7, direction in bit 5-7
+
+@L1:    ldy     #$00           ; High byte of return value
+       lsr     tmp1
+       lsr     tmp1
+       lsr     tmp1
+               lsr     tmp1
+
+; Mask the relavant bits, get the fire bit
+
+@L2:   asl     a               ; Fire bit into carry
+       lda     tmp1
+       and     #$0F
+       bcc     @L3
+       ora     #$10
+@L3:   eor     #$1F            ; All bits are inverted
+       jmp     restore_bank
+
+.endproc
+