;/* */
;/* */
;/* */
-;/* (C) 2003 Ullrich von Bassewitz */
+;/* (C) 2003-2004 Ullrich von Bassewitz */
;/* Römerstraße 52 */
;/* D-70794 Filderstadt */
;/* EMail: uz@cc65.org */
.byte
CSHOW .addr
.byte
- CMOVE .addr
+ CMOVEX .addr
+ .byte
+ CMOVEY .addr
.endstruct
.endstruct
+;------------------------------------------------------------------------------
+; The mouse callback structure
+
+.struct MOUSE_CALLBACKS
+ HIDE .addr ; Hide the mouse cursor
+ SHOW .addr ; Show the mouse cursor
+ MOVEX .addr ; Move the mouse cursor
+ MOVEY .addr ; Dito for Y
+.endstruct
+
;------------------------------------------------------------------------------
; The mouse API version, stored in MOUSE_HDR::VERSION
;------------------------------------------------------------------------------
; C callable functions
- .global _mouse_set_callbacks
.global _mouse_load_driver
.global _mouse_unload
.global _mouse_install
/* */
/* */
/* */
-/* (C) 2003 Ullrich von Bassewitz */
+/* (C) 2003-2004 Ullrich von Bassewitz */
/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
void (*show) (void);
/* Show the mouse cursor */
- void (*move) (void);
- /* Move the mouse cursor. This function is called, even when the cursor
- * is currently invisible.
+ void (*movex) (void);
+ /* Move the mouse cursor to the new X coordinate. This function is called,
+ * even when the cursor is currently invisible.
+ */
+
+ void (*movey) (void);
+ /* Move the mouse cursor to the new Y coordinate. This function is called,
+ * even when the cursor is currently invisible.
*/
};
+/* The default mouse callbacks */
+extern const struct mouse_callbacks mouse_def_callbacks;
+
/*****************************************************************************/
-void __fastcall__ mouse_set_callbacks (const struct mouse_callbacks* c);
-/* Sets the callbacks to be used by the driver. NOTE: The function will just
- * remember the pointer, it will not copy the contents of the passed struct.
- * The latter is done in mouse_install. This means that the struct must be
- * valid at least until mouse_install is called. Do not use a local variable!
- */
-
-unsigned char __fastcall__ mouse_load_driver (const char* driver);
+unsigned char __fastcall__ mouse_load_driver (const struct mouse_callbacks* c,
+ const char* driver);
/* Load and install a mouse driver, return an error code. */
unsigned char __fastcall__ mouse_unload (void);
/* Uninstall, then unload the currently loaded driver. */
-unsigned char __fastcall__ mouse_install (void* driver);
+unsigned char __fastcall__ mouse_install (const struct mouse_callbacks* c,
+ void* driver);
/* Install an already loaded driver. Returns an error code. */
unsigned char __fastcall__ mouse_uninstall (void);
*.emd
*.joy
+*.mou
*.ser
*.tgi
%.joy: %.o ../runtime/zeropage.o
@$(LD) -t module -o $@ $^
+%.mou: %.o ../runtime/zeropage.o
+ @$(LD) -t module -o $@ $^
+
%.ser: %.o ../runtime/zeropage.o
@$(LD) -t module -o $@ $^
kbhit.o \
kernal.o \
mainargs.o \
- mouse.o \
+ mcbdefault.o \
randomize.o \
revers.o \
sysuname.o \
JOYS = c64-hitjoy.joy c64-numpad.joy c64-ptvjoy.joy c64-stdjoy.joy
+MOUS = c64-1351.mou
+
SERS = c64-swlink.ser
TGIS = c64-320-200-2.tgi
.PHONY: all clean zap
-all: $(OBJS) $(EMDS) $(JOYS) $(SERS) $(TGIS)
+all: $(OBJS) $(EMDS) $(JOYS) $(MOUS) $(SERS) $(TGIS)
../runtime/zeropage.o:
$(MAKE) -C $(dir $@) $(notdir $@)
clean:
- @$(RM) $(OBJS) $(EMDS:.emd=.o) $(JOYS:.joy=.o) $(SERS:.ser=.o) $(TGIS:.tgi=.o)
+ @$(RM) $(OBJS) $(EMDS:.emd=.o) $(JOYS:.joy=.o) $(MOUS:.mou=.o) $(SERS:.ser=.o) $(TGIS:.tgi=.o)
zap: clean
- @$(RM) $(EMDS) $(JOYS) $(SERS) $(TGIS)
+ @$(RM) $(EMDS) $(JOYS) $(MOUS) $(SERS) $(TGIS)
--- /dev/null
+;
+; Driver for the 1351 proportional mouse. Parts of the code are from
+; the Commodore 1351 mouse users guide.
+;
+; Ullrich von Bassewitz, 2003-12-29
+;
+
+ .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
+
+; Data that is visible to the outside. Initialized by the kernel.
+
+XPos: .word 0 ; Current mouse position, X
+YPos: .word 0 ; Current mouse position, Y
+
+; 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
+
+;----------------------------------------------------------------------------
+;
+; Global variables
+;
+
+.bss
+
+Vars:
+OldPotX: .res 1 ; Old hw counter values
+OldPotY: .res 1
+
+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
+
+OldValue: .res 1 ; Temp for MoveCheck routine
+NewValue: .res 1 ; Temp for MoveCheck routine
+
+; Default values for above variables
+
+.rodata
+
+.proc DefVars
+ .byte 0, 0 ; OldPotX/OldPotY
+ .word 0, 0 ; XMin/YMin
+ .word SCREEN_WIDTH ; XMax
+ .word SCREEN_HEIGHT ; YMax
+.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
+
+; Done, return zero (= MOUSE_ERR_OK)
+
+ inx ; X = 0
+ txa
+; rts ; Run into UNINSTALL instead
+
+;----------------------------------------------------------------------------
+; UNINSTALL routine. Is called before the driver is removed from memory.
+; No return code required (the driver is removed from memory on return).
+
+UNINSTALL:
+ rts
+
+;----------------------------------------------------------------------------
+; 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 = CHIDE
+
+;----------------------------------------------------------------------------
+; 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 = CSHOW
+
+;----------------------------------------------------------------------------
+; BOX: Set the mouse bounding box. 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:
+ rts
+
+;----------------------------------------------------------------------------
+; MOVE: Move the mouse to a new position which is passed in X=ptr1, Y=a/x.
+; 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
+
+ lda ptr1
+ ldx ptr1+1
+ sta XPos
+ stx XPos+1 ; New X position
+
+ jsr CMOVEX ; Move the cursor
+
+ cli ; Allow interrupts
+ rts
+
+;----------------------------------------------------------------------------
+; BUTTONS: Return the button mask in a/x.
+
+BUTTONS:
+ lda #$7F
+ sei
+ sta CIA1_PRA
+ lda CIA1_PRB ; Read joystick #0
+ cli
+ ldx #0
+ and #$1F
+ eor #$1F
+ 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
+
+ jsr BUTTONS ; Will not touch ptr1
+ 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 ; We don't support ioclts for now
+ ldx #>MOUSE_ERR_INV_IOCTL
+ rts
+
+;----------------------------------------------------------------------------
+; IRQ: Irq handler entry point. Called as a subroutine but in IRQ context
+; (so be careful).
+;
+
+IRQ: lda SID_ADConv1 ; Get mouse X movement
+ ldy OldPotX
+ jsr MoveCheck ; Calculate movement vector
+ sty OldPotX
+
+; Skip processing if nothing has changed
+
+ tay
+ beq @SkipX
+
+; 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
+
+; Move the mouse pointer to the new X pos
+
+ tya
+ jsr CMOVEY
+
+; Calculate the Y movement vector
+
+@SkipX: lda SID_ADConv2 ; Get mouse Y movement
+ ldy OldPotY
+ jsr MoveCheck ; Calculate movement
+ sty OldPotY
+
+; Skip processing if nothing has changed
+
+ tay
+ beq @SkipY
+
+; Calculate the new Y coordinate (--> a/y)
+
+ sta OldValue
+ lda YPos
+ sub OldValue
+ tay
+ stx OldValue
+ lda YPos+1
+ sbc OldValue
+ 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
+ jsr CMOVEX
+
+; Done
+
+@SkipY: 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
+;
+
+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
+
--- /dev/null
+;
+; Default mouse callbacks for the C64
+;
+; Ullrich von Bassewitz, 2004-03-20
+;
+
+ .export _mouse_def_callbacks
+
+ .include "mouse-kernel.inc"
+ .include "c64.inc"
+
+
+; Sprite definitions. The first value can be changed to adjust the number
+; of the sprite used for the mouse.
+MOUSE_SPR = 0 ; Sprite used for the mouse
+MOUSE_SPR_MASK = $01 .shl MOUSE_SPR ; Positive mask
+MOUSE_SPR_NMASK = .lobyte(.not MOUSE_SPR_MASK) ; Negative mask
+VIC_SPR_X = (VIC_SPR0_X + 2*MOUSE_SPR) ; Sprite X register
+VIC_SPR_Y = (VIC_SPR0_Y + 2*MOUSE_SPR) ; Sprite Y register
+
+
+.code
+
+; --------------------------------------------------------------------------
+; Hide the mouse pointer
+
+.proc hide
+
+ lda #MOUSE_SPR_NMASK
+ sei
+ and VIC_SPR_ENA
+ sta VIC_SPR_ENA
+ cli
+ rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+; Show the mouse pointer
+
+.proc show
+
+ lda #MOUSE_SPR_MASK
+ sei
+ ora VIC_SPR_ENA
+ sta VIC_SPR_ENA
+ cli
+ rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+; Move the mouse pointer X position to the value in a/x
+
+.proc movex
+
+; Set the low byte, this frees A
+
+ sta VIC_SPR_X
+
+; Set the high byte
+
+ txa ; Test high byte of X coord
+ bne @L1
+ sei
+ lda VIC_SPR_HI_X ; Get high X bits of all sprites
+ and #MOUSE_SPR_NMASK ; Clear high bit for sprite
+ sta VIC_SPR_HI_X
+ cli
+ rts
+
+@L1: sei
+ lda VIC_SPR_HI_X ; Get high X bits of all sprites
+ ora #MOUSE_SPR_NMASK ; Set high bit for sprite
+ sta VIC_SPR_HI_X
+ cli
+ rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+; Move the mouse pointer Y position to the value in a/x
+
+.proc movey
+
+ sta VIC_SPR_Y ; Set Y position
+ rts
+
+.endproc
+
+; --------------------------------------------------------------------------
+; Callback structure
+
+.rodata
+
+_mouse_def_callbacks:
+ .addr hide
+ .addr show
+ .addr movex
+ .addr movey
+
+
+
mouse_info.o \
mouse_ioctl.o \
mouse_pos.o \
- mouse_show.o
+ mouse_show.o \
+ mouse_unload.o
#--------------------------------------------------------------------------
# Targets
; Common functions of the mouse driver API.
;
- .import return0
- .importzp ptr1
+ .import return0, popsreg, incsp2
+ .importzp sreg, ptr1, tmp1, tmp2
.condes mouse_irq, 2 ; Export as IRQ handler
.include "mouse-kernel.inc"
;----------------------------------------------------------------------------
-; unsigned char __fastcall__ mouse_install (void* driver);
+; unsigned char __fastcall__ mouse_install (const struct mouse_callbacks* c,
+; void* driver);
; /* Install an already loaded driver. Returns an error code. */
-
-
_mouse_install:
sta _mouse_drv
sta ptr1
- stx _mouse_drv+1
+ stx _mouse_drv+1
stx ptr1+1
; Check the driver signature
ldy #MOUSE_HDR::JUMPTAB
ldx #0
@L1: inx ; Skip the JMP opcode
- jsr copy ; Copy one byte
- jsr copy ; Copy one byte
+ jsr copyjv ; Copy one byte
+ jsr copyjv ; Copy one byte
cpy #(MOUSE_HDR::JUMPTAB + .sizeof(MOUSE_HDR::JUMPTAB))
bne @L1
- jsr mouse_install ; Call driver install routine
+; Copy the callback vectors into the driver space
+
+ jsr popsreg
+ ldy #(MOUSE_HDR::CALLBACKS + .sizeof(MOUSE_HDR::CALLBACKS) - 1)
+ sty tmp2
+ ldy #.sizeof(MOUSE_CALLBACKS)-1
+ sty tmp1
+
+@L2: jsr copycb
+ jsr copycb
+ dec tmp2 ; Skip opcode byte
+ ldy tmp1
+ bpl @L2
+
+; Call driver install routine
+
+ jsr mouse_install
+
+; Install the IRQ vector if the driver needs it. A/X contains the error code
+; from mouse_install, so don't use it.
ldy mouse_irq+2 ; Check high byte of IRQ vector
- beq @L2 ; Jump if vector invalid
- ldy #$4C ; Jump opcode
+ beq @L3 ; Jump if vector invalid
+ ldy #$4C ; Jump opcode
sty mouse_irq ; Activate IRQ routine
-@L2: rts
+@L3: rts
-; Driver signature invalid
+; Driver signature invalid. One word is still on the stack
inv_drv:
lda #MOUSE_ERR_INV_DRIVER
ldx #0
- rts
+ jmp incsp2
; Copy one byte from the jump vectors
-copy: lda (ptr1),y
+copyjv: lda (ptr1),y
sta mouse_vectors,x
iny
inx
rts
+; Copy one byte from the callback vectors
+
+copycb: lda (sreg),y
+ dec tmp1
+ ldy tmp2
+ sta (ptr1),y
+ dec tmp2
+ rts
+
;----------------------------------------------------------------------------
; unsigned char __fastcall__ mouse_uninstall (void);
; /* Uninstall the currently loaded driver. Returns an error code. */
-unsigned char __fastcall__ mouse_load_driver (const char* name)
+/* Use static local variables, since the module is not reentrant anyway */
+#pragma staticlocals (on);
+
+
+
+unsigned char __fastcall__ mouse_load_driver (const struct mouse_callbacks* c,
+ const char* name)
/* Load a mouse driver and return an error code */
{
static struct mod_ctrl ctrl = {
if (Res == MLOAD_OK) {
/* Check the driver signature, install the driver */
- return mouse_install (ctrl.module);
+ return mouse_install (c, ctrl.module);
}
}
--- /dev/null
+;
+; Ullrich von Bassewitz, 2004-03-21
+;
+; unsigned char __fastcall__ mouse_unload (void);
+; /* Uninstall, then unload the currently loaded driver. */
+
+
+ .import mouse_clear_ptr
+
+ .include "mouse-kernel.inc"
+ .include "modload.inc"
+
+
+_mouse_unload:
+ lda _mouse_drv
+ ora _mouse_drv+1
+ beq no_driver ; No driver
+
+ lda _mouse_drv
+ pha
+ lda _mouse_drv+1
+ pha ; Save pointer to driver
+
+ jsr _mouse_uninstall ; Uninstall the driver
+
+ pla
+ tax
+ pla ; Get pointer to driver
+ jmp _mod_free ; Free the driver
+
+no_driver:
+ tax ; X = 0
+ lda #<MOUSE_ERR_NO_DRIVER
+ rts
+