From 2b098710d9a151232e4477dcad2b7bad4ecd69d4 Mon Sep 17 00:00:00 2001 From: uz Date: Tue, 5 Aug 2008 20:54:35 +0000 Subject: [PATCH] Added Koala Pad mouse drivers written by Stefan Haubenthal. git-svn-id: svn://svn.cc65.org/cc65/trunk@3877 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- doc/c128.sgml | 18 +- doc/c64.sgml | 7 +- libsrc/Makefile | 2 + libsrc/c128/Makefile | 2 +- libsrc/c128/c128-potmouse.s | 371 ++++++++++++++++++++++++++++++++++++ libsrc/c64/Makefile | 2 +- libsrc/c64/c64-potmouse.s | 371 ++++++++++++++++++++++++++++++++++++ 7 files changed, 767 insertions(+), 6 deletions(-) create mode 100644 libsrc/c128/c128-potmouse.s create mode 100644 libsrc/c64/c64-potmouse.s diff --git a/doc/c128.sgml b/doc/c128.sgml index 37c428d12..174ffdcc0 100644 --- a/doc/c128.sgml +++ b/doc/c128.sgml @@ -57,7 +57,7 @@ Special locations: Mouse drivers

-Currently no drivers available (in fact, the API for loadable mouse drivers -does not exist). + + + + Supports a standard mouse connected to port #0 of the C128. + + + Supports a mouse emulated by a standard joystick e.g. 1350 mouse in port + #1 of the C128. + + + Supports a potentiometer device e.g. Koala Pad connected to port #1 of + the C128. + +

RS232 device drivers

diff --git a/doc/c64.sgml b/doc/c64.sgml index c058f73f3..370cb4422 100644 --- a/doc/c64.sgml +++ b/doc/c64.sgml @@ -233,7 +233,12 @@ configuration. Supports a standard mouse connected to port #0 of the C64. - Supports a mouse emulated by a standard joystick in port #0 of the C64. + Supports a mouse emulated by a standard joystick e.g. 1350 mouse in port + #1 of the C64. + + + Supports a potentiometer device e.g. Koala Pad connected to port #1 of + the C64.

diff --git a/libsrc/Makefile b/libsrc/Makefile index 8fb21da0e..f134e6040 100644 --- a/libsrc/Makefile +++ b/libsrc/Makefile @@ -117,6 +117,7 @@ c64lib: cp c64/*.joy . cp c64/c64-1351.mou . cp c64/c64-joymouse.mou c64-joy.mou + cp c64/c64-potmouse.mou c64-pot.mou cp c64/*.ser . cp c64/c64-320-200-2.tgi c64-hi.tgi @@ -133,6 +134,7 @@ c128lib: cp c128/*.joy . cp c128/c128-1351.mou . cp c128/c128-joymouse.mou c128-joy.mou + cp c128/c128-potmouse.mou c128-pot.mou cp c128/*.ser . cp c128/c128-640-200-2.tgi c128-vdc.tgi cp c128/c128-640-480-2.tgi c128-vdc2.tgi diff --git a/libsrc/c128/Makefile b/libsrc/c128/Makefile index 46f229c0c..87df0f76e 100644 --- a/libsrc/c128/Makefile +++ b/libsrc/c128/Makefile @@ -74,7 +74,7 @@ EMDS = c128-georam.emd c128-ram.emd c128-ramcart.emd c128-reu.emd c128-vdc.emd JOYS = c128-ptvjoy.joy c128-stdjoy.joy -MOUS = c128-1351.mou c128-joymouse.mou +MOUS = c128-1351.mou c128-joymouse.mou c128-potmouse.mou SERS = c128-swlink.ser diff --git a/libsrc/c128/c128-potmouse.s b/libsrc/c128/c128-potmouse.s new file mode 100644 index 000000000..fdb45763b --- /dev/null +++ b/libsrc/c128/c128-potmouse.s @@ -0,0 +1,371 @@ +; +; Driver for a potentiometer "mouse" e.g. Koala Pad +; +; Ullrich von Bassewitz, 2004-03-29 +; Stefan Haubenthal, 2006-08-20 +; + + .include "zeropage.inc" + .include "mouse-kernel.inc" + .include "c128.inc" + + .macpack generic + +; ------------------------------------------------------------------------ +; Header. Includes jump table + +.segment "JUMPTABLE" + +HEADER: + +; Driver signature + + .byte $6d, $6f, $75 ; "mou" + .byte MOUSE_API_VERSION ; Mouse driver API version number + +; Jump table. + + .addr INSTALL + .addr UNINSTALL + .addr HIDE + .addr SHOW + .addr BOX + .addr MOVE + .addr BUTTONS + .addr POS + .addr INFO + .addr IOCTL + .addr IRQ + +; Callback table, set by the kernel before INSTALL is called + +CHIDE: jmp $0000 ; Hide the cursor +CSHOW: jmp $0000 ; Show the cursor +CMOVEX: jmp $0000 ; Move the cursor to X coord +CMOVEY: jmp $0000 ; Move the cursor to Y coord + + +;---------------------------------------------------------------------------- +; Constants + +SCREEN_HEIGHT = 200 +SCREEN_WIDTH = 320 + +.enum JOY + UP = $01 + DOWN = $02 + LEFT = $04 + RIGHT = $08 + FIRE = $10 +.endenum + +;---------------------------------------------------------------------------- +; Global variables. The bounding box values are sorted so that they can be +; written with the least effort in the BOX routine, so don't reorder them. + +.bss + +Vars: +YPos: .res 2 ; Current mouse position, Y +XPos: .res 2 ; Current mouse position, X +YMax: .res 2 ; Y2 value of bounding box +XMax: .res 2 ; X2 value of bounding box +YMin: .res 2 ; Y1 value of bounding box +XMin: .res 2 ; X1 value of bounding box +Buttons: .res 1 ; Button mask + +; Temporary value used in the int handler + +Temp: .res 1 + +; Default values for above variables + +.rodata + +.proc DefVars + .word SCREEN_HEIGHT/2 ; YPos + .word SCREEN_WIDTH/2 ; XPos + .word SCREEN_HEIGHT ; YMax + .word SCREEN_WIDTH ; XMax + .word 0 ; YMin + .word 0 ; XMin + .byte 0 ; Buttons +.endproc + +.code + +;---------------------------------------------------------------------------- +; INSTALL routine. Is called after the driver is loaded into memory. If +; possible, check if the hardware is present. +; Must return an MOUSE_ERR_xx code in a/x. + +INSTALL: + +; Initialize variables. Just copy the default stuff over + + ldx #.sizeof(DefVars)-1 +@L1: lda DefVars,x + sta Vars,x + dex + bpl @L1 + +; Be sure the mouse cursor is invisible and at the default location. We +; need to do that here, because our mouse interrupt handler doesn't set the +; mouse position if it hasn't changed. + + sei + jsr CHIDE + lda XPos + ldx XPos+1 + jsr CMOVEX + lda YPos + ldx YPos+1 + jsr CMOVEY + cli + +; Done, return zero (= MOUSE_ERR_OK) + + ldx #$00 + txa + rts + +;---------------------------------------------------------------------------- +; UNINSTALL routine. Is called before the driver is removed from memory. +; No return code required (the driver is removed from memory on return). + +UNINSTALL = HIDE ; Hide cursor on exit + +;---------------------------------------------------------------------------- +; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages +; a counter for calls to show/hide, and the driver entry point is only called +; if the mouse is currently visible and should get hidden. For most drivers, +; no special action is required besides hiding the mouse cursor. +; No return code required. + +HIDE: sei + jsr CHIDE + cli + rts + +;---------------------------------------------------------------------------- +; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages +; a counter for calls to show/hide, and the driver entry point is only called +; if the mouse is currently hidden and should become visible. For most drivers, +; no special action is required besides enabling the mouse cursor. +; No return code required. + +SHOW: sei + jsr CSHOW + cli + rts + +;---------------------------------------------------------------------------- +; BOX: Set the mouse bounding box. The parameters are passed as they come from +; the C program, that is, maxy in a/x and the other parameters on the stack. +; The C wrapper will remove the parameters from the stack when the driver +; routine returns. +; No checks are done if the mouse is currently inside the box, this is the job +; of the caller. It is not necessary to validate the parameters, trust the +; caller and save some code here. No return code required. + +BOX: ldy #5 + sei + sta YMax + stx YMax+1 + +@L1: lda (sp),y + sta XMax,y + dey + bpl @L1 + + cli + rts + +;---------------------------------------------------------------------------- +; MOVE: Move the mouse to a new position. The position is passed as it comes +; from the C program, that is: X on the stack and Y in a/x. The C wrapper will +; remove the parameter from the stack on return. +; No checks are done if the new position is valid (within the bounding box or +; the screen). No return code required. +; + +MOVE: sei ; No interrupts + + sta YPos + stx YPos+1 ; New Y position + jsr CMOVEY ; Set it + + ldy #$01 + lda (sp),y + sta XPos+1 + tax + dey + lda (sp),y + sta XPos ; New X position + + jsr CMOVEX ; Move the cursor + + cli ; Allow interrupts + rts + +;---------------------------------------------------------------------------- +; BUTTONS: Return the button mask in a/x. + +BUTTONS: + lda Buttons + ldx #$00 + rts + +;---------------------------------------------------------------------------- +; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1. +; No return code required. + +POS: ldy #MOUSE_POS::XCOORD ; Structure offset + + sei ; Disable interrupts + lda XPos ; Transfer the position + sta (ptr1),y + lda XPos+1 + iny + sta (ptr1),y + lda YPos + iny + sta (ptr1),y + lda YPos+1 + cli ; Enable interrupts + + iny + sta (ptr1),y ; Store last byte + + rts ; Done + +;---------------------------------------------------------------------------- +; INFO: Returns mouse position and current button mask in the MOUSE_INFO +; struct pointed to by ptr1. No return code required. +; +; 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. + +INFO: jsr POS + +; Fill in the button state + + lda Buttons + ldy #MOUSE_INFO::BUTTONS + sta (ptr1),y + + rts + +;---------------------------------------------------------------------------- +; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl +; specific data in ptr1, and the ioctl code in A. +; Must return an error code in a/x. +; + +IOCTL: lda #MOUSE_ERR_INV_IOCTL + rts + +;---------------------------------------------------------------------------- +; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context +; (so be careful). +; + +IRQ: lda #$7F + sta CIA1_PRA + lda CIA1_PRB ; Read port #1 + and #%00001100 + eor #%00001100 ; Make all bits active high + asl + sta Buttons + lsr + lsr + lsr + and #%00000001 + ora Buttons + sta Buttons + ldx #%01000000 + stx CIA1_PRA + ldy #0 +: dey + bne :- + ldx SID_ADConv1 + stx XPos + ldx SID_ADConv2 + stx YPos + + lda #$FF + tax + bne @AddX ; Branch always + lda #$01 + ldx #$00 + +; Calculate the new X coordinate (--> a/y) + +@AddX: 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 + +; Move the mouse pointer to the new X pos + + tya + jsr CMOVEX + + lda #$FF + tax + bne @AddY +@Down: lda #$01 + ldx #$00 + +; Calculate the new Y coordinate (--> a/y) + +@AddY: add YPos + tay ; Remember low byte + txa + adc YPos+1 + tax + +; Limit the Y coordinate to the bounding box + + 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 pointer to the new X pos + + tya + jmp CMOVEY diff --git a/libsrc/c64/Makefile b/libsrc/c64/Makefile index ca0e27852..90b5c3ebb 100644 --- a/libsrc/c64/Makefile +++ b/libsrc/c64/Makefile @@ -72,7 +72,7 @@ EMDS = c64-georam.emd c64-ram.emd c64-ramcart.emd c64-reu.emd c64-vdc.emd dtv-hi JOYS = c64-hitjoy.joy c64-numpad.joy c64-ptvjoy.joy c64-stdjoy.joy -MOUS = c64-1351.mou c64-joymouse.mou +MOUS = c64-1351.mou c64-joymouse.mou c64-potmouse.mou SERS = c64-swlink.ser diff --git a/libsrc/c64/c64-potmouse.s b/libsrc/c64/c64-potmouse.s new file mode 100644 index 000000000..cd2bc9543 --- /dev/null +++ b/libsrc/c64/c64-potmouse.s @@ -0,0 +1,371 @@ +; +; Driver for a potentiometer "mouse" e.g. Koala Pad +; +; Ullrich von Bassewitz, 2004-03-29 +; Stefan Haubenthal, 2006-08-20 +; + + .include "zeropage.inc" + .include "mouse-kernel.inc" + .include "c64.inc" + + .macpack generic + +; ------------------------------------------------------------------------ +; Header. Includes jump table + +.segment "JUMPTABLE" + +HEADER: + +; Driver signature + + .byte $6d, $6f, $75 ; "mou" + .byte MOUSE_API_VERSION ; Mouse driver API version number + +; Jump table. + + .addr INSTALL + .addr UNINSTALL + .addr HIDE + .addr SHOW + .addr BOX + .addr MOVE + .addr BUTTONS + .addr POS + .addr INFO + .addr IOCTL + .addr IRQ + +; Callback table, set by the kernel before INSTALL is called + +CHIDE: jmp $0000 ; Hide the cursor +CSHOW: jmp $0000 ; Show the cursor +CMOVEX: jmp $0000 ; Move the cursor to X coord +CMOVEY: jmp $0000 ; Move the cursor to Y coord + + +;---------------------------------------------------------------------------- +; Constants + +SCREEN_HEIGHT = 200 +SCREEN_WIDTH = 320 + +.enum JOY + UP = $01 + DOWN = $02 + LEFT = $04 + RIGHT = $08 + FIRE = $10 +.endenum + +;---------------------------------------------------------------------------- +; Global variables. The bounding box values are sorted so that they can be +; written with the least effort in the BOX routine, so don't reorder them. + +.bss + +Vars: +YPos: .res 2 ; Current mouse position, Y +XPos: .res 2 ; Current mouse position, X +YMax: .res 2 ; Y2 value of bounding box +XMax: .res 2 ; X2 value of bounding box +YMin: .res 2 ; Y1 value of bounding box +XMin: .res 2 ; X1 value of bounding box +Buttons: .res 1 ; Button mask + +; Temporary value used in the int handler + +Temp: .res 1 + +; Default values for above variables + +.rodata + +.proc DefVars + .word SCREEN_HEIGHT/2 ; YPos + .word SCREEN_WIDTH/2 ; XPos + .word SCREEN_HEIGHT ; YMax + .word SCREEN_WIDTH ; XMax + .word 0 ; YMin + .word 0 ; XMin + .byte 0 ; Buttons +.endproc + +.code + +;---------------------------------------------------------------------------- +; INSTALL routine. Is called after the driver is loaded into memory. If +; possible, check if the hardware is present. +; Must return an MOUSE_ERR_xx code in a/x. + +INSTALL: + +; Initialize variables. Just copy the default stuff over + + ldx #.sizeof(DefVars)-1 +@L1: lda DefVars,x + sta Vars,x + dex + bpl @L1 + +; Be sure the mouse cursor is invisible and at the default location. We +; need to do that here, because our mouse interrupt handler doesn't set the +; mouse position if it hasn't changed. + + sei + jsr CHIDE + lda XPos + ldx XPos+1 + jsr CMOVEX + lda YPos + ldx YPos+1 + jsr CMOVEY + cli + +; Done, return zero (= MOUSE_ERR_OK) + + ldx #$00 + txa + rts + +;---------------------------------------------------------------------------- +; UNINSTALL routine. Is called before the driver is removed from memory. +; No return code required (the driver is removed from memory on return). + +UNINSTALL = HIDE ; Hide cursor on exit + +;---------------------------------------------------------------------------- +; HIDE routine. Is called to hide the mouse pointer. The mouse kernel manages +; a counter for calls to show/hide, and the driver entry point is only called +; if the mouse is currently visible and should get hidden. For most drivers, +; no special action is required besides hiding the mouse cursor. +; No return code required. + +HIDE: sei + jsr CHIDE + cli + rts + +;---------------------------------------------------------------------------- +; SHOW routine. Is called to show the mouse pointer. The mouse kernel manages +; a counter for calls to show/hide, and the driver entry point is only called +; if the mouse is currently hidden and should become visible. For most drivers, +; no special action is required besides enabling the mouse cursor. +; No return code required. + +SHOW: sei + jsr CSHOW + cli + rts + +;---------------------------------------------------------------------------- +; BOX: Set the mouse bounding box. The parameters are passed as they come from +; the C program, that is, maxy in a/x and the other parameters on the stack. +; The C wrapper will remove the parameters from the stack when the driver +; routine returns. +; No checks are done if the mouse is currently inside the box, this is the job +; of the caller. It is not necessary to validate the parameters, trust the +; caller and save some code here. No return code required. + +BOX: ldy #5 + sei + sta YMax + stx YMax+1 + +@L1: lda (sp),y + sta XMax,y + dey + bpl @L1 + + cli + rts + +;---------------------------------------------------------------------------- +; MOVE: Move the mouse to a new position. The position is passed as it comes +; from the C program, that is: X on the stack and Y in a/x. The C wrapper will +; remove the parameter from the stack on return. +; No checks are done if the new position is valid (within the bounding box or +; the screen). No return code required. +; + +MOVE: sei ; No interrupts + + sta YPos + stx YPos+1 ; New Y position + jsr CMOVEY ; Set it + + ldy #$01 + lda (sp),y + sta XPos+1 + tax + dey + lda (sp),y + sta XPos ; New X position + + jsr CMOVEX ; Move the cursor + + cli ; Allow interrupts + rts + +;---------------------------------------------------------------------------- +; BUTTONS: Return the button mask in a/x. + +BUTTONS: + lda Buttons + ldx #$00 + rts + +;---------------------------------------------------------------------------- +; POS: Return the mouse position in the MOUSE_POS struct pointed to by ptr1. +; No return code required. + +POS: ldy #MOUSE_POS::XCOORD ; Structure offset + + sei ; Disable interrupts + lda XPos ; Transfer the position + sta (ptr1),y + lda XPos+1 + iny + sta (ptr1),y + lda YPos + iny + sta (ptr1),y + lda YPos+1 + cli ; Enable interrupts + + iny + sta (ptr1),y ; Store last byte + + rts ; Done + +;---------------------------------------------------------------------------- +; INFO: Returns mouse position and current button mask in the MOUSE_INFO +; struct pointed to by ptr1. No return code required. +; +; 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. + +INFO: jsr POS + +; Fill in the button state + + lda Buttons + ldy #MOUSE_INFO::BUTTONS + sta (ptr1),y + + rts + +;---------------------------------------------------------------------------- +; IOCTL: Driver defined entry point. The wrapper will pass a pointer to ioctl +; specific data in ptr1, and the ioctl code in A. +; Must return an error code in a/x. +; + +IOCTL: lda #MOUSE_ERR_INV_IOCTL + rts + +;---------------------------------------------------------------------------- +; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context +; (so be careful). +; + +IRQ: lda #$7F + sta CIA1_PRA + lda CIA1_PRB ; Read port #1 + and #%00001100 + eor #%00001100 ; Make all bits active high + asl + sta Buttons + lsr + lsr + lsr + and #%00000001 + ora Buttons + sta Buttons + ldx #%01000000 + stx CIA1_PRA + ldy #0 +: dey + bne :- + ldx SID_ADConv1 + stx XPos + ldx SID_ADConv2 + stx YPos + + lda #$FF + tax + bne @AddX ; Branch always + lda #$01 + ldx #$00 + +; Calculate the new X coordinate (--> a/y) + +@AddX: 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 + +; Move the mouse pointer to the new X pos + + tya + jsr CMOVEX + + lda #$FF + tax + bne @AddY +@Down: lda #$01 + ldx #$00 + +; Calculate the new Y coordinate (--> a/y) + +@AddY: add YPos + tay ; Remember low byte + txa + adc YPos+1 + tax + +; Limit the Y coordinate to the bounding box + + 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 pointer to the new X pos + + tya + jmp CMOVEY -- 2.39.5