home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Club Amiga de Montreal - CAM
/
CAM_CD_1.iso
/
files
/
532.lha
/
ClockTick
/
ClockTick.asm
< prev
next >
Wrap
Assembly Source File
|
1991-07-09
|
21KB
|
553 lines
TTL ClockTick
*
*******************************************************************************
* *
* ClockTick 1.2 *
* *
* Copyright (c) 1991 by Michael Sinz MKSoft Development *
* *
* AmigaDOS EXEC release 1.2 or greater... *
* *
*******************************************************************************
* *
* To assemble, I used CAPE 68K *
* *
* # CAPE 68k MakeFile rule... *
* .asm: *
* @CAsm -a $*.asm -i sys:lc/include -cqsy -o $*.o *
* @BLink $*.o lib lib:amiga.lib to $* sc sd nd *
* @List $* *
* *
* It should assemble without any problems on most 680x0 assemblers. *
* *
*******************************************************************************
* *
* This program installs a handler into the input food chain. *
* The handler changes the hands of the clock every time a time *
* tick comes down the chain. *
* *
* It uses the fact that SPRITES are hardware mapped bitmaps. If *
* the sprite system ever needs to be retargeted, this will no longer *
* work. (A2024 is already such a case) *
* *
* It also setfunctions the SetPointer() call and checks what the *
* the pointer looks like. If it is the standard clock busy pointer *
* from 2.0, it will change the SetPointer call to use the built in one *
* *
* When you run this program, it will allocate some CHIP memory and *
* some of PUBLIC memory to install the handler and images. *
* It then exits... *
* *
* It will not let itself be installed more than once... *
* *
*******************************************************************************
* *
* Reading legal mush can turn your brain into guacamole! *
* *
* So here is some of that legal mush: *
* *
* Permission is hereby granted to distribute this program's source *
* executable, and documentation for non-comercial purposes, so long as the *
* copyright notices are not removed from the sources, executable or *
* documentation. This program may not be distributed for a profit without *
* the express written consent of the author Michael Sinz. *
* *
* This program is not in the public domain. *
* *
* Fred Fish is expressly granted permission to distribute this program's *
* source and executable as part of the "Fred Fish freely redistributable *
* Amiga software library." *
* *
* Permission is expressly granted for this program and it's source to be *
* distributed as part of the Amicus Amiga software disks, and the *
* First Amiga User Group's Hot Mix disks. *
* *
*******************************************************************************
*
* The following INCLUDE files are needed to make this program assemble.
* They come with the Amiga Macro-Assembler Package.
*
NOLIST ; No need to list these
INCLUDE "exec/types.i"
INCLUDE "exec/libraries.i"
INCLUDE "exec/interrupts.i"
INCLUDE "exec/memory.i"
INCLUDE "exec/io.i"
INCLUDE "exec/ables.i"
INCLUDE "libraries/dosextens.i"
INCLUDE "devices/input.i"
INCLUDE "devices/inputevent.i"
INCLUDE 'intuition/intuitionbase.i'
INCLUDE 'intuition/intuition.i'
INCLUDE 'clocktick_rev.i'
LIST ; Ok, lets start the listing
*
*******************************************************************************
*
* The following defines control some minor features:
*
* If DO_MKSOFT_POINTER is defined, ClockTick will also replace the busy pointer
* of older MKSoft products. This pointer is the same as used in DiskSpeed 3.1.
* It will also notice busy pointers such as those in 1.2/1.3 Kickstart. Thus,
* ClockTick will even make those pointers "tick."
*
DO_MKSOFT_POINTER EQU 1
*
*******************************************************************************
*
* This is the only fixed address in the system and it even "floats"...
*
xref _AbsExecBase
*
*******************************************************************************
*
* Some macros that make calling the system routines easier...
*
CALLSYS MACRO
xref _LVO\1 ; Set the external reference
CALLLIB _LVO\1 ; Call the EXEC definied macro
ENDM
*
*******************************************************************************
* *
* Register usage through this system... *
* *
* a0 - Scrap *
* a1 - Scrap *
* a2 - IO Block *
* a3 - MsgPort *
* a4 - Task *
* a5 - New Memory *
* a6 - ExecBase pointer *
* a7 - Stack pointer... What else? *
* *
* d0 - Scrap *
* d1 - Scrap *
* d2 - Scrap *
* d3 - Scrap *
* d4 - Scrap *
* d5 - Scrap *
* d6 - Scrap *
* d7 - Zero... *
* *
*******************************************************************************
*
* Now, for the start of the code...
*
ClockTick: move.l _AbsExecBase,a6 ; Get the EXEC library base
*
clr.l d7 ; Clear d7...
*
move.l d7,a1 ; Clear a1
CALLSYS FindTask ; Get our task pointer...
move.l d0,a4 ; Now, move it to a1 for addressing use
lea pr_MsgPort(a4),a3
tst.l pr_CLI(a4) ; Check if this is a CLI task...
bne.s QuickCLI ; If so, skip the next section
*
*******************************************************************************
*
* This section deals with starting from the WorkBench...
* It is just here for completeness...
*
QuickWorkBench: move.l a3,a0 ; Get message port
CALLSYS WaitPort ; Wait for the WorkBench message...
move.l a3,a0 ; ...it's here, so let's get it
CALLSYS GetMsg ; off the message port...
bra.s QuickCont ; ...and go to the continue routine
*
*******************************************************************************
*
* The routine was started from the CLI (prefered)
* Let's store a NULL pointer so that there is no WB message...
*
QuickCLI: move.l d7,d0 ; No reply message...
*
*******************************************************************************
*
* Continue with the Quick initialization
*
QuickCont:
move.l d0,-(sp) ; Save the message pointer...
*
*******************************************************************************
*
* Check if we are running already...
*
lea portName(PC),a1 ; Get the special port name...
CALLSYS FindPort ; Look for it...
tst.l d0 ; If it is there, we are installed...
bne abortNoInput ; If installed, don't do it again...
*
lea InputBlock(pc),a2 ; Get the I/O block
move.b #NT_MESSAGE,LN_TYPE(a2) ; initialize it...
move.w #IOSTD_SIZE,MN_LENGTH(a2)
move.l a3,MN_REPLYPORT(a2) ; Our reply port...
*
lea inputName(pc),a0 ; Get input.device name
move.l d7,d0 ; Clear d0
move.l d7,d1 ; and d1
move.l a2,a1
CALLSYS OpenDevice ; a1 is still set to the I/O block
tst.l d0
bne abortNoInput
*
*******************************************************************************
*
* We now allocate and copy the image...
*
moveq.l #clockSize,d0 ; Size of memory
move.l d0,d6 ; Save it here...
moveq.l #MEMF_CHIP,d1 ; Type of memory...
CALLSYS AllocMem ; Allocate it
lea TheClockPtr(pc),a0 ; Get pointer to storage...
move.l d0,(a0) ; Save image pointer...
beq NormalExit ; No memory, no go...
move.l d0,a1 ; Get pointer...
lea TheClock(pc),a0 ; Original data...
subq.l #1,d6 ; Drop by 1...
CopyImageLoop: move.b (a0)+,(a1)+ ; Now copy it down
dbra d6,CopyImageLoop ; Copy all of it...
*
*******************************************************************************
*
* We now allocate and copy the handler...
*
move.l #CodeSize,d0 ; Size of memory
move.l d0,d6 ; Save it...
moveq.l #MEMF_PUBLIC,d1 ; Type of memory
CALLSYS AllocMem ; Get the memory
move.l d0,a5 ; Save it...
tst.l d0 ; Check it...
beq NormalExit ; No memory, no copy...
move.l d0,a1 ; Destination...
lea StartOfCode(pc),a0 ; Source
subq.l #1,d6 ; From 0 to n-1
CopyLoop: move.b (a0)+,(a1)+ ; Copy it...
dbra d6,CopyLoop ; All of it...
*
*******************************************************************************
*
* Now that the copy worked, we clear the local pointer...
*
lea TheClockPtr(pc),a0 ; Get address...
move.l d7,(a0) ; Clear it...
*
*******************************************************************************
*
* Ok, now we put our port name into the port list...
*
lea portOffset(a5),a0 ; Port structure address...
move.l a0,a1 ; Save it in a1...
move.w #MP_SIZE-1,d0 ; Size of message port...
ClearPort: move.b d7,(a0)+ ; Clear byte...
dbra d0,ClearPort ; Do all of it...
move.b d0,LN_PRI(a1) ; Set PRI to -1...
move.b #NT_MSGPORT,LN_TYPE(a1) ; Set type of node...
lea portNameOffset(a5),a0 ; Port name address...
move.l a0,LN_NAME(a1) ; Save pointer to name
CALLSYS AddPort ; Add it to the list...
*
*******************************************************************************
*
* Check to see if we are running in V37 ROM or better. If so,
* we want to call CacheClearU() to make sure we are safe on future
* hardware such as the 68040. This section of code assumes that
* a6 points at ExecBase. a0/a1/d0/d1 are trashed in CacheClearU()
*
cmpi.w #37,LIB_VERSION(a6) ; Check if exec is >= V37
bcs.s TooOld ; If less than V37, too old...
CALLSYS CacheClearU ; Clear the cache...
TooOld:
*
*******************************************************************************
*
* We also need to add our own input handler into the food chain...
*
lea HandlerOffset(a5),a0 ; Pointer to handler...
move.b #51,LN_PRI(a0) ; Handler priority
move.l a5,IS_DATA(a0) ; Handler data
addq.l #codeOffset,a5 ; Point at code...
move.l a5,IS_CODE(a0) ; Set the handler code pointer
subq.l #codeOffset,a5 ; Restore pointer...
move.l a2,a1 ; Get i/o block
move.l a0,IO_DATA(a1) ; Set the data address...
move.w #IND_ADDHANDLER,IO_COMMAND(a1) ; the ADD command...
CALLSYS DoIO ; All set, handler is running
*
*******************************************************************************
*
* Now, we patch intuition.library
*
* We do not close intuition.library since the patch will need to stay
* Also, we do not check the open of intuition.library as if it did not work,
* we are in more trouble than we could ever report (since not even alert would
* work since that uses intuition!)
*
lea intuitionName(pc),a1 ; We need to open
moveq.l #0,d0 ; any version of intuition
CALLSYS OpenLibrary ; We assume this works...
FORBID ; Stop task switching...
move.l d0,IBaseOffset(a5) ; Save IBase...
move.l d0,a1 ; Get ready for the
lea NewSetOffset(a5),a3 ; Pointer to new entry point
move.l a3,d0 ; Needed for SetFunction...
XREF _LVOSetPointer ; We need this reference...
lea _LVOSetPointer,a0 ; Function offset...
CALLSYS SetFunction ; Put me in...
subq.l #4,a3 ; Point at old pointer...
move.l d0,(a3) ; Save it...
CALLSYS Permit
*
*******************************************************************************
*
* The standard exit routines...
* Close anything that we have opened...
*
NormalExit:
move.l TheClockPtr(pc),d0 ; Get the first allocation...
beq.s NoFree ; If we don't need to free it
move.l d0,a1 ; Pointer to the memory...
move.l #clockSize,d0 ; Size of memory block...
CALLSYS FreeMem ; Free it...
*
NoFree: move.l a2,a1 ; Get I/O block...
CALLSYS CloseDevice ; Close the thing...
abortNoInput:
move.l (sp)+,d0 ; Get that message back
beq.s abortNoWB ; If none, we are done
move.l d0,a1 ; Get the pointer ready
FORBID ; manual says we must forbid...
CALLSYS ReplyMsg ; ...when returning WB message
abortNoWB:
rts ; RTS out of this task...
*
*******************************************************************************
*
* The input block...
*
InputBlock: ds.b IOSTD_SIZE
*
*******************************************************************************
*
* This is the mouse accel value...
*
StartOfCode: dc.w 0 ; Clock timer count...
*
*******************************************************************************
*
* This is the handler... It is the hardest working piece of code here...
*
MyHandler: move.l a0,-(sp) ; We MUST save what we play with...
*
*******************************************************************************
*
* Now, for the handler loop... We will look at every event that has been given
* to us.
*
HandlerLoop: cmpi.b #IECLASS_TIMER,ie_Class(a0) ; Check for timer
bne.s HandlerNext ; If skip it...
*
* if IECLASS_TIMER, we move the hands by one...
*
* Since we found a timer event, we do not need to check
* for more and thus we can trash all of the scrap registers...
*
move.w (a1),d0 ; Get clock word index...
addq.l #1,d0 ; Bump by 1...
moveq.l #15,d1 ; Mask value...
and.l d1,d0 ; Mask it to the 0-15 range...
move.w d0,(a1) ; Store it...
moveq.l #changeSize,d1 ; The amount to change...
mulu d1,d0 ; Get offset...
move.l TheClockPtr(pc),a1 ; Get clock image...
lea changeOffset(a1),a1 ; Get change area
lea Clock0(pc),a0 ; Get first clock
add.l d0,a0 ; Point to real one...
moveq.l #(changeSize/4)-1,d1 ; Number of long-words (-1)
CopyClock: move.l (a0)+,(a1)+ ; Copy the words that changed
dbra d1,CopyClock ; in the clock...
bra.s NoMoreEvents
*
* Check for next event...
*
HandlerNext:
move.l ie_NextEvent(a0),d0 ; Get next event...
move.l d0,a0
bne.s HandlerLoop ; Go back and do this one...
NoMoreEvents:
move.l (sp)+,d0 ; Restore our stuff... d0=a0...
rts ; Done with handler...
*
*******************************************************************************
*
* SetPointer( Window, Pointer, Height, Width, XOffset, YOffset )
* A0 A1 D0 D1 D2 D3
*
OldSetPointer: dc.l 0
NewSetPointer: move.l OldSetPointer(pc),-(sp) ; We will return to old code
movem.l a2/a3/d0/d1/d2/d3,-(sp) ; We need these...
move.l a1,d0 ; If no pointer, skip...
beq.s EndSet ; ...
cmp.l TheClockPtr(pc),d0 ; Check if it is "ours"
beq.s EndSet ; If so, we don't do this...
*
*******************************************************************************
*
* This section checks for the MKSoft ZZZ busy pointer and replaces it too.
* (That pointer is available in the Diskspeed 3.1 source)
*
IFD DO_MKSOFT_POINTER
lea changeOffset(a1),a2 ; Point at the changes area
lea OldZZZ(pc),a3 ; Point at old image
moveq.l #(changeSize/4)-1,d1 ; Number of long-words (-1)
ZZZCheckLoop: move.l (a2)+,d0 ; Get real value...
sub.l (a3)+,d0 ; Subtract expected value...
dbne d1,ZZZCheckLoop ; Check some more...
beq.s ReplaceImage ; If not same, we bail...
*
* Now check for old workbench ZZZ cloud...
*
lea changeOffset(a1),a2 ; Point at the changes area
lea WB_ZZZ(pc),a3 ; Point at old image
moveq.l #(changeSize/4)-1,d1 ; Number of long-words (-1)
WB_CheckLoop: move.l (a2)+,d0 ; Get real value...
sub.l (a3)+,d0 ; Subtract expected value...
dbne d1,WB_CheckLoop ; Check some more...
beq.s ReplaceImage ; If not same, we bail...
ENDC
*
*******************************************************************************
*
* Now, check the area where the hands are and see if it is the same as
* our pointer. We do not check the whole pointer since we do not have
* one available. This should be enough of a check anyway.
*
lea changeOffset(a1),a2 ; Point at the changes area
lea Clock0(pc),a3 ; Point at our version
moveq.l #(changeSize/4)-1,d1 ; Number of long-words (-1)
CheckLoop: move.l (a2)+,d0 ; Get real value...
sub.l (a3)+,d0 ; Subtract expected value...
dbne d1,CheckLoop ; Check some more...
bne.s EndSet ; If not same, we bail...
*
* We found a clock that looks like ours...
* So, we now change the SetPointer() parameters to match our
* pointer parameters and call the "real" SetPointer()
*
ReplaceImage: move.l TheClockPtr(pc),a1 ; Get our replacement...
moveq.l #16,d0 ; Set our height
move.l d0,d1 ; and width
moveq.l #-6,d2 ; and XOffset
moveq.l #0,d3 ; and YOffset
move.l OldSetPointer(pc),a2 ; Get address...
jsr (a2) ; Call it...
*
* This is a nasty trick: We just did the SetPointer() with our values
* and do not want to do it again. Since the address we will RTS to
* is that of the old code, we will change the address on the stack to
* point at our RTS instruction and thus make it a NOP.
*
lea EndSetRTS(pc),a2 ; Get blank RTS...
move.l a2,6*4(sp) ; Change the return address...
*
* Now restore back to the caller's registers and get out...
*
EndSet: movem.l (sp)+,a2/a3/d0/d1/d2/d3 ; Restore data...
EndSetRTS: rts ; Return to old code...
*
*******************************************************************************
*
* Pointer to the CHIP memory clock image
*
TheClockPtr: dc.l 0 ; Pointer to clock image...
IBase: dc.l 0 ; IBase pointer...
*
*******************************************************************************
*
* These are the clock images. Clock0 is the one used to compare with
* the given clock... (Clock numbers 0 to 15)
*
Clock0: dc.l $1FF03FEC,$3FF87FDE,$3FF87FBE,$7FFCFF7F,$7EFCFFFF,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
Clock1: dc.l $1FF03FFC,$3FF87FFE,$3FF87FE6,$7FFCFF9F,$7EFCFF7F,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCFF07,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCFF7F,$7FFCFF9F,$3FF87FE6,$3FF87FFE,$1FF03FFC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCFFFF,$7FFCFF7F,$3FF87FBE,$3FF87FDE,$1FF03FEC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCFFFF,$7FFCFF7F,$3FF87F7E,$3FF87FBE,$1FF03FBC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCFFFF,$7FFCFEFF,$3FF87EFE,$3FF87EFE,$1FF03EFC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCFFFF,$7FFCFDFF,$3FF87DFE,$3FF87BFE,$1FF03BFC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCFFFF,$7FFCFDFF,$3FF87BFE,$3FF877FE,$1FF02FFC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCFDFF,$7FFCF3FF,$3FF84FFE,$3FF87FFE,$1FF03FFC
dc.l $1FF03FFC,$3FF87FFE,$3FF87FFE,$7FFCFFFF,$7EFCC1FF,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
dc.l $1FF03FFC,$3FF87FFE,$3FF84FFE,$7FFCF3FF,$7EFCFDFF,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
dc.l $1FF02FFC,$3FF877FE,$3FF87BFE,$7FFCFDFF,$7EFCFFFF,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
dc.l $1FF03BFC,$3FF87BFE,$3FF87DFE,$7FFCFDFF,$7EFCFFFF,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
dc.l $1FF03EFC,$3FF87EFE,$3FF87EFE,$7FFCFEFF,$7EFCFFFF,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
dc.l $1FF03FBC,$3FF87FBE,$3FF87F7E,$7FFCFF7F,$7EFCFFFF,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
*
*******************************************************************************
*
* This is the section of the pointer that needs to match the MKSoft pointer
*
IFD DO_MKSOFT_POINTER
OldZZZ: dc.l $FBFCFFFC,$70FC7FFC,$7FFE7FFE,$7F0E7FFE,$3FDF3FFF,$7FBE7FFE,$3F0E3FFE,$1FFC1FFC,$07F807F8
WB_ZZZ: dc.l $7BF87FF8,$F7F8FFF8,$61FC7FFC,$7F0C7FFC,$3FDE3FFE,$7FBC7FFC,$3F0C3FFC,$1FF81FF8,$07F007F0
ENDC
*
*******************************************************************************
*
HandlerInfo: ds.b IS_SIZE ; The handler structure...
*
portStruct ds.b MP_SIZE ; The message port structure...
*
portName dc.b 'MKSoft ClockTick Installed',0
*
EndOfCode:
*
*******************************************************************************
*
* This is the clock image that will be used to replace clocks from the
* SetPointer call...
*
ds.w 0
TheClock: dc.l 0,$040007C0,$000007C0,$01000380,$000007E0,$07C01FF8
ChangeArea: dc.l $1FF03FEC,$3FF87FDE,$3FF87FBE,$7FFCFF7F,$7EFCFFFF,$7FFCFFFF,$3FF87FFE,$3FF87FFE,$1FF03FFC
ClockBottom: dc.l $07C01FF8,$000007E0,0
TheClockEnd:
*
*******************************************************************************
*
* The data section...
*
inputName dc.b 'input.device',0
intuitionName dc.b 'intuition.library',0
VERSTAG
*
*******************************************************************************
*
* Now some offset type symbols...
*
CodeSize EQU EndOfCode-StartOfCode
HandlerOffset EQU HandlerInfo-StartOfCode
portOffset EQU portStruct-StartOfCode
portNameOffset EQU portName-StartOfCode
NewSetOffset EQU NewSetPointer-StartOfCode
changeSize EQU Clock1-Clock0
changeOffset EQU ChangeArea-TheClock
codeOffset EQU MyHandler-StartOfCode
IBaseOffset EQU IBase-StartOfCode
clockSize EQU TheClockEnd-TheClock
*
*******************************************************************************
*
* "A master's secrets are only as good as the
* master's ability to explain them to others." - Michael Sinz
*
*******************************************************************************
*
* And, with that we come to the end of another full-length feature staring
* that wonderful MC680x0 and the Amiga system. Join us again next time
* for more Wonderful World of Amiga...
*
end