diff --git a/libsrc/cbm510/Makefile b/libsrc/cbm510/Makefile
index 50fdf623c..3db93aacf 100644
--- a/libsrc/cbm510/Makefile
+++ b/libsrc/cbm510/Makefile
@@ -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
index 000000000..d22b48168
--- /dev/null
+++ b/libsrc/cbm510/README
@@ -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.
+
diff --git a/libsrc/cbm510/cgetc.s b/libsrc/cbm510/cgetc.s
index 4cb75ccb4..1e966341d 100644
--- a/libsrc/cbm510/cgetc.s
+++ b/libsrc/cbm510/cgetc.s
@@ -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
 
+
diff --git a/libsrc/cbm510/io.inc b/libsrc/cbm510/io.inc
index 9f9939d9e..3d1422d86 100644
--- a/libsrc/cbm510/io.inc
+++ b/libsrc/cbm510/io.inc
@@ -63,58 +63,50 @@ VIC_BG_COLOR3  	= $24
 
 ; I/O  $da00: SID 6581
 
-; 	sid		=	$da00
+SID_S1Lo       	= $00
+SID_S1Hi       	= $01
+SID_PB1Lo      	= $02
+SID_PB1Hi      	= $03
+SID_Ctl1       	= $04
+SID_AD1	       	= $05
+SID_SUR1       	= $06
 
- 	Osc1		=	$00
- 	Osc2		=	$07
- 	Osc3		=	$0e
+SID_S2Lo       	= $07
+SID_S2Hi       	= $08
+SID_PB2Lo      	= $09
+SID_PB2Hi      	= $0A
+SID_Ctl2       	= $0B
+SID_AD2	       	= $0C
+SID_SUR2       	= $0D
 
- 	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_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
index 11b12fa48..000000000
--- a/libsrc/cbm510/kblncur.s
+++ /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
-
-
diff --git a/libsrc/cbm510/kirq.s b/libsrc/cbm510/kirq.s
index a2a0d2eec..cd71693b2 100644
--- a/libsrc/cbm510/kirq.s
+++ b/libsrc/cbm510/kirq.s
@@ -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
index 000000000..9ff1a4dc8
--- /dev/null
+++ b/libsrc/cbm510/mouse.s
@@ -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
index 000000000..0bbbd5c30
--- /dev/null
+++ b/libsrc/cbm510/readjoy.s
@@ -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
+