From 3bfbaee6a66a34e8dab0c5a5c4653f96f704d598 Mon Sep 17 00:00:00 2001 From: cuz Date: Sun, 21 Mar 2004 22:12:06 +0000 Subject: [PATCH] Working on loadable mouse drivers git-svn-id: svn://svn.cc65.org/cc65/trunk@2953 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- asminc/mouse-kernel.inc | 17 +- include/mouse.h | 29 +-- libsrc/c64/.cvsignore | 1 + libsrc/c64/Makefile | 13 +- libsrc/c64/c64-1351.s | 365 ++++++++++++++++++++++++++++++++++++ libsrc/c64/mcbdefault.s | 103 ++++++++++ libsrc/mouse/Makefile | 3 +- libsrc/mouse/mouse-kernel.s | 57 ++++-- libsrc/mouse/mouse_load.c | 10 +- libsrc/mouse/mouse_unload.s | 35 ++++ 10 files changed, 595 insertions(+), 38 deletions(-) create mode 100644 libsrc/c64/c64-1351.s create mode 100644 libsrc/c64/mcbdefault.s create mode 100644 libsrc/mouse/mouse_unload.s diff --git a/asminc/mouse-kernel.inc b/asminc/mouse-kernel.inc index ae3b26f7d..20596f142 100644 --- a/asminc/mouse-kernel.inc +++ b/asminc/mouse-kernel.inc @@ -6,7 +6,7 @@ ;/* */ ;/* */ ;/* */ -;/* (C) 2003 Ullrich von Bassewitz */ +;/* (C) 2003-2004 Ullrich von Bassewitz */ ;/* Römerstraße 52 */ ;/* D-70794 Filderstadt */ ;/* EMail: uz@cc65.org */ @@ -75,10 +75,22 @@ .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 @@ -113,7 +125,6 @@ MOUSE_BTN_RIGHT = $01 ;------------------------------------------------------------------------------ ; C callable functions - .global _mouse_set_callbacks .global _mouse_load_driver .global _mouse_unload .global _mouse_install diff --git a/include/mouse.h b/include/mouse.h index decca012d..edb4e0d4e 100644 --- a/include/mouse.h +++ b/include/mouse.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 2003 Ullrich von Bassewitz */ +/* (C) 2003-2004 Ullrich von Bassewitz */ /* Römerstraße 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -82,12 +82,20 @@ struct mouse_callbacks { 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; + /*****************************************************************************/ @@ -96,20 +104,15 @@ struct mouse_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); diff --git a/libsrc/c64/.cvsignore b/libsrc/c64/.cvsignore index 581e5ff62..3eecd7b49 100644 --- a/libsrc/c64/.cvsignore +++ b/libsrc/c64/.cvsignore @@ -1,4 +1,5 @@ *.emd *.joy +*.mou *.ser *.tgi diff --git a/libsrc/c64/Makefile b/libsrc/c64/Makefile index 04e52681c..1dcfbca06 100644 --- a/libsrc/c64/Makefile +++ b/libsrc/c64/Makefile @@ -21,6 +21,9 @@ %.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 $@ $^ @@ -44,7 +47,7 @@ OBJS = _scrsize.o \ kbhit.o \ kernal.o \ mainargs.o \ - mouse.o \ + mcbdefault.o \ randomize.o \ revers.o \ sysuname.o \ @@ -57,6 +60,8 @@ EMDS = c64-georam.emd c64-ram.emd c64-ramcart.emd c64-reu.emd c64-vdc.emd 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 @@ -66,14 +71,14 @@ 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) diff --git a/libsrc/c64/c64-1351.s b/libsrc/c64/c64-1351.s new file mode 100644 index 000000000..6bd4cefe5 --- /dev/null +++ b/libsrc/c64/c64-1351.s @@ -0,0 +1,365 @@ +; +; 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 + 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 + diff --git a/libsrc/c64/mcbdefault.s b/libsrc/c64/mcbdefault.s new file mode 100644 index 000000000..44c911035 --- /dev/null +++ b/libsrc/c64/mcbdefault.s @@ -0,0 +1,103 @@ +; +; 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 + + + diff --git a/libsrc/mouse/Makefile b/libsrc/mouse/Makefile index 8b098b9ae..a2138d04a 100644 --- a/libsrc/mouse/Makefile +++ b/libsrc/mouse/Makefile @@ -24,7 +24,8 @@ S_OBJS = mouse-kernel.o \ mouse_info.o \ mouse_ioctl.o \ mouse_pos.o \ - mouse_show.o + mouse_show.o \ + mouse_unload.o #-------------------------------------------------------------------------- # Targets diff --git a/libsrc/mouse/mouse-kernel.s b/libsrc/mouse/mouse-kernel.s index 85acdfbf8..624088078 100644 --- a/libsrc/mouse/mouse-kernel.s +++ b/libsrc/mouse/mouse-kernel.s @@ -4,8 +4,8 @@ ; 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" @@ -42,15 +42,14 @@ mouse_sig: .byte $6d, $6f, $75, MOUSE_API_VERSION ; "mou", version ;---------------------------------------------------------------------------- -; 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 @@ -72,34 +71,62 @@ _mouse_install: 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. */ diff --git a/libsrc/mouse/mouse_load.c b/libsrc/mouse/mouse_load.c index 7fa114366..cbb7cecba 100644 --- a/libsrc/mouse/mouse_load.c +++ b/libsrc/mouse/mouse_load.c @@ -42,7 +42,13 @@ -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 = { @@ -69,7 +75,7 @@ unsigned char __fastcall__ mouse_load_driver (const char* name) if (Res == MLOAD_OK) { /* Check the driver signature, install the driver */ - return mouse_install (ctrl.module); + return mouse_install (c, ctrl.module); } } diff --git a/libsrc/mouse/mouse_unload.s b/libsrc/mouse/mouse_unload.s new file mode 100644 index 000000000..d70464732 --- /dev/null +++ b/libsrc/mouse/mouse_unload.s @@ -0,0 +1,35 @@ +; +; 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 #