home *** CD-ROM | disk | FTP | other *** search
- 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
-