home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-08-16 | 209.3 KB | 7,594 lines |
- @a=fc0000
- ****************************************************************************
- * *
- * Comments copyright (c) 1989 Markus Wandel *
- * *
- * Release date: February 3, 1989. *
- * *
- * The following is a complete disassembly of the Amiga 1.2 "exec", as *
- * found on a kickstart disk for an Amiga 1000. Everything is shown, *
- * right down to the padding introduced by the linker, and unused code *
- * fragments which probably made it in by accident. *
- * *
- * Thorough familiarity with the Rom Kernel Manual: Exec, with suitable *
- * updates to version 1.2, and the exec subdirectory of the include files, *
- * is assumed in all comments. Where existing documentation appears to *
- * be inadequate, or a particular section of code is judged to be more *
- * interesting than most, comments are more extensive. *
- * *
- * Absolutely no guarantee is made of the correctness of all information *
- * supplied below, nor of its usefulness. *
- * *
- * Note that virtually all references to "ROM" actually refer to the *
- * write-protected RAM which the kickstart disk loads into. The genuine *
- * ROMs on Amiga 500 and 2000 computers may not contain exactly the same *
- * code, although most of it should be similar. *
- * *
- * The completed disassembly file is not redistributable, and contains *
- * code which is copyrighted by Commodore-Amiga, and comments which are *
- * copyrighted by Markus Wandel. The source file used to make the *
- * disassembly is distributable under a limited set of conditions as *
- * outlined in the accompanying documentation. *
- * *
- * For Commodore-Amiga's copyright notice, see a few lines farther down. *
- * *
- ****************************************************************************
-
- ; This match word is used when looking for ROMs.
-
- @8p@w
-
- ; The ROM can be started by jumping to its base address plus 2,
- ; or by mapping it at location zero and resetting. Either way,
- ; the machine starts running at FC00D2 (in the latter case, because
- ; the 68000's PC is loaded from location 4 at cold start).
-
- @d
- @a?fc0008
-
- @8p@28wGarbage.
- @8p@w
-
- ; The following version number doesn't appear to be used
- ; from within exec.library.
-
- @8p@w
- @8p@w
-
- ; The following version number appears in the exec.library
- ; node, and this copy is checked to ensure it is still valid.
-
- @8p@28wVersion.
- @8p@28wRevision.
-
- @8p@28lGarbage.
-
- ; The exec's ID string
- ; --------------------
-
- @8p@,28s
-
- @8p@28lGarbage.
-
- ; Copyright notice.
- ; -----------------
-
- @8p@,45s
- @8p@,43s
- @8p@,24s
-
- ; Library name
- ; ------------
-
- @8p@,14s
-
- ; The RomTag structure.
- ; ---------------------
-
- @8p@28wRTC_MATCHWORD (start of ROMTAG marker)
- @8p@28lRT_MATCHTAG (pointer RTC_MATCHWORD)
- @8p@28lRT_ENDSKIP (pointer to end of code)
- @8p@28bRT_FLAGS (no flags)
- @8p@28bRT_VERSION (version number)
- @8p@28bRT_TYPE (NT_LIBRARY)
- @8p@28bRT_PRI (priority = 126)
- @8p@28lRT_NAME (pointer to name)
- @8p@28lRT_IDSTRING (pointer to ID string)
- @8p@28lRT_INIT (execution address)
- @a?fc00d0
-
-
- @d
-
- ; We start running here.
-
- @36dSet stack pointer to top of first 128K.
- @d
- @36dDelay loop.
- @d
-
- ; If the ROM is also visible at F00000, or if there is another
- ; ROM there, jump there.
-
- @36dLoad base address of ROM we're in.
- @36dLoad (absolute address) F00000.
- @36dAre we at F00000?
- @36dIf so, don't execute the following.
- @36dThis is relative, i.e. always points
- 12 bytes down from where we are.
- @36dIf "1111" not found at F00000, then
- @36dcontinue running below, else start
- @36drunning at F00002.
-
- ; Set up port A on the first CIA (8520-A).
-
- @36dSet low two bits for output.
- @36dSet boot ROM off, power light dim.
-
- ; Disable interrupts and DMA.
-
- @36dBase address of custom chip area.
- @d
- @36dDisable all interrupts.
- @36dClear all pending interrupts.
- @36dDisable all DMA.
-
- ; Set a blank, dark gray display.
-
- @36dBPLCON0 = Blank screen.
- @36dBitplane 0 data = all zeros.
- @36dBackground colour = dark gray.
-
- ; Set up the Exception Vector Table. Vectors 2 through 47
- ; (Bus Error through TRAP #15) are all all set to the initial
- ; exception handler. If any exception occurs now, the screen
- ; will turn yellow, the power light will flash, and the computer
- ; will be reset.
-
- @36dStart at address 8 (vector #2).
- @36dDo 46 vectors.
- @36dAddress of initial exception handler.
- @36dSet one vector
- @36dLoop back.
-
- ; See if the system wants a guru put up after reboot.
-
- ; This works as follows: If for some reason, a guru can't be put
- ; up in the normal fashion, the system writes "HELP" at location
- ; zero, writes the alert data (number and 32-bit parameter) at
- ; location $000100, and resets.
-
- ; Early in the startup code (right here), this "HELP" is checked
- ; for. If it is present, it is removed, and the data at location
- ; $000100 is loaded into registers D6 and D7. If no "HELP" is
- ; found, register D6 is loaded with -1. This data will later be
- ; put at ExecBase->LastAlert, once the ExecBase structure has been
- ; built. The following subroutine call does all this.
-
- @36dCheck for "HELP" at location 0.
-
- ; Check whether there is already a valid ExecBase data structure.
- ; This is important, since it indicates whether we need to clear and
- ; reconfigure memory (wiping out recoverable RAM disks and such),
- ; or whether we already know the memory configuration and can leave
- ; it untouched.
-
- ; Note that if the machine crashed in such a way that the ExecBase
- ; structure got clobbered, memory will be cleared.
-
- @36dGet pointer at location 4.
- @36dCheck if it is an odd address.
- @36dGo reconfigure memory if it is.
- @36dAssume we are pointing to ExecBase.
- @36dGet complement of ExecBase.
- @36dCheck it.
- @36dGo reconfigure memory if it didn't match.
- @d
- @36dChecksum the static part of the ExecBase
- @36ddata structure.
- @d
- @d
- @36dVerify the checksum.
- @36dGo reconfigure memory if not valid.
-
- ; If we get this far, we are reasonably confident that the ExecBase
- ; structure is OK, and run the cold start capture code if there
- ; is any.
-
- @36dGet the cold start capture vector.
- @36dBranch if it is zero.
- @d
- @36dWhere to come back afterward.
- @36dClear the cold start capture vector.
- @36dJump to the cold start capture code.
-
- ; We come here if the cold start capture vector was zero, or
- ; upon return from the cold-start capture code. We continue
- ; to verify the ExecBase structure.
-
- @36dFlip the power light to bright.
-
- @36dCheck the version/revision numbers
- @36dstored in ExecBase against those in ROM.
- @36dGo reconfigure memory if no match.
-
- @36dGet end address of chip memory.
- @36dGreater than 512K?
- @36dIf so, it must be invalid.
- @36dLess than 256K?
- @36dIf so, it must be invalid.
-
- @36dGet end address of $C00000 memory.
- @d
- @36dAll OK if no $C00000 memory.
- @36dCheck more than 1.5 meg (invalid).
- @36dGo reconfigure memory if so.
- @36dCheck if less than 256K (invalid).
- @36dGo reconfigure memory if so.
- @d
- @36dCheck that ends on a 256K boundary.
- @36dAll OK if it does.
-
- ; If we come here, it was decided that there is no valid ExecBase
- ; data structure. This means we have to figure out what the memory
- ; configuration of the machine is.
-
- ; First, calculate ExecBase based on the assumption that the ExecBase
- ; structure will end up in chip RAM. This would put it at $0676,
- ; just far enough past the exception vector table to make room for
- ; the jump table.
-
- @36dCalculate $0676.
- @36d(don't ask me why they do it like this).
-
- ; Now go and check for memory in the $C00000 - $DC0000 area.
- ; This allows for a maximum of 1.75 megabytes of non-chip memory
- ; to be automatically configured if located at $C00000.
-
- @36dLower bound for $C00000 memory.
- @36dHigh bound for $C00000 memory.
- @36dReturn address.
- @36dGo check how much we have.
- @36dDid we find any expansion memory?
- @36dIf not, skip the following.
-
- ; The machine has expansion RAM at $C00000. We put the ExecBase
- ; structure there to save chip memory. This puts it at $C00276.
-
- @36dCalculate $C00276.
- @d
-
- ; Now we clear the expansion memory to zeros.
-
- @36dGet end address of expansion memory.
- @36dGet start address of expansion memory.
- @36dSet return address.
- @36dGo clear the memory.
-
- ; Having figured out the end address of expansion memory (in A4),
- ; and the value to use for ExecBase (in A6), we now check how much
- ; chip memory we have. Any memory in the first 2 megabytes of
- ; address space is considered to be chip memory. Less than 256K
- ; of chip memory is considered a fatal error.
-
- @36dStart looking at location 0.
- @36dDon't look past 2 megabytes.
- @36dSet the return address.
- @36dGo check the memory.
- @36dDo we have at least 256K of chip memory?
- @36dBomb if not.
-
- ; Clear chip memory. Everything from $C0 (right after the end of
- ; the initial exception vector table we've set up) to the end of
- ; chip memory is cleared.
-
- @36dClear location 0.
- @d
- @36dSet start address to $C0 (end of vectors)
- @36dSet return address.
- @36dGo clear the chip memory.
-
- ; Since we have found less than 256K of chip memory, some of it
- ; must not be working. Turn the screen bright green, blink the
- ; power light, and reset.
-
- @d
- @d
-
- ; We continue here after we've figured out where the chip memory
- ; ends (256K or greater) and where the $C00000 memory ends
- ; (0 if none present). The two addresses are in A3 and A4,
- ; respectively.
-
- @36dPoint to base of custom chip area.
- @36dDisable all DMA.
- @36dSet BPLCON0 for a blank screen.
- @36dSet bitplane 0 data to zeros.
- @36dSet background colour to medium gray.
-
- ; Clear most of the ExecBase structure to zeros.
-
- @36dPoint at ExecBase->IntVects.
- @36dGet KickMemPtr, KickTagPtr, KickCheckSum.
- @d
- @36dClear all of ExecBase from IntVects
- @36dto the end of the structure.
- @d
- @36dRestore Kick variables saved above.
-
- ; Set up the ExecBase pointer at location 4, and its complement
- ; in the ExecBase structure.
-
- @36dInstall ExecBase pointer at location 4.
- @d
- @d
- @36dInstall ExecBase complement check value.
-
- ; Set up the system stack.
-
- @36dTry to put stack in $C00000 RAM.
- @36dDo we have any $C00000 RAM?
- @36dIf not, use chip RAM.
- @36dSet system stack pointer.
- @36dStore system stack upper bound.
- @36dAllow 6K bytes for system stack.
- @36dStore system stack lower bound.
-
- ; Store the memory configuration. Next reset will use this if
- ; still intact, and not clear memory.
-
- @36dStore top of chip memory.
- @36dStore top of $C00000 memory.
-
- ; Part 2 of the deferred-guru procedure. Long ago, we set up
- ; registers D6 and D7 with the data for ExecBase->LastAlert.
- ; The following call writes them there. Now all is ready for
- ; the "alert.hook" mechanism to put up the deferred guru, if
- ; one was wanted.
-
- @36dSetup ExecBase->LastAlert.
-
- @36dCheck CPU type, and if 68881 present.
- @36dOr the result into the Attention flags.
-
- ; Initialize the exec lists. This is driven from a data table which
- ; contains the offsets from ExecBase where the various lists are,
- ; and the list types.
-
- @36dPoint to the table.
- @36dGet a table entry.
- @36dZero marks the end.
- @36dAdd to ExecBase to get absolute address.
- @36dClear the list by setting its head
- @36dpointer to point to itself,
- @36dclearing its "Tail" field,
- @36dand setting up the "TailPred" pointer.
- @36dGet the list type.
- @36dPut it into the list header.
- @36dLoop back to do next list.
- @a?fc02d2
-
- ; Table of list header offsets and types.
-
- @8p@5w@11wMemList (ExecBase + $142, type = NT_MEMORY)
- @8p@5w@11wResourceList (ExecBase + $150, type = NT_RESOURCE)
- @8p@5w@11wDeviceList (ExecBase + $15E, type = NT_DEVICE)
- @8p@5w@11wLibList (ExecBase + $17A, type = NT_LIBRARY)
- @8p@5w@11wPortList (ExecBase + $188, type = NT_MSGPORT)
- @8p@5w@11wTaskReady (ExecBase + $196, type = NT_TASK)
- @8p@5w@11wTaskWait (ExecBase + $1A4, type = NT_TASK)
- @8p@5w@11wIntrList (ExecBase + $16C, type = NT_INTERRUPT)
- @8p@5w@11wSoftInts[0] (ExecBase + $1B2, type = NT_SOFTINT)
- @8p@5w@11wSoftInts[1] (ExecBase + $1C2, type = NT_SOFTINT)
- @8p@5w@11wSoftInts[2] (ExecBase + $1D2, type = NT_SOFTINT)
- @8p@5w@11wSoftInts[3] (ExecBase + $1E2, type = NT_SOFTINT)
- @8p@5w@11wSoftInts[4] (ExecBase + $1F2, type = NT_SOFTINT)
- @8p@5w@11wSemaphoreList (ExecBase + $214, type = NT_SIGNALSEM)
-
- @8p@16wEnd of table marker.
-
- ; Table used to initialize the exec's library node.
-
- @8p@16bType = NT_LIBRARY.
- @8p@16bPriority = 0.
- @8p@16lName = pointer to "exec.library".
- @8p@16bFlags = LIBF_CHANGED | LIBF_SUMUSED.
- @8p@16bPad.
- @8p@16wNegSize (not set yet).
- @8p@16wPosSize.
- @8p@16wVersion.
- @8p@16wRevision.
- @8p@16lIdString = pointer to "exec ..."
- @8p@16lChecksum (not set yet).
- @8p@16wOpenCnt = 1.
-
- ; Names to use in the system free-memory lists.
-
- @8p@,12s
- @8p@,12s
-
-
- @36dGet address of task crash routine.
- @36dInstall in default trap code.
- @36dInstall in default exception code.
- @a?fc034a
-
- @40dSet the default task exit address.
- @40dPreallocate the lower 16 signals.
- @40dPreallocate TRAP #15 (for use
- in ROM-Wack breakpoints).
-
- @36dInitialize the exec.library node
- @36dup to and including the OpenCnt
- @36dfield, from the table above.
- @d
- @d
-
- @36dMake the library jump vector, using the
- @36dtable at $FC1A40, and the MakeFunctions()
- @36droutine. Setting A2 to the table address
- @36dsignals that the table is relative.
- @36dInstall library negative size.
-
- @36dSee if we have expansion memory.
- @36dBranch past this if we don't.
-
- ; Add expansion memory at $C00000 to the free memory lists.
-
- @36dFirst free location = ExecBase + $024C.
- @36dName = "Fast Memory".
- @36dPut in memory list at priority 0.
- @36dAttributes = MEMF_FAST | MEMF_PUBLIC.
- @36dGet end address of expansion memory.
- @36dSubtract address of first free location.
- @36dSubtract system stack size.
- @36dBuild free list and add it to system.
-
- @36dFree chip memory starts at $0400.
- @36dSpace for stack already reserved.
- @d
-
- ; Add chip memory to free memory lists. Enter here if there is
- ; no expansion memory, and ExecBase therefore resides at the bottom
- ; of chip memory.
-
- ; Note how chip memory is added to the system list at a lower
- ; priority than expansion memory. This causes it to be allocated
- ; only when specifically requested or when expansion memory is full.
-
- @36dFree chip memory is at ExecBase + $024C.
- @36dReserve 6K for system stack.
-
- ; Enter here if we do have expansion memory, with D0 and A0 set
- ; up as above.
-
- @36dAttributes = MEMF_CHIP | MEMF_PUBLIC.
- @d
- @36dName = "Chip Memory".
- @36dPriority = -10.
- @36dGet end address of free chip memory.
- @36dSubtract address of first free location.
- @36dBuild free list and add it to system.
-
- @36dGet ExecBase.
- @36dAdd the exec to the system library list.
-
- ; Set the exception vector table up for actual system operation.
- ; Up to this point, any interrupt or exception would have caused
- ; the screen to turn yellow and the computer to reset.
-
- ; The format of the data table used here is explained in comments
- ; at the front of the data table.
-
- @36dPoint to data table.
- @36dSet up base address for the offsets.
- @36dPoint to exception vector #2.
- @36dEnter the loop at the bottom.
-
- @36dConvert table entry to absolute address.
- @36dStore the handler address in the EVT.
- @36dGet the next data table entry.
- @36dLoop until end of table reached.
-
- @36dSee if we are running on a 68010/020.
- @d
- @36dSkip the following if not.
-
- ; Special initialization for machines using a 68010/020.
-
- @36dPoint at 68010/020 bus error handler.
- @d
- @36dFix the bus error vector.
- @36dFix the address error vector.
-
- @36d Use a different Supervisor() routine.
-
- ; Fix GetCC() for 68010/020 processors.
-
- ; We simply load the instruction sequence "MOVE.W CCR,D0 / RTS" into
- ; the place where the library jump vector to GetCC() normally is.
-
- @d
-
- ; Check if we have a 68881 numeric coprocessor, and if so, fix up
- ; some more vectors. This needs to be done since we also need to
- ; save the 68881's context when we switch tasks.
-
- @40dDo we have a 68881? If so,
- @d
- @40dUse a different Switch() function.
- @40dUse a different Dispatch() funciton.
-
- ; Regular 68000's continue here.
-
- @36dInitialize the exec interrupt handlers.
-
- @36dPoint to the custom chips.
- @36dEnable all DMA.
- @36dEnable the interrupt system.
- @36dSet the interrupt disable level to -1.
-
- @36dInitialize ROM-Wack.
-
- @36dChecksum the static part of the ExecBase
- @36ddata structure.
- @36dThis is used after a reset to see if
- @36dthe data structure has been clobbered.
- @d
- @d
- @36dStore the checksum.
-
- ; Now we are going to manufacture the very first task.
- ; We use AllocEntry() to obtain a block of memory. This is then
- ; used to hold the MemList from AllocEntry(), the task's stack,
- ; and the task descriptor.
-
- @36dPoint to the MemList.
- @36dAllocEntry()
- @36dGet the address of the MemList.
-
- ; It's assumed here that the allocated memory follows directly
- ; after the MemList. A safe assumption, since we still have
- ; unfragmented memory. We now create a task descriptor at the
- ; top of the allocated memory. The stack pointer for the task
- ; is initialized below the task descriptor.
-
- @36dPoint near the top of the memory block.
- @36dPoint to the future task descriptor.
- @d
- @36dStore stack lower bound.
- @36dStore stack upper bound.
- @36dSet the initial stack pointer image.
- @36dSet the stack pointer itself.
- @36dPriority = 0.
- @36dNode type = NT_TASK.
- @36dTask name = "exec.library".
-
- ; We initialize the task's memory list to empty, then enqueue
- ; the MemList holding all this memory there. This means that
- ; when the task dies, the memory will automatically be deallocated.
-
- @36dPoint to the task's memory list.
- @36dInitialize it to empty.
- @d
- @d
- @d
- @36dEnqueue the MemList from AllocEntry()
- @36don the task's memory list.
- @36dGet the task address back.
-
- ; Make this the current task, and make it ready to run.
- ; initialPC and finalPC are both initialized as zero, but no
- ; harm results, since the task can't start running yet.
-
- @36dMake this the current task.
- @36dClear A2.
- @36dClear A3.
- @36dAddTask()
- @36dGet the pointer to the task again.
- @36dMake the task state TS_RUN.
- @36dUnlink it from the TaskReady queue.
-
- ; A historic moment: We turn the supervisor mode flag off.
- ; Starting right now, we are running as a task named "exec.library",
- ; and the multitasking system is operational.
-
- @a?fc04be
- FC04BE and.w #0,SR Turn the supervisor bit off.
- @a=fc04c2
- @36dForbid()
- @36dPermit()
- @d
-
-
- ; The MemList used to allocate memory for the initial task.
-
- @7p@9l@9l@9l@8wA dummy list node.
-
- @7p@35w1 block of memory desired.
- @7p@35lMEMF_PUBLIC | MEMF_CLEAR
- @7p@35l1124 bytes.
-
-
- ; Table of areas to look for RomTags in. I don't know why the
- ; FC0000 - 1000000 area is covered twice. The F00000 to F80000
- ; area appears to be an alternate or additional place to put ROMs.
-
- @7p@9l@l
- @7p@9l@l
- @7p@9l@l
-
- @7p@35lEnd of list marker.
-
-
- ; Scan for RomTags, process the KickMemPtr and KickTagPtr
- ; variables, and build a table of all the resident modules found.
- ; The address of the table of resident modules is stored in
- ; the ExecBase data structure.
-
- @36dPoint to table of ROM address spaces.
- @36dScan for RomTags, etc.
- @36dStore the result in ExecBase->ResModules.
-
- @36dSet the power light to bright.
-
- ; Handle the "cool start" capture vector. Note that if we decided
- ; (much) earlier that ExecBase had been clobbered, it will have
- ; been rebuilt from scratch, and the cool start capture vector
- ; will be zero. Thus, we don't have to verify it further.
-
- @36dGet the "cool start" capture vector.
- @36dBranch past the following if zero.
- @d
- @36dCall the "cool start" capture code.
-
- ; Another historic moment. We call InitCode() to initialize the
- ; resident modules. This is where all the other stuff in the ROMs,
- ; stuff in RAM which survived the reboot, etc. comes online. We
- ; indicate that all those modules with the RTF_COLDSTART flag set
- ; should be initialized now.
-
- @36dRTF_COLDSTART flag must be set.
- @36dMinimum version is 0 (any will do).
- @36dInitCode().
-
- ; Yet another capture vector, this time the "WarmCapture" one.
-
- @36dCheck the "WarmCapture" vector.
- @36dBranch past this if zero.
- @d
- @36dCall the warm start capture code.
-
- ; I assume that when the DOS came online, it took over. This
- ; task looks like it's heading into a dead end.
-
- ; Clear all the CPU registers except for ExecBase and the stack
- ; pointer.
-
- @38dPush 14 longwords of zero on
- @38dthe stack.
- @d
- @38dRead them off again into the registers.
-
- ; This is the end of the road.
-
- Do forever
- @38dDebug()
- @38dGet ExecBase.
- @36dEnd
-
-
- ; Determine CPU type and whether FPP is present.
- ; ----------------------------------------------
-
- ; We need to know whether a non-68000 CPU is present for two
- ; reasons: First, on the 68000, at least one instruction
- ; (MOVE.W SR,<ea>) is available in user mode, whereas on the
- ; newer CPU's, it is privileged. Second, on the newer CPU's,
- ; when an exception occurs, more information is saved on the
- ; stack, and in the case of a bus error, the CPU's entire state
- ; is dumped there so that virtual memory computers (big UNIX
- ; boxes for example) can recover from page faults.
-
- ; Note that the 68020 can do everything the 68010 can, and thus,
- ; if a 68020 is detected, both the AFB_68010 and the AFB_68020
- ; flags will be set.
-
- ; We need to know whether there's an FPP present since, for task
- ; switches, we want to save the FPP registers on the stack as
- ; as the CPU registers, so each task can think it has the FPP
- ; all to itself.
-
- @d
-
- ; We are going to try 68010/020 and 68881 instructions. These will
- ; cause error exceptions if the respective parts aren't present, so
- ; we set up to trap these.
-
- @36dSave "Illegal Instruction" error vector.
- @36dSave "1111 Opcode" error vector.
- @36dPoint to temporary exception handler.
- @36dInstall this address in both vectors.
- @d
- @36dSave the stack pointer.
-
- ; Initialize the flags to zero (D0), and point to address zero (D1).
- ; Then we try to set the 68010 Vector Base Register, which determines
- ; where the exception vector table is. In the 68000, this is hard
- ; wired at zero. If the 68010 is present, we set it to zero.
-
- @d
- @d
- @a?fc0564
- FC0564 movec D1,VBR Set Vector Base Register to 0.
- @a=fc0568
-
- ; If we're still here, the CPU is at least a 68010. We thus set
- ; the AFB_68010 flag. Then we try to access a 68020-specific
- ; feature, namely, we try to enable its instruction cache.
-
- @36dSet AFB_68010 flag.
- @d
- @a?fc056e
- FC056E movec D1,CACR Try enabling the 68020 cache.
- @a=fc0572
-
- ; If we're still here, we have a 68020, and so we set the AFB_68020
- ; flag. Then we see if we also have a 68881 FPP, by trying to
- ; access one of its registers. Note that this will not cause an
- ; exception if no FPP is present.
-
- @36dSet AFB_68020 flag.
- @a?fc0576
- FC0576 fmove.l FPCR,D1 Try reading a 68881 register.
- @a=fc057a
- @36dDid it work?
- @d
- @36dIf so, set the AFB_68881 flag.
-
- ; We continue here either from above, or, on plain Amigas, by
- ; an error exception from one of the foreign instructions above.
- ; D0 contains all the flags which have been set along the way.
- ; We restore the two changed entries in the EVT and the stack
- ; pointer, then exit.
-
- @36dRestore the stack pointer.
- @36dRestore the exception vectors.
- @d
- @d
- @d
-
-
- ; Chip Memory Checking Routine
- ; ----------------------------
-
- ; This routine checks for the presence of memory. It is used at
- ; startup to determine how much chip memory is available. Note
- ; that it can't be used to check for memory at $C00000, and a
- ; special routine is provided to do this further on.
-
- ; On entry, A0 is the lower bound of the area to check, and A1 is
- ; the high bound. Memory is checked in 4K blocks.
-
- @d
- @40dWrite a zero to the first location.
- @40dSave the first location.
- @40dUse this as a signature value.
-
- ; Main loop: We enter here to check each 4K block.
-
- @40dIncrement current location by 4K.
- @40dSee if upper bound reached.
- @40dIf so, exit from the loop.
- @40dWrite the signature into memory.
-
- ; Longword 0 of the block being checked was initially cleared to
- ; zero. If it is now no longer zero, we have "wrapped around",
- ; i.e. due to incomplete address decoding, we have written the
- ; signature value at the beginning of the block. When this
- ; occurs, we have reached the end of memory, even though the
- ; signature value would read back correctly.
-
- @40dCheck location 0.
- @40dExit if signature appears there.
- @40dSee if signature can be read back.
- @40dIf successful, go check more memory.
-
- ; Done, return the end address of memory to the user. Return
- ; via indirect jump through A5 since we don't have a stack yet.
-
- @d
- @d
-
-
- ; Error System Reset Routine
- ; --------------------------
-
- ; This is the routine which blinks the power light, then resets
- ; the computer. It is called from the startup code if a failure
- ; of any sort is detected. The colour of the screen indicates
- ; the type of failure.
-
- ; This is the exception entry point. All vectors in the
- ; Exception Vector Table point here while the ROM kernel is
- ; initializing itself. A yellow screen means an unexpected
- ; exception has occurred.
-
- @40dColour number for yellow.
-
- ; This is the non-exception entry point. From here on down it's
- ; a general purpose routine which can be entered with a coulour
- ; number in D0.
-
- @40dPoint to the custom chips.
- @40dSet BPLCON0 for a blank screen.
- @40dSet bitplane 0 data to zeros.
- @40dSet background colour to yellow.
-
- @40dFor D1 = 1 to 10 do
- @42dSet delay to 1 time unit.
- @42dMake power light dim.
- @42dDelay.
- @42dSet delay to 0.5 time unit.
- @42dMake power light bright.
- @42dDelay.
- @40dEndfor
-
- ; Note: The "boot" and "ig" commands from ROM-Wack jump here.
-
- @40dDelay some more.
- @d
- @d
-
- @40dReset everything external to the CPU.
-
-
- ; Get the initial PC from the ROM (now mapped at zero due to the
- ; reset instruction) and start over.
-
- @d
- @d
-
-
- ; Memory Clear Subroutine
- ; -----------------------
-
- ; This subroutine clears a block of memory. The start address is
- ; in A0, the end address is in D0. Since we may not have a stack,
- ; the return address is provided in A5.
-
- @40dValue to store in memory.
- @40dCompute number of bytes to clear.
- @40dDivide by 4 (number of longwords).
- @40dPut the low-order 16 bits in D0,
- @40dand the high-order ones in D1, and
- @40dstart at the bottom (for dbra's).
- @40dClear a longword.
- @40dLoop until current 256K block done.
- @40dLoop until everything done.
- @40dReturn to caller.
-
-
- ; $C00000 Expansion RAM Checker
- ; -----------------------------
-
- ; The following routine checks for the presence of memory
- ; in the $C00000 - $DC0000 area. This is a nontrivial exercise,
- ; since if there is no memory there, we see images of the custom
- ; chip registers there instead, due to incomplete address decoding.
- ;
- ; This took a while to figure out, so I'm commenting it
- ; very heavily for my own satisfaction.
-
- ; Register A4 holds the end address of the block where we know
- ; RAM to reside. At first, we initialize this to the start address.
- ; Then, each time through the loop, we copy A4 to a temporary
- ; register, which we increment by 256K.
-
- @40dCopy start address into A4.
- @40dCopy A4 into temporary register.
- @40dAdd 256K to temporary register.
-
- ; Now we write to an address $0F66 bytes less than the temporary
- ; register. If there is RAM here, this will write into it near
- ; the top of the 256K block. If there isn't, this will write to
- ; the INTENA register and disable all interrupts.
-
- @40dWrite to RAM or INTENA.
-
- ; Now we read an address $0FE4 bytes below the temporary address.
- ; If there is memory here, this will read it. Otherwise, it will
- ; read the INTENAR register. If we find a non-zero value, it must
- ; be memory, since all bits in INTENAR were reset above. Otherwise,
- ; it could be either (memory could happen to contain zero).
-
- @40dRead RAM or INTENAR.
- @40dIf not zero, we've found memory.
-
- ; We got a zero. Make sure this isn't INTENAR by causing bits
- ; to be set in it. We set all of them except for the master
- ; interrupt enable. Again, if there's RAM here, this won't do
- ; anything to INTENAR, and we'll continue to see a zero.
-
- @40dWrite to RAM or INTENA.
-
- ; Read the same location as before. If this returns anything but
- ; $3FFF, it's fine. $3FFF means we're seeing INTENAR. If it's
- ; still zero, it's RAM. Anything else would be a fatal error, but
- ; that isn't checked for.
-
- @40dRead RAM or INTENAR.
- @40dExit from loop if INTENAR seen.
-
- ; Now we bump up A4 by copying the temporary register back. This
- ; means we have found a valid 256K block. We then go on looking
- ; until we've reached the upper limit of the address space to check.
-
- @40dUpdate A4 (means memory was found).
- @40dCompare to upper limit.
- @40dKeep looking if not reached.
-
- ; Continue here when we've reached the end of the space to check,
- ; or finally seen an image of the INTENAR register. We return the
- ; end address of the detected RAM in A4, or zero A4 if no RAM
- ; was found.
-
- @40dDisable all interrupts.
- @40dWas A4 ever updated?
- @40dIf so, return it.
- @40dZero A4 (indicates no memory).
- @40dReturn to caller.
-
- @8p@32wPadding
-
- ---------------------------------------------------------------------------
- AddDevice( device )
- A1
- ---------------------------------------------------------------------------
-
- @36dPoint to the system device list.
- @36dAdd the device to the list.
- @36dUpdate the device's vector checksum.
- @d
-
-
- ---------------------------------------------------------------------------
- RemDevice( device )
- A1
- ---------------------------------------------------------------------------
-
- ; NOTE: Some other part of the system, presumably DOS, will patch
- ; itself in ahead of this.
-
- @36dJust go to RemLibrary().
-
-
- ---------------------------------------------------------------------------
- error = OpenDevice( devName, unitNumber, ioRequest, flags )
- D0 A0 D0 A1 D1
- ---------------------------------------------------------------------------
-
- ; NOTE: Some other part of the system, presumably DOS, will patch
- ; itself in ahead of this, presumably so it can pull devices off
- ; disk if they aren't already in the device list.
-
- @d
- @36dPoint to the ioRequest.
- @36dClear the io_Error field in it.
- @d
- @d
- @36dPoint to the system device list.
- @36dForbid()
- @36dFindName()
- @36dGet the pointer to the device.
- @d
- @36dStore it in the ioRequest.
- @36dReturn -1 if device not found.
- @36dClear the io_Unit pointer.
- @d
- @36dSave ExecBase.
- @36dPoint A6 to the device's base address.
- @36dCall the device's Open() function.
- @36dRestore ExecBase.
- @36dGet the io_Error (from the Open() call).
- @36dExtend to a longword for return to
- @36dthe caller.
- @36dPermit()
- @d
- @d
-
- ; Continue here if the device was not found.
-
- @36dSet the return value to -1.
- @36dSet the io_Error field to -1.
- @d
-
-
- ---------------------------------------------------------------------------
- CloseDevice( ioRequest )
- A1
- ---------------------------------------------------------------------------
-
- ; NOTE: Some other part of the system, presumably DOS, will patch
- ; itself in ahead of this.
-
- @36dForbid()
- @36dSave ExecBase.
- @36dGet the pointer to the device node.
- @36dCall the device's Close() function.
- @36dRestore ExecBase.
- @36dPermit()
- @d
-
-
- ---------------------------------------------------------------------------
- SendIO( ioRequest )
- A1
- ---------------------------------------------------------------------------
-
- ; The command is sent to device with the "quick I/O" bit not set.
- ; This means the device must always respond by sending the
- ; I/O request back as a reply message when done.
-
- @36dClear the "quick I/O" bit.
- @36dSave ExecBase.
- @36dGet pointer to device node.
- @36dCall the device's "BeginIO" entry point.
- @36dRestore ExecBase.
- @d
-
-
- ---------------------------------------------------------------------------
- error = DoIO( ioRequest )
- D0 A1
- ---------------------------------------------------------------------------
-
- ; The command is sent to the device with the "quick I/O" bit set.
- ; This allows the device to decide whether to process the request
- ; synchronously or asynchronously.
-
- @36dSave ioRequest pointer for later.
- @36dSet the "quick I/O" bit.
- @36dSave ExecBase.
- @36dGet pointer to device node.
- @36dCall the device's "BeginIO" entry point.
- @36dRestore ExecBase.
- @36dGet ioRequest pointer back.
-
- ; Now fall through to WaitIO.
-
-
- ---------------------------------------------------------------------------
- error = WaitIO( ioRequest )
- D0 A1
- ---------------------------------------------------------------------------
-
- ; If the "quick I/O" bit is set, then the call to the device
- ; in BeginIO() finished the I/O operation synchronously, and
- ; we can return to the caller. Otherwise, we must wait for
- ; the reply message from the device.
-
- @36dCheck the "quick I/O" bit.
- @36dIf still set, the I/O is complete.
-
- ; "quick I/O" bit was not (or no longer) set, so we need to
- ; wait for the reply message from the device.
-
- @36dSave A2.
- @36dSave pointer to the ioRequest.
- @36dGet pointer to the reply port.
- @36dGet the reply port's signal bit.
- @d
- @36dConvert to signal mask.
-
- @36dDisable()
- @d
-
- @36dCheck if the ioRequest became NT_REPLYMSG
- @d
- @36dWait for the signal.
- @36dGo back and check the ioRequest again.
-
- @36dUnlink the ioRequest from the reply
- @36dport's message queue.
- @d
- @d
- @d
-
- @36dEnable()
- @d
- @d
-
- @36dRestore pointer to the ioRequest.
- @36dRestore A2.
- @36dGet the error field from the ioRequest.
- @36dExtend to long word.
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- result = CheckIO( ioRequest )
- D0 A1
- ---------------------------------------------------------------------------
-
- @a?fc074e
- @36dCheck the "quick I/O" bit.
- @36dIf set, request is done, so...
- @36dReturn address of ioRequest.
- @d
- @36dCheck if ioRequest type is NT_REPLYMSG
- @36dIf so, it is finished.
- @36dReturn zero.
- @d
- @36dReturn address of ioRequest.
- @d
-
-
- ---------------------------------------------------------------------------
- AbortIO( ioRequest )
- A1
- ---------------------------------------------------------------------------
-
- @36dSave ExecBase.
- @36dGet pointer to the device node.
- @36dCall the device's "AbortIO" entry point.
- @36dRestore ExecBase.
- @d
-
-
- ; Table used to set up the exception vector table.
-
- ; Each entry is a 16-bit offset from the table's base address
- ; to the address of the exception handler for that exception.
- ; The final longword of zeros marks the end of the table.
-
- ; The first entry means that the handler for exception number 2
- ; (bus error) is at $FC0778 + $64. The next entry is for exception
- ; number 3, and so on through to the end of the TRAP instruction
- ; vectors.
-
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@l
-
- @7p@29wEnd of table marker.
-
- @7p@29wPadding.
-
-
- ; Exception entry points. The indicated entries in the Exception
- ; Vector Table are set to point here.
-
- ; The BSR instructions are used so that the stacked return address
- ; from the BSR can be used to find out which exception occurred.
-
- @d
- @d
- @36dBus error.
- @36dAddress error.
- @36dIllegal instruction.
- @36dDivide by zero.
- @36dCHK instruction.
- @36dTRAPV instruction.
- @d
- @36dTrace mode.
- @36d"1010" opcode.
- @36d"1111" opcode.
- @36dReserved vector #12.
- @36dReserved vector #13.
- @36dReserved vector #14.
- @36dReserved vector #15.
- @36dReserved vectors #16-23, spurious int.
- @36dTRAP #0
- @36dTRAP #1
- @36dTRAP #2
- @36dTRAP #3
- @36dTRAP #4
- @36dTRAP #5
- @36dTRAP #6
- @36dTRAP #7
- @36dTRAP #8
- @36dTRAP #9
- @36dTRAP #10
- @36dTRAP #11
- @36dTRAP #12
- @36dTRAP #13
- @36dTRAP #14
- @36dTRAP #15
-
- ; Handler for reserved exceptions #16-23 and spurious interrupts.
- ; These are dead ends (click for Guru).
-
- @a?fc081a
- FC081A or.w #$0700,SR Disable all maskable interrupts.
- @a=fc081e
- @36dAlert number (fatal).
- @36dFreeze the task.
-
- ; Another exception handler. This one is a dead end also.
-
- @a?fc0828
- FC0828 or.w #$0700,SR Disable all maskable interrupts.
- @a=fc082c
- @d
- @36dMake alert number.
- @36dFreeze the task.
-
- ; Handler for bus and address errors (long stack frame).
- ; These two can be caught by the task if set up to do so.
-
- @36dUse the return address on the stack
- @36dto compute the exception number.
- @36dSee if error occurred in supervisor mode.
- @36dIf not, go to task's trap routine.
- @36dFreeze the task.
-
- ; Handler for miscellaneous other errors.
- ; These can be caught by the task.
-
- @36dUse the return address on the stack
- @36dto compute the exception number.
- @36dSee if error occurred in supervisor mode.
- @36dIf not, go to task's trap routine.
- @36dGuru time if in supervisor mode.
-
- ; Handler for TRAP instructions.
-
- @36dUse the return address on the stack
- @36dto compute the exception number.
- @36dSee if error occurred in supervisor mode.
- @36dGuru time if in supervisor mode.
- @36dElse go to task specific trap routine.
-
- ; Bus error handler for 68010/020 processors. These processors
- ; produce a more detailed stack frame when they hit a bus error
- ; (for use in virtual memory systems). The bus and address
- ; error exception vectors are set to point here at system startup
- ; if such a processor is being used.
-
- @36dPush a zero from the stack.
- @36dRead the exception number.
- @36dConvert it to a format compatible
- @36dwith the numbering scheme used
- @36delsewhere.
- @36dProcess the exception normally.
-
- ; We get here if various exceptions occurred in user mode.
- ; This looks up an exception handler address in the current task's
- ; descriptor, and jumps there. This allows each task to specify
- ; what is to happen if it causes an exception or executes a
- ; TRAP instruction.
-
- ; The task can clean up the stack and continue running if it
- ; wants to. All its registers are preserved.
-
- @36dReserve 4 words on stack and save A0.
- @36dGet ExecBase
- @36dGet the current task pointer.
- @36dGet current task's tc_TrapCode address
- and put it on the stack for the RTS.
- @36dRestore A0.
- @d
-
-
- ---------------------------------------------------------------------------
- Supervisor( code_to_execute )
- A5
- ---------------------------------------------------------------------------
-
- ; This routine is used to run things with the CPU in supervisor
- ; mode. The address of the code to execute once we're in supervisor
- ; mode is passed in A5.
-
- ; First, we tamper with the status register (attempt to set the
- ; supervisor mode bit). If successful, we are already in supervisor
- ; mode. If not, there will be a privilege violation, handled by
- ; the exception handler below.
-
- @a?fc08aa
- FC08AA or.w #$2000,SR Tamper with the status register.
- @a=fc08ae
-
- ; Are we still here? If so, we are already in supervisor mode.
- ; Fake an exception by pushing status register and PC on the stack.
-
- @36dPush a fake program counter.
- @36dPush the status register.
- @36dGo execute the caller's code.
- @d
-
- ; The following is 68010/020 version of the above. It is used
- ; if the startup code has detected such a processor and pointed
- ; the Supervisor() vector here.
-
- @a?fc08ba
- FC08BA or.w #$2000,SR Tamper with the status register.
- @a=fc08be
- @36dMake room on the stack.
- @36dStore status register.
- @36dStore fake program counter.
- @36dStore 68010/020 stack frame type.
- @36dGo execute the caller's code.
-
- ; Privilege violation exception handler.
-
- ; First, we find out where the CPU was when it got the privilege
- ; violation.
-
- @36dWas it the 68000 Supervisor() function?
- @d
- @36dWas it the 68010/020 version?
- @d
- @36dYes, fix return address, and go
- @36dexecute the caller's code.
-
- ; If we get here, it was a real privilege violation, i.e. not one
- ; of the intentionally caused ones above.
-
- @a?fc08f0
- FC08F0 or.w #$0700,SR Disable all maskable interrupts.
- @a=fc08f4
- @36dMake alert number.
- @36dFreeze the current task or guru.
-
-
- @8p@28wPadding.
-
-
-
- ; ROMTAG Scanner and "KickMemPtr/KickTagPtr" Processor
- ; ----------------------------------------------------
-
- ; The routines in this section do two things. One, they scan a
- ; section of the CPU addressing space for resident modules, each
- ; flagged by a "RomTag". For an example of what a RomTag looks
- ; like, check out the one at the very beginning of the exec.
-
- ; The start and end addresses of each piece of CPU address space
- ; to look for RomTags in are given in a table, to which A0 must
- ; point on entry.
-
- ; A temporary list is built, containing nodes which each point to
- ; a RomTag. Each resident module has a name, and no two modules
- ; with the same name are allowed. If there is a conflict, the
- ; one with the higher version number or priority wins and the
- ; other one is discarded.
-
- ; After the list of RomTags has been compiled, we process something
- ; called the KickMemPtr and the KickTagPtr, found in the ExecBase
- ; structure. The former points to a chain of MemLists. The latter
- ; points to an odd type of chain containing pointers to RomTags.
- ; If you really need to know the format of this chain, read the
- ; comments at the appropriate code.
-
- ; All the MemList structures, and tables of RomTag addresses, pointed
- ; to by these pointers, have a checksum, also stored in ExecBase.
- ; If the checksum we calculate doesn't match that checksum, we
- ; discard all the data (assume it has been damaged in a system crash
- ; before the reboot).
-
- ; If the checkum matches, then we try to allocate all the pieces
- ; of memory pointed to by the KickMemPtr MemLists. If this is
- ; successful, we add all the KickTagPtr RomTags to the RomTag list.
- ; Presumably, the KickMemPtr list will indicate where RAM-resident
- ; modules are located, and if we were able to reclaim them before
- ; the memory got allocated for something else, we add them to the
- ; system again after a reboot.
-
- ; Finally, we process the RomTag list. This takes the form of
- ; building a table of resident module addresses, terminated with
- ; a zero, in memory allocated for that purpose. The RomTag list is
- ; deallocated. Note that the table of module addresses has the
- ; same format as one of the entries in the KickTagPtr list.
-
- ; Each resident module can have a flag set in its RomTag which
- ; which causes it to be automatically initialized later.
-
-
- @d
-
- ; First, create a temporary list structure to hold the found RomTags
- ; in. The list header is put on the stack.
-
- @36dReserve 14 bytes on the stack (enough
- @36dfor a list header), and get the address.
- @36dClear the list to empty.
- @d
- @d
- @d
-
- ; Now process the table of areas to look for RomTags in. Call the
- ; RomTag scanning routine with the data from each table entry to
- ; find all the RomTags in that section of address space.
-
- @36dPoint to the start of the address table.
- @36dSee if end of table reached.
- @36dNegative value indicates end.
- @36dGet the start address and the end address
- @36dof an area to look for RomTags in.
- @36dScan the area for RomTags.
- @36dLoop until end of list reached.
-
- ; Now process the "Kick" variables in ExecBase. These apparently
- ; exist to allow a set of resident modules (such as a RRD) to
- ; survive a system reboot. If the checksum of all the data tables
- ; is still valid, we claim the memory and add the RomTags to
- ; the list.
-
- @36dSumKickData()
- @36dVerify the checksum against the old one.
- @36dSkip the following if not valid.
- @36dTry to reallocate all the MemLists.
- @36dDid we get all the memory back?
- @36dIf not, don't bother with the KickTags.
- @36dProcess the list of "KickTags".
- @36dBuild a table of RomTag addresses.
- @36dDeallocate the RomTag list header.
- @d
- @d
-
-
- ; This routine scans an area indicated by A4 (start address) and
- ; D4 (end address) for RomTag structures, and puts any found RomTags
- ; on the RomTag list. If there is more than one version of any
- ; given RomTag, the newest one wins, the older ones are discarded.
-
- @d
- @36dLoad the RomTag matchword.
- @36dGet the end address.
- @36dSubtract the start address.
- @36dIf less than zero, return.
- @36dDivide the result by 2 (number of words).
- @36dDecrement by 1 (for DBcc instruction).
- @36dSplit into two halves (since DBcc can
- @36donly use 16-bit counters).
- @d
- @36dLook for the RomTag matchword.
- @d
- @36dLoop until entire area scanned.
- @36dExit if end reached.
-
- ; We've found a RomTag matchword. A4 points to it. Check if
- ; this is really a RomTag by verifying the pointer directly
- ; after the matchword.
-
- @36dPoint to the matchword.
- @36dSee the longword directly after the
- matchword points to it.
- @36dNot a valid RomTag if not.
-
- ; We are pointing to a valid RomTag. Add it to the RomTag list.
-
- @36dAdd RomTag to list of found ones.
-
- ; Each RomTag has in it a pointer (RT_ENDSKIP) which points to
- ; the address where to start looking for the next RomTag, i.e.
- ; the end of whatever code/data is associated with it.
-
- @36dSkip to the end of the module.
- @36dStart looking for the next one.
- @d
- @d
-
-
- ; This subroutine adds a RomTag to the list of found RomTags.
- ; If the current RomTag has the same name as a RomTag already in
- ; the list, the older (or if same age, lower priority) version
- ; is discarded. Memory is allocated to hold each node as needed.
-
- @36dPoint to the temporary list on the stack.
- @36dGet the name of this RomTag.
- @36dFindName()
- @36dDid we find a node with this name?
- @36dIf not, go and add the tag to the list.
- @36dPoint to the node we found.
- @36dCompare the version numbers of the list
- @36dnode and the newly found RomTag to find
- @36dout which is more recent.
- @36dDiscard current RomTag if older.
- @36dUse current one if newer.
- @36dVersion numbers match, so compare
- @36dthe priority fields.
- @36dDiscard current RomTag if lower priority.
-
- ; This RomTag supersedes a previous one, which is already in the
- ; list. Therefore we discard the one in the list.
-
- @36dPoint to the node in the list.
- @36dUnlink it from the list.
- @36dKeep a pointer to the node's memory.
- @36dGo and make a new node out of it.
-
- ; We enter here if this RomTag doesn't supersede some other one.
- ; This means we have to allocate some memory for a list node to
- ; store information about it.
-
- @36dNo particular memory requirements.
- @36d14 bytes.
- @36dGo and allocate the memory.
- @36dDid we get the memory?
- @36dIf not, skip the following.
- @36dPoint to the memory.
-
- ; We have obtained 14 bytes of memory one way or another, and we
- ; now build a list node and add it to the list of found RomTags.
-
- @36dCopy the RomTag's priority.
- @36dCopy the RomTag's name.
- @36dStore the RomTag's address.
- @d
- @36dAnd enqueue on the RomTag list.
- @d
-
-
- ; RomTag list to resident module table converter.
-
- ; This routine scans the temporary RomTag list, and builds a table
- ; of resident module addresses from it. The list itself is
- ; deallocated.
-
- @36dStart with 1 longword needed.
- @36dStart at the head node of the list.
- @36dGet pointer to the current node.
- @36dGet pointer to the next node.
- @36dEnd of list reached if zero.
- @36d4 longwords needed for this node.
- @36dScan the rest of the list.
- @36dMEMF_PUBLIC | MEMF_CLEAR.
- @36dAllocate memory.
- @36dGet pointer to allocated memory.
- @36dSave a copy of it.
- @36dStart at the head of the RomTag list.
- @36dGet pointer to current node.
- @36dGet pointer to next node.
- @36dEnd of list reached if zero.
- @36dStore pointer to this RomTag.
- @36d14 bytes.
- @36dFreeMem() the list node.
- @36dGo process next list node.
- @36dMark end of "KickTag" list.
- @36dReturn its base address.
- @d
-
-
- ; KickTagPtr processor.
-
- ; This routine steps through the table(s) of RomTag addresses
- ; pointed to by the KickTagPtr, and adds all the RomTags pointed
- ; to by these addresses to the list of found RomTags.
-
- @d
- @36dGet the KickTagPtr.
- @36dJust exit if it is zero.
- @36dPoint to the first tag.
- @36dRead a longword from the current tag.
- @36dExit if end of list reached.
- @36dIf this is a link, handle it.
- @36dData must be a pointer to a RomTag.
- @36dAdd the RomTag to the list.
- @36dContinue with current node.
- @36dStrip high bit from pointer to next
- @36dnode in the list of "KickTags".
- @36dGo process the next node.
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- SumKickData()
- ---------------------------------------------------------------------------
-
- ; This routine computes the KickCheckSum by checksumming all the
- ; tables associated with the KickMemPtr and KickTagPtr pointers.
- ; The result should is the KickCheckSum.
-
- @a?fc0a3c
- @d
- @36dPoint to the KickMemPtr in ExecBase.
- @36dGet the KickMemPtr and the KickTagPtr.
- @36dClear both to zero in the ExecBase
- @36dstructure.
- @36dStart checksum at -1.
- @36dStart at the old KickMemPtr.
-
- @36dEnd of list reached?
- @36dExit from loop if so.
- @36dPoint to current MemList.
- @36dGet pointer to next MemList.
- @36dGet the number of entries in the MemList.
- @36dDouble it and add 4 more longwords, to
- @36dget the size (in longwords) of this list.
- @36dChecksum the MemList.
- @36dGo process next MemList, if any.
-
- @36dGet the old KickTagPtr.
- @36dSkip the following if none.
- @36dPoint to the start of the list.
- @36dStart checksumming the list.
-
- @36dAdd a longword to the checksum.
- @36dGet first data word at this node.
- @36dExit if end of list reached.
- @36dIf high bit clear, add the data to the
- checksum and go on to the next longword.
- @36dClear the high bit.
- @36dUse result as pointer to next node.
- @36dContinue processing the list.
- @36dPut KickMemPtr/KickTagPtr back.
- @d
- @d
-
- ; Subroutine to checksum all the entries in a MemList.
-
- @d
- @d
- @d
-
-
- ; The KickMemPtr points to a list of MemLists, each pointing to
- ; some number of chunks of memory. This routine steps through
- ; all the MemLists, allocating all those chunks. If any can't
- ; be allocated (memory already grabbed by someone else), it returns
- ; zero. If successful, it returns 1.
-
-
- @36dStart where the KickMemPtr points.
- @36dEnd of list reached?
- @36dIf so, return 1 and exit.
- @36dPoint to the current MemList.
- @36dGet pointer to the next MemList.
- @36dAdvance past the MemList header.
- @36dGet number of entries in this MemList.
- @36dFake "successful allocation" return code.
- @36dEnter the loop.
-
- ; Allocate all the pieces of memory indicated by this MemList.
-
- @36dGet the address of this entry.
- @36dGet the size of this entry.
- @36dAllocAbs()
- @36dSuccessful?
- @36dIf so and more entries remain, loop.
-
- ; When we come out of the loop, if the zero flag is set, we were
- ; unable to reclaim a piece of memory specified in the MemList.
- ; In this case, return zero and exit. Otherwise, we have allocated
- ; them all and go on to the next MemList.
-
- @36dIf failed, go exit.
- @36dElse proces next MemList.
- @36dIndicate all is OK.
- @d
-
-
- ---------------------------------------------------------------------------
- resident = FindResident( name )
- D0 A1
- ---------------------------------------------------------------------------
-
- @d
- @36dGet pointer to the resident module table.
- @d
-
- ; Outer loop: Step through the table(s) of RomTags, looking
- ; for one whose name matches the wanted one.
-
- @36dGet a RomTag address from the table.
- @36dReturn zero if end of table reached.
- @36dIf table entry is a link then
- @38dclear its high bit.
- @38duse it as a new table pointer.
- @38dGo to the top of the loop.
- @36dEndif
- @36dGet pointer to desired name.
- @36dPoint to RomTag's name field.
-
- ; Inner loop: Compare the wanted name with that in the RomTag.
-
- @36dCompare a character.
- @36dBack to top of loop if not equal.
- @36dDid we reach the terminating zeros?
- @36dCompare more characters if not.
-
- ; Fall through with the module's address in D0.
-
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- InitCode( startClass, version )
- D0 D1
- ---------------------------------------------------------------------------
-
- ; This function initializes modules from the resident module list.
-
- ; The resident module list is one or more tables of RomTag addresses.
- ; Such tables can be linked together by including the address of the
- ; next table, with the high bit set, as the last address in a table.
-
- ; We are given a set of required flags in D0, and a minimum
- ; version number in D1. Modules which have flags not set whose bits
- ; appear in D0, or are of a lower version than D1, will not be
- ; initialized.
-
- @d
- @40dGet the ResModules pointer.
- @40dGet forbidden flags.
- @40dGet cutoff version number.
- @40dRead a module address from the table.
- @40dExit if end of table reached.
- @40dIs the high bit set? If so, it's
- @40da pointer to another table, so strip
- @40dthe high bit off, point to the next
- @40dtable, and process it.
-
- @40dCheck the module's version number
- @40dagainst the cutoff.
- @40dIgnore module if too low.
- @40dGet the module's flags.
- @40dCheck against mask.
- @40dIgnore it if required ones not set.
- @d
- @40dInitResident()
- @40dProcess next resident module.
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- InitResident( resident, segList )
- A1 D1
- ---------------------------------------------------------------------------
-
- ; This initializes a resident module. The pointer to the module
- ; is in register A1. If the RT_FLAGS byte at offset 10 from
- ; the module pointer has the RTF_AUTOINIT flag set, we let the
- ; module initialize itself by calling its initialization code.
-
- ; Otherwise we assume it's a library type of thing, and call
- ; MakeLibrary with a set of parameters taken from the module.
- ; If the MakeLibrary succeeds, we add the module to the appropriate
- ; system list.
-
- @40dCheck the RTF_AUTOINIT flag.
- @d
- @40dGet the RT_INIT address.
- @d
- @40dGet the segList pointer.
- @40dCall the module's init code.
- @d
-
- ; The RTF_AUTOINIT flag was not set, so we MakeLibrary() the
- ; module instead. Note that the address at RT_INIT points to
- ; a data structure containing parameters for MakeLibrary().
-
- @d
- @40dGet the initialization address.
- @40dGet parameters for MakeLibrary.
- @40dMakeLibrary()
- @d
- @40dStore the library pointer.
- @40dIf zero, just return it and exit.
-
- ; The library has been created successfully.
-
- @40dGet the library pointer.
- @40dGet the module's node type.
- @40dIf the node type is NT_DEVICE then
- @d
- @42dAddDevice().
- @d
- @40dElse if it is NT_LIBRARY then
- @d
- @42dAddLibrary().
- @d
- @40dElse if it is NT_RESOURCE then
- @d
- @42dAddResource().
- @40dEndif.
- @d
-
-
- ; InitStruct entry point to copy one byte several times (-186).
-
- @40dGet the byte initially.
- @40dCopy it the required number of times.
- @d
- @40dBack to main loop.
-
- ; Entry ponint for invalid InitStruct commands (-176). Guru time.
-
- @40dSave registers.
- @40dAlert number (fatal).
- @40dGet ExecBase
- @40dPut up the Alert.
- @40dThis never gets executed.
-
- ; InitStruct entry point to copy one longword several times (-154).
-
- @40dRound A1 up to next even address.
- @d
- @d
- @d
- @40dGet the longword initially.
- @40dCopy it the required number of times.
- @d
- @40dBack to main loop.
-
- ; InitStruct entry point to copy one word several times (-134).
-
- @40dRound A1 up to next even address.
- @d
- @d
- @d
- @40dGet the word initially.
- @40dCopy it the required number of times.
- @d
- @40dBack to main loop.
-
-
- ---------------------------------------------------------------------------
- InitStruct( initTable, memory, size )
- A1 A2 D0
- ---------------------------------------------------------------------------
-
- @36dGet structure base address.
- @36dDivide size by 2 (get size in words)
- @d
- @36dLoop: Clear the structure's memory.
- @d
-
- @36dGet structure base address again.
- @d
- @36dRead a byte from the initTable.
- @36dIf it is zero, we're done.
- @36dCheck and reset offset flag.
- @36dBranch if it was not set.
-
- ; Process an offset command (10ssnnnn or 11ssnnnn).
-
- @36dCheck and reset byte/rptr flag.
- @36dBranch if it was not set.
- @36dBack up over command byte.
- @36dGet cmd byte + 24 bit data.
- @36dMask out the command byte.
- @d
-
- ; Process an offset/byte command (10ssnnnn).
-
- @d
- @36dGet next byte from table into D1.
-
- ; Continue here for both offset commands. In each case, A1 now
- ; points at the next even address in the initTable, and D1 contains
- ; the offset we have just fetched from it, as a longword.
-
- @36dGet structure base address.
- @36dAdd offset just computed.
-
- ; Continue here for all commands, A0 now holds the absolute
- ; address where the next operand should go, D0 contains what is
- ; left of the command byte, and A1 points at the current even
- ; address in the table.
-
- @38dGet the command byte
- @38dShift and mask it so it becomes
- @38d2 * (sdd)
- @38dGet the jump offset from the table.
- @38dMask all but (nnnn) out of the command.
- @38dJump to the right routine.
-
- ; Entry point for copying multiple bytes (-42).
-
- @36dCopy one byte.
- @36dLoop until required number done.
-
- @36dRound A1 up to next even address.
- @d
- @d
- @d
- @36dGo back to main loop.
-
- ; Entry point for copying multiple longwords (-24).
-
- ; Simply falls through to word copy routine, set up to copy twice as
- ; many words. An extra 1 must be added to compensate for the effects
- ; of the "dbra" instruction.
-
- @36dD0 = (2 * D0) + 1.
- @d
-
- ; Entry point for copying multiple words (-20).
-
- @36dRound A1 up to next even address.
- @d
- @d
- @d
- @36dMove the data.
- @d
- @36dGo back to top of main loop.
-
- @d
-
- ; Dispatch table for InitStruct.
-
- @8p@10w-24 (sdd = 000) longword, count.
- @8p@10w-20 (sdd = 001) word, count.
- @8p@10w-42 (sdd = 010) byte, count.
- @8p@10w-176 (sdd = 011) Invalid.
- @8p@10w-154 (sdd = 100) longword, repeat.
- @8p@10w-134 (sdd = 101) word, repeat.
- @8p@10w-186 (sdd = 110) byte, repeat.
- @8p@10w-176 (sdd = 111) Invalid.
-
- @8p@28w Padding.
-
-
- ; The following is used to bail out of an interrupt which we should
- ; have ignored.
-
- @d
- @d
-
- ; Level 1 Autovector interrupt entry point.
- ; -----------------------------------------
-
- @d
-
- @36dPoint to custom chip register area.
- @36dGet ExecBase.
- @36dGet interrupt enable register.
- @36dCheck master interrupt enable.
- @36dBail out if no interrupts enabled.
- @36dCheck for pending & enabled interrupts.
-
- @36dSerial port transmit interrupt?
- @d
- @36dGet IntVects[0] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dDisk block finished interrupt?
- @d
- @36dGet IntVects[1] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dSoftware generated interrupt?
- @d
- @36dGet IntVects[2] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dBail out if nothing found.
-
- ; Level 2 Autovector interrupt entry point.
- ; -----------------------------------------
-
- @d
-
- @36dSee level 1 for comments.
- @d
- @d
- @d
- @d
- @d
-
- @36dI/O port or timer interrupt?
- @d
- @36dGet IntVects[3] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dBail out if nothing found.
-
- ; Level 3 Autovector interrupt entry point.
- ; -----------------------------------------
-
- @a?fc0cd8
- @d
-
- @36dSee level 1 for comments.
- @d
- @d
- @d
- @d
- @d
-
- @36dBlitter finished?
- @d
- @36dGet IntVects[6] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dStart of vertical blank?
- @d
- @36dGet IntVects[5] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dCopper interrupt?
- @d
- @36dGet IntVects[4] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dBail out if nothing found.
-
- ; Level 4 Autovector interrupt entry point.
- ; -----------------------------------------
-
- @d
-
- @36dSee level 1 for comments.
- @d
- @d
- @d
- @d
- @d
-
- @36dAudio channel 1?
- @d
- @36dGet IntVects[8] handler data.
- @36dUse special ExitIntr() below.
- @d
- @a?fc0d62
-
- @36dAudio channel 3?
- @d
- @36dGet IntVects[10] handler data.
- @36dUse special ExitIntr() below.
- @d
-
- @36dAudio channel 0?
- @d
- @36dGet IntVects[7] handler data.
- @36dUse special ExitIntr() below.
- @d
-
- @36dAudio channel 2?
- @d
- @36dGet IntVects[9] handler data.
- @36dUse special ExitIntr() below.
- @d
-
- @36dBail out if nothing found.
-
- ; This routine allows a single invocation of the level 4 interrupt
- ; handler to service all level 4 interrupts which are pending or
- ; become pending while one is serviced.
-
- @36dPoint at custom chip register area.
- @36dGet ExecBase.
- @36dMask for all level 4 interrupt bits.
- @d
- @36dFind enabled and pending level 4 ints.
- @36dIf any still pending, go service them.
-
- @36dOtherwise, do ExitIntr()
-
- ; Level 5 Autovector interrupt entry point.
- ; -----------------------------------------
-
- @d
-
- @36dSee level 1 for comments.
- @d
- @d
- @d
- @d
- @d
-
- @36dDisk sync interrupt?
- @d
- @36dGet IntVects[12] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dSerial port receive interrupt?
- @d
- @36dGet IntVects[11] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dBail out if nothing found.
-
- ; Level 6 Autovector interrupt entry point.
- ; -----------------------------------------
-
- @d
-
- @36dSee level 1 for comments.
- @d
- @d
- @d
- @d
- @d
-
- @36dSpecial copper interrupt?
- @d
- @36dGet IntVects[14] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dExternal level 6 interrupt?
- @d
- @36dGet IntVects[13] handler data.
- @36dPush address of ExitIntr()
- @d
-
- @36dBail out if nothing found.
-
- ; Level 7 Autovector interrupt entry point.
- ; -----------------------------------------
-
- @d
- @d
- @36d Get IntVects[15] handler data.
- @d
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- ExitIntr()
- ---------------------------------------------------------------------------
-
- ; This routine is called after an interrupt handler has finished.
- ; It checks if a task switch is necessary. If not, it returns
- ; from the interrupt. Otherwise, it drops into the scheduler.
-
- ; The initial check for supervisor mode is very important. If
- ; the CPU was in supervisor mode, then there either was no task
- ; running (CPU stopped), or the task had already been interrupted
- ; by a lower priority interrupt. In either case, we may not do
- ; a task switch. In the former case, it will be done after the
- ; CPU comes out of the STOP instruction in the dispatcher, and
- ; in the latter, it will be taken care of by the lowest priority
- ; interrupt handler (which interrupted the CPU while it was not
- ; in supervisor mode).
-
- @38dCheck if CPU was in supervisor mode.
- @38dIf so, just return from interrupt.
- @38dGet ExecBase.
- @38dSee if task switching is disabled.
- @38dIf so, just return from interrupt.
-
- @38dCheck the scheduling attention flag.
- @38dReturn from interrupt if not set.
-
- @a?fc0e7a
- FC0E7A move.w #$2000,SR Enable all interrupts.
- @a=fc0e7e
- @d
-
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- Schedule()
- ---------------------------------------------------------------------------
-
- ; This is the scheduler. It is called with the current task's
- ; registers saved on the system stack, as put there by the interrupt
- ; entry point, and PC/SR as put there by the interrupt itself.
- ;
- ; The scheduler checks if the task should be suspended and another
- ; task run in its place. The following decision is made:
- ;
- ; IF the current task has an exception pending THEN
- ; reschedule the current task, so that it will be redispatched,
- ; so that the dispatcher can process the exception.
- ; ELSEIF the TaskReady queue is empty THEN
- ; the current task is the only runnable task in the system, so
- ; let it continue running.
- ; ELSEIF the TaskReady queue contains a higher priority task THEN
- ; do a task switch.
- ; ELSEIF the current task's time slice has expired THEN
- ; reschedule the current task (it may be redispatched right away,
- ; with a new time slice).
- ; ELSE
- ; let the current task keep running.
- ; ENDIF
-
- @d
- @a?fc0e8a
- FC0E8A move.w #$2700,SR Mask all maskable interrupts.
- @a=fc0e8e
- @38dReset the scheduling attention flag.
- @38dGet the current task pointer.
- @38dCheck the task's TB_EXCEPT flag.
- @d
- @38dPoint to the TaskReady queue.
- @38dCheck if the queue is empty.
- @38dIf so, return from interrupt.
- @38dGet the queue's head node.
- @38dGet the head node's priority.
- @38dCompare to the current task's priority.
- @38dSwitch tasks if higher priority.
- @38dCheck the time slice expired flag.
- @38dIf not expired, return from interrupt.
-
- ; If we get this far, it is necessary to put the current task on
- ; the TaskReady queue and then run the one at the head of the queue.
- ; This may be the same one if a TB_EXCEPT is being processed.
-
- @38dPoint to the TaskReady queue.
- @38dEnqueue the current task.
- @38dMake the task's state TS_READY.
- @a?fc0ecc
- FC0ECC move.w #$2000,SR Enable all interrupts.
- @a=fc0ed0
-
- ; Get the current task's saved registers back. They may have been
- ; put on the stack when an interrupt occurred, or at the start of
- ; this routine.
-
- @d
-
- @38dInsert some space in the system stack.
- @38dPut in the address of Switch().
- @38dGet A6 from the stack.
- @38dGo to Switch().
-
-
- ---------------------------------------------------------------------------
- Switch()
-
- [Version for machines without a numeric coprocessor]
- ---------------------------------------------------------------------------
-
- ; The ExecBase "Switch()" vector points here if no FPP is installed.
-
- ; This routine does a task switch. It stores the context of
- ; the currently running task, then drops into the dispatcher.
-
- ; The routine stores the current CPU context on the user
- ; stack. The status register and program counter are popped from
- ; the supervisor stack. The current interrupt disable nesting
- ; level and the user stack pointer are then saved in this task's
- ; task descriptor.
-
- ; If the TB_SWITCH bit is set in the task descriptor, the task's
- ; TC_SWITCH function is called.
-
- @a?fc0ee0
- FC0EE0 move #$2000,SR Enable all interrupts.
- @a=fc0ee4
- @40dStack A5 on the supervisor stack.
- @40dGet the user stack pointer.
- @40dStack all registers on user stack.
-
- @40dGet ExecBase
-
- @40dGet current interrupt disable level.
- @40dSet interrupt disable level to -1.
- @40dEnable interrupts.
-
- @40dFix A5 in the saved register set.
- @40dSave the status register.
- @40dSave the program counter.
-
- @40dAddress of context-restore routine
- for machines without an FPP.
-
- @40dFind the current task descriptor.
- @40dStore interrupt disable level.
- @40dStore user stack pointer.
- @40dCheck the TB_SWITCH bit
- @d
- @40dIf TB_SWITCH bit was set, then
- @40dcall this task's TC_SWITCH function.
- @d
-
-
- ---------------------------------------------------------------------------
- Dispatch()
-
- [Version for machines without a numeric coprocessor]
- ---------------------------------------------------------------------------
-
- ; This routine dispatches the next runnable task, if there is one.
-
- ; If the TaskReady queue is empty, the routine waits, stopping
- ; the processor and checking the queue again each time it resumes
- ; running (after an interrupt).
-
- ; When a runnable task is found, it is dispatched. Its context
- ; and interrupt disable level are restored, and the TB_LAUNCH
- ; and TB_EXCEPT flags are checked. If either is set, they are
- ; handled.
-
- @40dAddress of context-restore routine
- for machines without an FPP.
-
- @40dInitialize interrupt disable level
- @40dat -1, and enable interrupts.
-
- @40dPoint at the TaskReady queue.
- @a?fc0f40
- FC0F40 move #$2700,SR Mask all maskable interrupts.
- @a=fc0f44
- @40dCheck for a task descriptor at
- @40dthe front of the queue.
- @d
-
- ; TaskReady queue is empty. Halt the processor until the next
- ; interrupt, then check for runnable tasks again.
-
- @40dIncrement the idle counter.
- @40dSet the rescheduling attention flag.
- @a?fc0f54
- FC0F54 stop #$2000 Enable all interrupts and stop.
- @a=fc0f56
- @d
- @40dGo back and check for runnable tasks.
-
- ; We have a runnable task.
-
- @40dUnlink the task descriptor from
- @40dthe TaskReady queue.
- @d
- @40dIncrement the dispatch counter.
-
- @40dSet the current task pointer.
-
- @40dInitialize the time-slice counter.
-
- @40dReset the time slice expired flag.
- @40dSet the task's state to TS_RUN.
-
- @40dRestore the interrupt disable level.
- @d
- @40dDisable interrupts if interrupt
- @40ddisable level >= 0.
-
- @a?fc0f90
- FC0F90 move #$2000,SR Enable all interrupts.
- @a=fc0f94
- @40dGet the task's flags.
- @40dCheck for TB_EXCEPT or TB_LAUNCH.
- @d
- @40dProcess the flags if either was set.
-
- @40dGet the user stack pointer.
-
- @40dRestore the CPU context.
-
-
- ; Context Restore routine (non-FPP version)
- ; -----------------------------------------
-
- ; Pop the task's CPU context off the user stack, and start it
- ; running. The program counter and status register are set by
- ; storing them on the supervisor stack for the "RTE" instruction.
-
- @40dGet the user stack pointer.
- @40dSet it.
- @40dGet the program counter.
- @40dGet the status register.
- @40dRestore all the other registers.
- @40dAnd start running the task.
-
- ; Subroutine to handle TB_LAUNCH and TB_EXCEPT.
-
- @40dCheck the TB_LAUNCH bit.
- @d
- @40dIf it was set, call the task's
- @40dTC_LAUNCH routine.
- @d
- @40dRestore D0.
- @40dCheck the TB_EXCEPT bit.
- @d
- @40dReturn if it was clear.
-
-
- ---------------------------------------------------------------------------
- Exception()
- ---------------------------------------------------------------------------
-
- ; This routine handles task-level exception processing.
-
- ; It checks whether any signals have occurred which should cause
- ; a software exception. If so, it calls the task's exception
- ; processing routine. After this returns, it restores everything
- ; so that the task itself can be dispatched.
-
- @40dReset the TB_EXCEPT bit.
-
- @40dDisable()
- @d
-
- @40dGet received signals.
- @40dCompare with exception signals.
- @40dIf any exception signals were set,
- @40dreset them in both places.
-
- @40dEnable()
- @d
- @d
-
- @40dGet the user stack pointer.
-
- ; Store tc_Flags, tc_State, tc_IDNestCnt, tc_TDNestCnt on user stack.
-
- @d
-
- ; If interrupts have been disabled exactly once, then enable them.
-
- @d
- @d
- @d
- @d
- @d
-
- ; Put the address of an exception post-processing routine on the
- ; user stack. This gets executed when the exception routine
- ; does an RTS.
-
- @40dPut return address on user stack.
- @40dSet user stack pointer.
- @40dSee if this is a plain 68000.
- @d
- @40dMake 68010/020 extended stack frame.
-
- @40dPut exception code and a fake status
- @40dword on the supervisor stack.
- @40dPoint to the exception handler's
- data segment.
- @d
-
- ; Continue here after the user's exception handling routine has run.
-
- @40dGet ExecBase.
- @40dWhere to go in supervisor mode.
- @40dGo to supervisor mode.
-
- @40dAddress of context restore routine.
-
- @40dIs this a 68010/020?
- @d
- @40dIf so, handle extended stack frame.
-
- @40dDo we have a 688881?
- @d
- @40dIf so, use the other context-restore.
-
- @40dPop PC and SR from stack.
- @40dGet current task descriptor.
- @40dSet the exception signals up again.
- @40dGet the user stack pointer.
-
- ; Restore tc_Flags, tc_State, tc_IDNestCnt, tc_TDNestCnt from
- ; user stack.
-
- @d
- @40dSet USP image in task descriptor.
- @40dRestore interrupt disable level.
- @d
- @d
- @40dDisable interrupts if needed.
- @d
-
-
- ---------------------------------------------------------------------------
- Switch()
-
- [Version for machines with a 68881 FPP]
- ---------------------------------------------------------------------------
-
- @a?fc108a
- FC108A move #$2000,SR Enable all interrupts.
- @a=fc108e
- @40dStore A5 on the supervisor stack.
- @40dGet the user stack pointer.
- @40dSave all registers on user stack.
- @40dGet ExecBase.
- @40dGet current interrupt disable level.
- @40dSet interrupt disable level to -1.
- @40dEnable interrupts.
- @40dFix A5 in the saved register set.
- @40dSave the status register.
- @40dSave the program counter.
-
- ; 68020/68881 specific material. Without documentation for those
- ; processors, I can't comment this.
-
- @a?fc10b4
- FC10B4 fsave -(A5)
- @a=fc10b6
- @d
- @d
- @d
- @d
- @d
- @d
- @d
- @d
- @d
- @d
- @d
- @d
- @d
- @a?fc10d6
- FC10D6 fmovem.x FP0-FP7,-(A5)
- FC10DA fmovem.l FPCR/FPSR/FPIAR,-(A5)
- @a=fc10de
- @d
-
- @40dPoint to 68881 context restore.
-
- ; The rest of the processing for Switch() is the same, so enter
- ; the "plain" version in the middle.
-
- @d
-
-
- ---------------------------------------------------------------------------
- Dispatch()
-
- [Version for machines with a 68881 FPP]
- ---------------------------------------------------------------------------
-
- @40dPoint to 68881 context-restore.
-
- ; The regular Dispatch() can be used for the rest.
-
- @d
-
-
- ; Special 68881 FPP compatible context restore
- ; --------------------------------------------
-
- ; 68020/68881 specific material. Without documentation for those
- ; processors, I can't comment this.
-
- @d
- @d
- @d
- @a?fc10f6
- FC10F6 fmovem.l (A5)+,FPCR/FPSR/FPIAR
- FC10FA fmovem.x (A5)+,FP0-FP7
- @a=fc10fe
- @d
- @d
- @d
- @d
- @d
- @d
- @d
- @a?fc1110
- FC1110 frestore (A5)+
- @a=fc1112
-
- @40dThis part is the same as the regular
- @40dcontext-restore routine.
- @d
- @d
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- oldSR = SetSR( newSR, mask)
- D0 D0 D1
- ---------------------------------------------------------------------------
-
- @d
- @36dWhat to execute in supervisor mode.
- @36dEnter supervisor mode.
- @d
-
- @36dNow in supervisor mode. Restore A5.
- @36dGet status register from stack.
- @36dMask unwanted bits out of newSR.
- @d
- @36dGet unchanged bits from old status reg.
- @36dOr in the bits to be changed.
- @d
- @36dReturn old status codes in D0.
- @36dLoad status reg. and return to user mode.
-
-
- ---------------------------------------------------------------------------
- conditions = GetCC()
- D0
-
- [Version for 68000 machines only]
- ---------------------------------------------------------------------------
-
- ; The ExecBase vector will have been changed not to point here
- ; unless the CPU is a 68000, since the following instruction would
- ; bomb with a privilege violation on 68010/020 processors.
-
- @a?fc1140
- FC1140 move SR,D0 Get the status register.
- @a=fc1142
- @36dClear all but the condition codes.
- @d
-
-
- ---------------------------------------------------------------------------
- oldSysStack = SuperState()
- D0
- ---------------------------------------------------------------------------
-
- @d
- @36dWhat to execute in supervisor mode.
- @36dEnter supervisor mode.
- @d
-
- @36dContinue here. Restore A5.
- @d
- @36dSet supervisor bit in status word.
- @36dDo nothing more if it was already set.
-
- @a?fc115e
- FC115E move (SP)+,SR Get status register from stack.
- @a=fc1160
- @36dSave supervisor stack pointer.
- @36dLoad user stack pointer.
-
- @36dCheck if running on a plain 68000.
- @d
- @36dPop 68010/020 exception info from stack.
- @36dPop exception return address from stack.
-
- @36dReturn to user.
-
- @d
-
-
- ---------------------------------------------------------------------------
- UserState( sysStack )
- D0
- ---------------------------------------------------------------------------
-
- @d
- @36dWhere to go in supervisor mode.
- @36dEnter supervisor mode (just in case).
- @36dRestore A5.
- @36dGet status register from stack.
- @36dCopy stack pointer to user stack pointer.
- @36dSet the system stack pointer.
- @36dClear the supervisor mode bit.
- @a?fc118a
- FC118A move D1,SR
- @a=fc118c
- @36dReturn to the user.
-
-
- ---------------------------------------------------------------------------
- oldInterrupt = SetIntVector( intNumber, interrupt )
- D0 D0 A1
- ---------------------------------------------------------------------------
-
- ; This routine makes an interrupt node the active interrupt node
- ; for a given interrupt number. This node corresponds to an
- ; interrupt handler. There can only be one node associated with
- ; each interrupt number.
-
- ; Note: Never try to SetIntVector() one of the interrupts which are
- ; dispatched as chains of servers. The handler which does this
- ; does not use regular interrupt vectors or nodes, and it would not
- ; be possible to hook it up to the interrupt again if it became
- ; disconnected.
-
- @36dCompute address of
- @36dExecBase->IntVects[intNumber]
-
- @36dDisable()
- @d
-
- @36dGet pointer to current interrupt node.
- @36dInstall pointer to new interrupt node.
-
- @36dIf there is a new node, then
- @36d Install interrupt data pointer.
- @36d Install interrupt code pointer.
- @36dElse
- @36d Set code and data pointers to -1.
- @d
- @36dEndif
-
- @36dEnable()
- @d
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- AddIntServer( intNumber, interrupt )
- D0 A1
- ---------------------------------------------------------------------------
-
- ; Adds an interrupt server to the server chain for a given
- ; interrupt number. The interrupt number must be one of the
- ; set for which interrupt server lists have been set up.
-
- ; The interrupt for which the server is being added will be enabled
- ; if it is not already enabled.
-
- @d
- @36dSave interrupt number.
- @d
- @36dCompute
- @36dExecBase->IntVects[intNumber].is_Node
- @d
-
- @36dDisable()
- @d
-
- @36dEnqueue the interrupt server.
-
- @36dHardware-enable the interrupt
- @36dcorresponding to the server just added.
- @d
-
- @36dEnable()
- @d
- @d
-
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- RemIntServer( intNumber, interrupt )
- D0 A1
- ---------------------------------------------------------------------------
-
- ; This routine takes an interrupt server off the server chain for
- ; a given interrupt. The interrupt is disabled if this leaves the
- ; server chain empty.
-
- @d
- @36dCompute
- @36dExecBase->IntVects[intNumber].is_Node
- @d
-
- @36dSave interrupt number and node.
- @d
-
- @36dDisable()
- @d
-
- @36dUnlink interrupt server from the chain.
- @d
- @36dCheck if the chain is now empty.
- @d
-
- @36dChain is empty. Disable the interrupt
- @36dcorresponding to this node.
- @d
-
- @36dEnable()
- @d
- @d
-
- @d
- @d
-
-
- ; The following routine is used at system startup to initialize
- ; the exec's internal interrupt handlers.
-
- ; It initializes the server chains used to dispatch servers for
- ; I/O and timer, Copper, vertical blank, external level 6, and
- ; non-maskable interrupts, and establishes vectors to the exec's
- ; built-in interrupt handlers.
-
- ; For each server chain, a 22-byte data structure is built,
- ; consisting of a list header and 4 words of control data. The
- ; 5 server chain headers are put into a contiguous 110-byte
- ; section of memory. The server chains are initialized to empty,
- ; and the rest of the data structure is initialized with the
- ; data required to assert, deassert, and cancel the interrupt.
-
-
- @d
- @36d110 bytes needed.
- @36dAttributes = MEMF_PUBLIC | MEMF_CLEAR.
- @36dRequest memory.
- @36dSee if we got the memory.
- @d
- @36dIf not, it's guru time!
- @36dUse this alert number.
- @36dGet ExecBase.
- @36dGo put up the alert.
- @36dNever reached.
-
- @36dLoop 5 times (4 + 1 for dbra).
- @36dGet pointer to allocated memory.
- @36dPoint to the data table below.
-
- ; Loop: Divide the 110 byte data area up into five data
- ; structures, each consisting of a list header and some control
- ; words.
-
- @36dSave pointer to current node.
- @36dInitialize the node's server chain
- @36dto empty.
- @d
- @d
-
- @36dPoint to the node's data area.
- @36dGet interrupt number from table.
- @36dMake the control word needed to disable
- @36dthis interrupt.
- @36dWrite it in the node's data area.
- @36dMake the control word needed to enable
- @36dthis interrupt and store it also.
- @36dGet the cancel interrupt control word.
- @36dMove a word of pad data.
- @36dPoint to the generic interrupt handler.
-
- ; Set up this interrupt in the exec table. The interrupt vector
- ; is at ExecBase + $54 + 12 * interrupt number. We write the code
- ; and data addresses only; we don't bother with the node address.
-
- @d
- @d
-
- @36dLoop until all interrupts done.
-
- ; Install the address of the software interrupt handler. The
- ; software interrupt lists have already been cleared earlier in
- ; the system startup code.
-
- @d
-
- ; Now enable interrupts and exit. Note that only the software
- ; interrupts are enabled. The interrupts handled by the handler
- ; below will be enabled if and when servers are put on their
- ; chains. Interrupts handled external to the exec must be enabled
- ; by whoever provides the handler.
-
- @d
- @d
- @d
-
-
- ; Interrupt initialization table. Each line consists of an
- ; interrupt number, and a control word which is used to cancel
- ; the interrupt if pending. The last column appears to be padding.
-
-
- @8p@5w@5w@w
- @8p@5w@5w@w
- @8p@5w@5w@w
- @8p@5w@5w@w
- @8p@5w@5w@w
-
-
- ; Generic Interrupt Handler
- ; -------------------------
-
- ; Each logical interrupt (0-15) has a handler. Some logical
- ; interrupts are accessible to the user not as handlers, but rather,
- ; as chains of servers. Most of these (all but the Blitter one)
- ; use this code, which acts as a handler and dispatches the servers.
-
- ; A data structure set up by the previous routine exists for each
- ; interrupt to store the list header for the server chain, and some
- ; control words.
-
- @d
- @d
- @35dCheck the head of the server chain.
-
- ; Main loop: Here we dispatch a server from the queue.
-
- @35dIs this the end of the chain?
- @35dIf so, exit.
- @35dGet the server's code and data addresses.
- @35dCall it.
-
- ; Servers return with the zero flag indicating whether they have
- ; taken care of the interrupt. We keep calling servers until
- ; we either run out or until one returns the zero flag clear.
-
- @35dIf the zero flag is clear, exit.
- @35dGo to next node in the queue.
- @35dGo back to top of loop.
-
- ; Either we ran out of servers, or one of them accepted the
- ; interrupt. Either way, clear the interrupt and exit.
-
- @d
- @35dClear the interrupt.
- @d
-
-
- ---------------------------------------------------------------------------
- Cause( interrupt )
- A1
- ---------------------------------------------------------------------------
-
- @36dDisable()
- @d
-
- @36dCheck if node type is already NT_SOFTINT.
- @36dIf so, do nothing.
-
- @36dMake node type NT_SOFTINT.
- @d
- @36dGet node priority.
- @36dTruncate to a multiple of 16.
- @36dSign extend to a word quantity.
- @36dPoint at middle of ExecBase->SoftInts
- @36dGet address of SoftInts entry correspon-
- ding to this priority (-32,-16,0,16,32).
-
- ; Now enqueue the node on the SoftIntList for this priority.
-
- @d
- @36dGet old TailPred pointer.
- @36dSet TailPred pointer to new node.
- @36dSet forward pointer of new node.
- @36dSet back pointer of new node.
- @d
- @36dSet forward pointer of old tail node.
-
- @36dSet the software interrupt pending flag.
- @36dGenerate a level 1 "software" interrupt.
- @36dEnable()
- @d
- @d
- @d
-
- ; Software Interrupt Handler
- ; --------------------------
-
- ; This is the interrupt handler for logical interrupt #2, which
- ; is used for software interrupts. It will be called as soon after
- ; the above routine as its interrupt priority will allow.
-
- @36dClear the interrupt.
- @36dClear the software int. pending flag.
- @36dIf it wasn't set, ignore the interrupt.
- @d
-
- @36dDisable further software interrupts.
- @36dGo and scan the SoftInts table.
-
- ; This code is called (from below) when a non-empty SoftIntList
- ; has been found. The pointer of the list will be in A0.
-
- @a?fc139c
- FC139C move.w #$2700,SR Mask all maskable interrupts.
- @a=fc13a0
- @36dGet the pointer to the first list node.
- @d
- @d
- @36dUnlink the node from the list.
- @d
- @d
- @d
- @36dMake the node type NT_INTERRUPT.
- @a?fc13b6
- FC13B6 move.w #$2000,SR Enable all interrupts.
- @a=fc13ba
- @36dGet the interrupt code and data.
- @36dCall the node's interrupt handler.
-
- ; The following scans the SoftInts[] table for non-empty
- ; SoftIntLists. If it finds one, it executes the code above.
-
- @36dLoop 5 times (1 less for dbra).
- @36dStart at SoftInts[4] (priority 32).
- @36dClear the software interrupt.
- @36dSee if there are any nodes on this list.
- @36dIf so, process the list.
- @36dOtherwise, go to next lower priority,
- @36dand loop back.
-
- ; No (more) nodes found.
-
- @a?fc13de
- FC13DE move #$2100,SR
- @a=fc13e2
- @36dReenable software interrupts and exit.
- @d
-
-
- ---------------------------------------------------------------------------
- Disable()
- ---------------------------------------------------------------------------
-
- ; Hardware disable all interrupts, and log the fact that this
- ; was done in the interrupt disable nesting level counter.
-
- @d
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- Enable()
- ---------------------------------------------------------------------------
-
- ; Decrement the interrupt level nesting counter, and if it goes
- ; negative, enable interrupts again.
-
- @d
- @d
- @d
- @d
-
- @8p@28wPadding.
-
-
- ---------------------------------------------------------------------------
- AddLibrary( library )
- A1
- ---------------------------------------------------------------------------
-
- @36dPoint to system library list.
- @36dAdd the library to the list.
- @36dUpdate the library vector checksum.
- @d
-
-
- ---------------------------------------------------------------------------
- error = RemLibrary( library )
- D0 A1
- ---------------------------------------------------------------------------
-
- ; NOTE: Some other part of the system, presumably DOS, will patch
- ; itself in ahead of this.
-
- @d
- @36dForbid()
- @36dSave ExecBase.
- @d
- @36dCall the library's Expunge() function.
- @36dRestore ExecBase.
- @36dPermit()
- @d
-
-
- ---------------------------------------------------------------------------
- library = OldOpenLibrary( libName )
- D0 A1
- ---------------------------------------------------------------------------
-
- ; This is just OpenLibrary() without the "version" parameter.
-
- @36dAny version of the library will do.
- @36dOpenLibrary()
- @d
-
-
- ---------------------------------------------------------------------------
- library = OpenLibrary( libName, version )
- D0 A1 D0
- ---------------------------------------------------------------------------
-
- ; NOTE: Some other part of the system, presumably DOS, will patch
- ; itself in ahead of this, presumably so it can pull libraries off
- ; disk if they aren't already in the library list.
-
- ; Note how several versions of a library can be in the system
- ; library list (although the initial RomTag system of putting them
- ; there will only take the newest one), and this routine will keep
- ; looking for one new enough to satisfy the request if it finds
- ; one which is too old.
-
- @d
- @d
- @36dForbid()
- @36dPoint to the system library list.
- @36dFindName()
- @36dDid we find the library?
- @36dReturn zero and exit if not.
- @d
- @36dCheck the version number.
- @36dTry to find another one if too old.
-
- ; We have an acceptable library.
-
- @36dSave ExecBase.
- @36dPoint A6 at the library base address.
- @36dCall the library's Open() function.
- @36dRestore ExecBase.
- @36dPermit()
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- CloseLibrary( library )
- A1
- ---------------------------------------------------------------------------
-
- ; NOTE: Some other part of the system, presumably DOS, will patch
- ; itself in ahead of this.
-
- @36dForbid()
- @36dSave ExecBase.
- @d
- @36dCall the library's Close() function.
- @36dRestore ExecBase.
- @36dPermit()
- @d
-
-
- ---------------------------------------------------------------------------
- oldFunc = SetFunction( library, funcOffset, funcEntry )
- D0 A1 A0.W D0
- ---------------------------------------------------------------------------
-
- @36dIndicate that library is modified.
- @36dCompute address of jump instruction.
- @36dGet the old jump destination address.
- @36dInstall a "JMP" instruction.
- @36dInstall the new destination address.
- @36dRe-checksum the library.
- @36dReturn the previous jump destination.
- @d
-
-
- ---------------------------------------------------------------------------
- SumLibrary( library )
- A1
- ---------------------------------------------------------------------------
-
- @36dCheck the "sum used" flag.
- @36dIf sum not used, then don't bother.
-
- @d
- @36dClear the "changed" flag.
- @d
- @36dIf the flag was set, clear the checksum.
- @d
- @36dGet the negative size.
- @36dDivide by 2 (gives size in words).
- @36dStart the sum at zero.
- @d
-
- ; Loop: Add up all the 16-bit words in the library's jump vector.
-
- @d
- @d
-
- @36dGet the old checksum.
- @d
- @36dOld checksum wasn't zero, so compare
- @36dit to the new checksum.
-
- ; Checksums didn't match, so put up an alert.
-
- @d
- @36dLibrary checksum alert number.
- @d
- @36dCall the alert function.
- @d
-
- @36dStore the new checksum in the library.
-
- @36dEnable multitasking.
- @d
-
-
- ---------------------------------------------------------------------------
- library = MakeLibrary( vectors, structure, init, dataSize, segList )
- D0 A0 A1 A2 D0 D1
- ---------------------------------------------------------------------------
-
- @d
-
- @36dSize of library data area.
- @36dPointer to library vector table.
- @36dPointer to initialization structure.
- @36dFunction to call after creating library.
- @36dSegList (for DOS use).
- @36dGet pointer to vector table.
- @36dSkip the following if no vectors.
-
- @d
- @d
- @36dCheck if vector data is absolute or
- @36drelative (first word = -1).
- @d
- @36dRelative vectors. Skip over the flag.
- @36dCount the vectors up to the terminating
- @36dflag. D3 holds -(number of vectors + 1)
- @d
- @36dAbsolute vectors. Count as above.
- @d
- @36dMake number of vectors positive.
- @36dMultiply by 6.
-
- @d
- @36dAdd size of data area.
-
- @36dMEMF_PUBLIC | MEMF_CLEAR
- @36dRequest memory for library node.
-
- @36dSee if the memory was allocated.
- @d
- @36dDidn't get any memory. Fail by returning
- @36da nil pointer to the caller.
-
- @36dPoint to start of allocated memory.
- @36dSkip over jump vector area.
- @36dInstall negative size in library node.
- @36dInstall positive size.
- @d
- @36dClear A2.
- @36dPoint at vector table again.
- @36dCheck if vectors are relative.
- @d
- @36dIf vectors are relative, skip over flag,
- @36dand set A2 to vector table address.
-
- @36dInstall the jump vector.
-
- @36dCheck if there is an initialization
- @36dstructure. Skip the following if not.
-
- @d
- @d
- @36dDo not clear memory before initializing.
- @36dProcess the initialization structure.
-
- @36dGet pointer to library node.
- @36dCheck if there is initialization code.
- @36dSkip the following if not.
-
- @36dGet the address of the code.
- @36dGet the address of the segList
- @36dCall the initialization code.
-
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- size = MakeFunctions( vectors, offset )
- D0 A1 A2
- ---------------------------------------------------------------------------
-
- @d
- @36dClear size counter.
- @36dCheck if vector table is relative.
- @d
-
- ; Process a relative vector initialization table.
-
- @36dGet a relative table entry.
- @36dCheck if end of table marker.
- @d
- @36dCompute absolute vector address.
- @36dInstall in jump vector.
- @36dInstall "JMP" instruction.
- @36dIncrement size counter.
- @d
-
- ; Process an absolute vector initialization table.
-
- @36dGet an absolute table entry.
- @36dCheck if end of table marker.
- @d
- @36dInstall it in the jump table.
- @36dInstall "JMP" instruction.
- @36dIncrement size counter.
- @d
-
- @36dDone, return to caller.
- @d
-
-
- ---------------------------------------------------------------------------
- Insert( list, node, listNode )
- A0 A1 A2
- ---------------------------------------------------------------------------
-
- @32dCheck if node to insert after is zero.
- @32dIf so, do an AddHead instead.
-
- @32dSee if list node indicates end of list.
- @32dBranch if so.
-
- ; If we get this far, A2 must point to a list node.
-
- @d
- @32dSet forward and back pointers of new node.
- @32dSet back pointer of next node.
- @32dSet forward pointer of previous node.
- @d
-
- ; The "Successor" field of the listNode was zero, i.e. listNode
- ; is really the end of list marker. In this case, insert just
- ; before listNode, i.e. at the end of the list (undocumented).
-
- @32dSet forward pointer of new node to end.
- @32dGet old TailPred pointer
- @32dLink previous end node to new node.
- @32dSet the TailPred pointer to the new node.
- @32dLink this node to the previous end node.
- @d
-
-
- ---------------------------------------------------------------------------
- AddHead( list, node )
- A0 A1
- ---------------------------------------------------------------------------
-
- @32dGet old pointer to first node.
- @32dMake the first node the new node.
- @32dSet forward and back pointers in new node.
- @d
- @32dFix back pointer in previous first node.
- @d
-
-
- ---------------------------------------------------------------------------
- AddTail( list, node )
- A0 A1
- ---------------------------------------------------------------------------
-
- @32dPoint A0 to list's "Tail" field.
- @32dSave old value of TailPred field.
- @32dMake the new node the last node.
- @32dSet new node's back pointer to list header.
- @32dSet new node's back pointer.
- @d
- @32dLink new node to previous last node.
- @d
-
-
- ---------------------------------------------------------------------------
- Remove( node )
- A1
- ---------------------------------------------------------------------------
-
- @32dGet pointer to successor node.
- @32dGet pointer to predecessor node.
- @32dPoint predecessor to successor.
- @32dPoint successor to predecessor.
- @d
-
-
- ---------------------------------------------------------------------------
- node = RemHead( list )
- D0 A0
- ---------------------------------------------------------------------------
-
- @32dGet list's head pointer.
- @32dGet first node's successor.
- @32dIf zero, list is empty, so return zero.
-
- @32dPoint head pointer past removed node.
- @d
- @32dPoint new head node back at list header.
- @d
-
-
- ---------------------------------------------------------------------------
- node = RemTail( list )
- D0 A0
- ---------------------------------------------------------------------------
-
- @a?fc161e
- @32dGet list's TailPred pointer.
- @32dCheck if the last node has a predecessor.
- @32dIf not, the list is empty, so return zero.
- @32dPoint TailPred pointer at second-last node.
- @d
- @32dPoint second-last node at the list header.
- @32dIncrement to point at "Tail" field.
- @d
-
-
- ---------------------------------------------------------------------------
- Enqueue( list, node )
- A0 A1
- ---------------------------------------------------------------------------
-
- @32dGet the priority field of the node.
- @32dGet the head pointer of the queue.
-
- ; Loop: Keep skipping nodes until the end of the list is
- ; reached or the next node has a lower priority.
-
- @32dPoint at the current node.
- @32dCheck if there is a successor.
- @32dIf not, we are at the end of the list.
- @32dCompare priorities.
- @32dLoop until priority is lower than new node's.
-
- ; A0 now points at the node to insert before, or at the end
- ; of the list (i.e. the list header plus 4).
-
- @32dGet old value of back pointer
- (or TailPred pointer of list header).
- @32dChange it to point to the new node.
- @32dSet new node's forward pointer.
- @32dSet new node's back pointer to last node
- skipped, or list header.
- @d
- @32dSet list's head field, or forward pointer
- of previous node, to new node.
- @d
-
-
- ---------------------------------------------------------------------------
- node = FindName( start, name )
- D0 A0 A1
- ---------------------------------------------------------------------------
-
- @d
- @36dPoint to list header or first node.
- @36dSave address of match string in D1.
- @d
- @36dExit if list is empty.
-
- ; Main loop: Check if node pointed to by D0 has the same name
- ; as the string pointed to by D1.
-
- @36dGet the address of the node to check.
- @d
- @36dExit if this is the end of the list.
-
- @36dPoint A0 at name of this node.
- @36dPoint A1 at match string.
-
- ; Inner loop: Compare the strings.
-
- @36dCompare one character.
- @36dSkip to next node if not equal.
- @36dWas this the terminating zero?
- @36dContinue comparing if not.
-
- @36dGot a match - point D0 to the node.
-
- @36dRestore registers and exit.
- @d
- @d
-
- ; Protected enqueue and dequeue routines
- ; --------------------------------------
-
- @36dForbid()
- @36dEnqueue()
- @36dPermit()
- @d
-
- @36dForbid()
- @36dRemove()
- @36dPermit()
- @d
-
-
- ---------------------------------------------------------------------------
- memoryBlock = Allocate( freeList, byteSize )
- D0 A0 D0
- ---------------------------------------------------------------------------
-
- @36dZero bytes requested?
- @36dIf so, just return.
- @d
- @36dRound D0 up to nearest multiple of 8.
- @d
- @d
- @36dCompare D0 to total number of bytes free.
- @36dIf greater, return zero.
- @36dPoint at the link to the first MemChunk.
-
- ; Loop: Scan the free list for a MemChunk big enough to satisfy
- ; the request.
-
- @36dGet the pointer to the next MemChunk.
- @36dIf no more MemChunks, return zero.
- @d
- @36dCheck D0 against size of this chunk.
- @36dIf smaller or equal, take it.
- @36dOtherwise, go to next MemChunk.
- @36dContinue searching.
-
- ; This is where memory fragmentation occurs. If the block we've
- ; found is bigger than what we need, we take what we need and make
- ; a smaller block out of the rest.
-
- @36dIf sizes are not the same, then
- @36d Compute address of leftover block.
- @36d Move the MemChunk pointer up.
- @36d Get the current size.
- @36d Subtract the allocated amount.
- @36d Put it into the new MemChunk.
- @36d Link to previous MemChunk (or header).
- @36dElse
- @36d Unlink this MemChunk.
- Endif
- @36dDecrease free memory value in header.
- @36dGet address of allocated block.
-
- @36dReturn zero or address of block.
- @d
- @d
-
- ; Routine to put up a "Corrupt Free List" dead-end alert.
-
- @a?fc16ee
- @d
- @36dAlert number.
- @36dGet ExecBase.
- @36dPut up the alert.
- @36dNever reached.
-
-
- ---------------------------------------------------------------------------
- Deallocate( freeList, memoryBlock, byteSize )
- A0 A1 D0
- ---------------------------------------------------------------------------
-
- @36dSee if byte size is zero.
- @36dDo nothing if so.
- @d
- @d
- @36dTruncate block address to nearest
- @36dmultiple of 8.
- @36dFind out by how much that decreased
- @36dthe address, then add this amount to
- @36dthe number of bytes to free.
- @36dNow round number of bytes to free up to
- @36dnearest multiple of 8.
- @36dExit if the result is zero bytes.
-
- ; Block address and size are now nice multiples of 8, so we can
- ; go ahead and put the block into the free list.
-
- @36dPoint at the link to the first MemChunk.
- @36dGet the address of the first MemChunk.
- @36dBranch if there are no MemChunks.
-
- ; Main loop: Find the first MemChunk with an address greater than
- ; that of our memory block.
-
- @36dCompare addresses.
- @36dExit loop if right MemChunk found.
- @36dIf addresses are equal, guru time!
- @d
- @36dGet address of next MemChunk.
- @36dContinue searching.
-
- ; A2 now points at the link which comes directly before the position
- ; where our block must be inserted. First, we check whether this
- ; is the start of the list. If so, we just link it in.
-
- @36dCompute address of MemHeader's link.
- @d
- @36dSee if A2 still points there.
- @36dIf so, insert block at head of the list.
-
- ; We are somewhere other than at the start of the list. It is
- ; possible that we can join the block to the previous MemChunk.
- ; Try this now.
-
- @36dCompute first address after the
- @36dprevious MemChunk.
- @36dCompare to address of our new block.
- @36dIf equal, join the two together.
- @36dIf greater, free list is corrupt.
-
- ; Enter here to make a new MemChunk and link it into the free list.
-
- @36dSet new MemChunk's link field.
- @36dPoint previous link at the MemChunk.
- @36dPut the block size into the MemChunk.
- @d
-
- ; Enter here to attach the new block to the previous MemChunk.
-
- @36dAdd to previous MemChunk's size.
- @36dBack pointer up to that MemChunk.
-
- ; Now the block is taken care of. Either we have built a MemChunk
- ; for it, or we have attached it to a MemChunk directly before the
- ; block. Either way, the address of the MemChunk where the block
- ; now is is in A1. It remains to check whether we can join this
- ; MemChunk with the next one down the line.
-
- @36dSee if there is a next MemChunk.
- @36dExit if not.
- @36dGet our MemChunk's size.
- @36dAdd to its base address.
- @36dCompare to address of next MemChunk.
- @36dIf higher, free list is corrupt.
- @36dIf not equal, we can't join them.
-
- ; If we get this far, we can join this MemChunk to the next one down
- ; the line, so we delete the next one and add its size to this one.
-
- @36dGet pointer to next MemChunk.
- @36dFetch its link and put in our MemChunk.
- @36dGet its size.
- @36dAdd to size of our MemChunk.
-
- ; This is where all the paths meet again.
-
- @36dAdd size of freed block to free counter.
- @d
- @d
-
- ; Error exit routine. Generate a dead-end alert.
-
- @d
- @36dAlert number.
- @36dGet ExecBase.
- @36dGo put up the alert.
- @36dNever reached.
-
-
- ---------------------------------------------------------------------------
- memoryBlock = AllocMem( byteSize, requirements )
- D0 D0 D1
- ---------------------------------------------------------------------------
-
- ; NOTE: Some other part of the system, presumably DOS, will patch
- ; itself in ahead of this, presumably so it can throw out unused
- ; libraries, devices, fonts, etc. when memory runs low.
-
- @36dForbid()
- @d
- @d
- @d
- @36dPoint to the system free memory list.
-
- ; Loop: Step through the system free memory list looking for
- ; a MemHeader which can satisfy the memory request.
-
- @36dGet pointer to a MemHeader.
- @36dEnd of memory list reached?
- @d
- @36dIf so, return a null pointer and exit.
- @d
- @36dGet the MemHeader's attributes.
- @36dCheck against needed attributes.
- @d
- @36dGo to next MemHeader if not present.
-
- ; The current MemHeader has the right attribute flags, now try
- ; to get a block of the required size out of its free list.
-
- @36dPoint to the MemHeader.
- @36dIndicate size of block required.
- @36dAllocate()
- @36dDid we get the memory?
- @36dIf not, go to next MemHeader.
-
- ; We got a memory block. Clear it if necessary.
-
- @36dWas the MEMF_CLEAR flag set?
- @36dJust return if not.
- @d
- @36dConvert number of bytes to nearest number
- @36dof longwords.
- @36dPoint to the memory block.
- @36dEnter the loop at the bottom.
-
- ; Loop: Clear the memory block.
-
- @36dClear one longword.
- @36dLoop back until none remain.
-
- @36dDBRA instruction only uses low 16 bits
- @36das program counter, so if any remain
- @36dset in the upper half of D3, decrement
- @36dthem manually and loop back.
- @d
- @d
-
- @36dPermit()
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- FreeMem( memoryBlock, byteSize )
- A1 D0
- ---------------------------------------------------------------------------
-
- @36dForbid()
- @36dIs number of bytes to free zero?
- @36dIf so, just exit.
- @36dPoint to system free memory list.
-
- ; Loop: Look for the right MemHeader to put the block back into.
-
- @36dPoint to the next MemHeader.
- @36dEnd of list reached?
-
- ; If no MemHeader can be found to put this block on, something
- ; is wrong, so it's guru time.
-
- @36dGuru time if end of list reached.
-
- ; See if the block falls into the address range covered by this
- ; MemHeader.
-
- @36dDoes block start before mh_Lower?
- @36dIf so, try next MemHeader.
- @36dDoes block start after mh_Upper?
- @36dIf so, try next MemHeader.
-
- ; The block belongs to this MemHeader, so go link it back into
- ; the free list.
-
- @36dDeallocate()
- @36dPermit()
- @d
-
-
- ---------------------------------------------------------------------------
- attributes = TypeOfMem( address )
- D0 A1
- ---------------------------------------------------------------------------
-
- @36dForbid()
- @36dPoint to system free memory list.
- @d
- @36dPoint to next MemHeader.
- @36dEnd of list reached?
- @36dIf so, return zero and exit.
- @36dCheck if the block is in the address
- @36drange covered by this MemHeader.
- @d
- @36dIf it is, return the contents of the
- @36dMemHeader's attribute field.
- @36dPermit()
- @d
-
-
- ---------------------------------------------------------------------------
- memoryBlock = AllocAbs( byteSize, location )
- D0 D0 A1
- ---------------------------------------------------------------------------
-
- @36dForbid()
- @d
- @36dGet the start address.
- @36dTruncate down to nearest multiple of 8.
- @d
- @36dAdd any difference to number of bytes
- @36dwanted, then round number of bytes
- @36dup to nearest multiple of 8.
- @36dPoint to the system free memory list.
-
- ; Loop: Scan through all the MemHeaders in the free list.
-
- @36dPoint to next MemHeader.
- @36dEnd of list reached?
- @36dIf so, allocation failed, return zero.
-
- ; Check whether the block we want is covered by this MemHeader.
-
- @36dIf block starts before this MemHeader's
- @36darea, go on to the next one.
- @36dIf block starts after this MemHeader's
- @36darea, go on to next one.
-
- ; The desired block starts in the address range covered by this
- ; MemHeader, so it's either this one or nothing.
-
- ; Quick check: If the total number of bytes free in this MemHeader's
- ; free list is less than the size of the block wanted, then the
- ; allocation is going to fail anyway.
-
- @37dCheck block size against mh_Free.
- @37dAllocation failed if higher.
- @37dGet start address of block wanted.
- @d
- @37dCompute end address of block wanted.
- @37dPoint to link to first MemChunk.
-
- ; Loop: Find the MemChunk in the free list which contains the
- ; wanted block.
-
- @37dGet pointer to next MemChunk.
- @37dAllocation failed if no more MemChunks.
- @d
- @37dGet the MemChunk's size.
- @37dCompute its end address.
- @37dCheck against needed end address.
- @37dExit loop if equal or higher.
- @d
- @37dGo to the next MemChunk.
-
- ; We have a MemChunk whose end address is greater than or equal
- ; to the end address of the block we want. It's either this
- ; MemChunk or none at all.
-
- @37dCheck start addresses.
- @37dAllocation failed if needed block
- starts before this MemChunk.
-
- ; The block we want is entirely within this MemChunk, so now we
- ; cut it out and make zero, one or two MemChunks out of what's left.
-
- @37dRemove block size from free count.
- @37dCompare end addresses.
- @d
-
- ; The end addresses of the allocated block and the MemChunk it
- ; was in were exactly equal.
-
- @d
- @d
-
- ; Memory was left over between the allocated block and the end of
- ; the MemChunk. Make a new MemChunk out of this and link it into
- ; the free list.
-
- @37dCompute base address of new MemChunk.
- @37dStore pointer to next MemChunk.
- @37dLink to previous MemChunk.
- @37dStore number of bytes in MemChunk.
-
- ; At this point, whatever was left after the block was taken
- ; care of, and a pointer to the next MemChunk after the block is
- ; in A0.
-
- @37dCompare start addresses.
- @d
-
- ; The block started after the beginning of this MemChunk, so we
- ; just truncate the MemChunk to contain the leftover memory before
- ; the allocated block.
-
- @d
- @37dCompute remaining size.
- @37dStore in the MemChunk.
- @37dAll done.
-
- ; The block started exactly at the beginning of the MemChunk, so
- ; the MemChunk must be deleted.
-
- @37dUnlink this MemChunk from the chain.
- @37dReturn address of allocated block.
- @d
- @37dPermit()
- @d
-
- @37dReturn zero if allocation failed.
- @d
-
-
- ---------------------------------------------------------------------------
- size = AvailMem( requirements )
- D0 D1
- ---------------------------------------------------------------------------
-
- @d
- @36dInitialize free memory counter.
- @36dPoint at the ExecBase->MemList.
- @36dForbid()
- @d
- @36dGet address of first MemHeader.
- @36dExit if list is empty.
- @36dGet this MemHeader's attributes.
- @36dMask with required attributes.
- @36dCheck if all attributes are satisfied.
- @36dGo to next MemHeader if not.
- @36dAre we looking for the largest
- contiguous block of memory?
- @d
- @36dIf not, just add the size,
- @36dand loop back.
-
- ; We are looking for the largest contiguous block of memory.
-
- @36dGet address of first MemChunk.
- @36dLoop back if there is no MemChunk.
- @d
- @36dSee if this MemChunk is the biggest yet.
- @d
- @36dIf it is, keep its base address (why?),
- @36dand its size.
- @d
- @36dGo to next MemChunk.
- @36dPermit()
- @36dReturn the accumulated or largest size.
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- memList = AllocEntry( memList )
- D0 A0
- ---------------------------------------------------------------------------
-
- @d
- @36dSave pointer to request MemList.
- @36dClear loop counter.
- @d
- @36dGet the number of MemEntries.
- @d
- @36dCompute the size of the MemList needed
- @36dto keep track of the MemEntries.
- @36dSet MEMF_CLEAR.
- @36dAllocate that amount of memory.
- @36dIf we didn't get it, go exit.
- @d
- @36dPoint to base of new MemList structure.
- @36dPut in the number of MemEntries.
- @36dPoint to MemEntries in request MemList.
- @36dPoint to MemEntries in result MemList.
- For each MemEntry do
- @36d Get its required attributes.
- @36d Get its required size.
- @36d Store the size in the result list.
- @36d If size is not zero then
- @36d Allocate the memory.
- @36d Go exit if unsuccessful.
- @36d Endif
- @36d Store memory address in result list.
- @36d Go to next request MemEntry.
- @36d Go to next result MemEntry.
- @36d Increment loop counter.
- @36d Compare to number of MemEntries.
- @36dEndfor.
- @d
- @36dCompute -(size of MemEntry list).
- @36dPoint A2 back at the request MemList.
- @36dPoint A3 back at the result MemList.
- @36dReturn the address of the result MemList.
- @d
- @d
-
- ; Enter here if one of the MemEntries could not be allocated.
-
- @36dSave size of the allocate which failed.
- @36dTest number of allocated MemEntries.
- @36dExit if none remaining.
- @36dDecrement number of MemEntries.
- @36dPoint to the allocated MemEntry.
- @36dGet the address and size of the block
- @36dcorresponding to it.
- @36dDeallocate the block.
- @36dGo back and check for more MemEntries.
-
- ; Enter here if the AllocEntry failed, after deallocating anything
- ; which was allocated before the failure.
-
- @36dGet size of the allocate which failed.
- @d
- @36dSet the high bit.
- @36dReturn it to the user.
-
-
- ---------------------------------------------------------------------------
- FreeEntry( memList )
- A0
- ---------------------------------------------------------------------------
-
- @d
- @36dPoint to the MemList.
- @36dPoint to the first MemEntry.
- @36dGet number of MemEntries.
- @36dFor each MemEntry in the MemList do
- @36d Get the address of the memory block.
- @36d Get the sizde of the memory block.
- @36d If size is not zero then
- @36d Deallocate the block.
- @36d Endif
- @36dEndfor
- @d
- @36dGet the number of MemEntries again.
- @d
- @36dCompute the size of the MemList.
- @36dPoint to the base of the MemList.
- @36dDeallocate it.
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- error = AddMemList( size, attributes, pri, base, name )
- D0 D0 D1 D2 A0 A1
- ---------------------------------------------------------------------------
-
- ; This routine takes a block of memory, builds a MemHeader at the
- ; start of it, and puts the rest of the block into the MemHeader's
- ; free list. Then it adds the MemHeader to the system free memory
- ; list.
-
- @36dStore the name in the MemHeader.
- @36dCompute first address after MemHeader.
- @36dMemHeader's node type is NT_MEMORY.
- @36dSet the MemHeader's priority.
- @36dSet the memory attributes.
- @d
- @36dRound the base address of the block up
- @36dto the nearest multiple of 8.
- @d
- @36dCompute by how much it changed,
- @36dand add this amount to the length.
- @36dTruncate the length to a multiple of 8.
- @36dSubtract the size of the MemHeader.
- @36dStore base address as lower bound of
- @36dmemory and link to first MemChunk.
- @d
- @36dCompute upper bound address.
- @36dStore it in the MemHeader.
- @36dStore the amount of free memory.
- @36dBuild a MemChunk at the start of free
- @36dmemory (clear link, store size).
- @36dGet base address of MemHeader
- @36dPoint to the system free memory list.
- @36dPut the MemHeader on the list.
- @d
-
- @8p@28wPadding.
-
-
- ; Data table used to build the exec jump vector table.
-
- ; There are 105 entries, corresponding to the 105 exec functions,
- ; followed by a -1 table end marker. Each entry is a 16-bit
- ; relative offset from the start of the table.
-
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@9l@9l@9l@l
- @7p@w
-
- @7p@29wEnd of table marker.
-
- @7p@29wLooks like garbage.
- @7p@w
-
-
- ---------------------------------------------------------------------------
- AddPort( port )
- A1
- ---------------------------------------------------------------------------
-
- @36dAddress of port's message list.
- @36dInitialize the list's head pointer.
- @d
- @36dInitialize the list's Tail field.
- @36dInitialize the list's TailPred pointer.
- @36dAddress of the public message port list.
- @36dSafely add port to the list.
-
-
- ---------------------------------------------------------------------------
- RemPort( port )
- A1
- ---------------------------------------------------------------------------
- @a?fc1b30
-
- ; Call a general purpose subroutine which unlinks something from
- ; its queue while disabling multitasking.
-
- @d
-
-
- ---------------------------------------------------------------------------
- PutMsg( port, message )
- A0 A1
- ---------------------------------------------------------------------------
-
- @36dMake sure message node type is NT_MESSAGE
- @d
- @36dCompute address of port's message list
-
- @36dDisable()
- @d
-
- ; Enqueue the message at the end of the port's message list
-
- @36dPoint A0 at port's Tail field.
- @36dSave pointer to last node in list
- @36dMake new node the last node
- @36dNew node has no next node
- @36dLink new node back to old last node
- @d
- @36dLink old last node to new node
-
- ; Do whatever needs to be done on message arrival.
-
- @d
- @36dGet address of message port's task.
- @36dExit if port has no task.
-
- @36dGet port's flag bits.
- @d
- @36dDecode the flag bits.
- @d
- @d
-
- ; Processing for PA_SOFTINT
-
- @d
- @36dCause the software interrupt.
- @d
-
- ; If PA_IGNORE, do nothing.
-
- @d
- @d
-
- ; (Undocumented?) processing for mp_Flags = 3. Apparently,
- ; calls a subroutine at mp_SigTask.
-
- @d
- @d
- @d
-
- ; Processing for PA_SIGNAL
-
- @36dGet SigBit.
- @d
- @36dCompute corresponding signal mask.
- @d
- @d
- @36dSignal the task.
-
- @36dEnable()
- @d
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- message = GetMsg( port )
- D0 A0
- ---------------------------------------------------------------------------
-
- @36dPoint A0 at head of port's message list.
-
- @36dDisable()
- @d
-
- ; Try to dequeue a message from the message list.
-
- @36dGet head pointer into A1.
- @d
- @36dIf list is empty, just return zero.
- @d
- @36dUnlink the message from the list.
- @d
-
- ; Reenable interrupts if necessary and exit.
-
- @36dEnable()
- @d
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- ReplyMsg( message )
- A1
- ---------------------------------------------------------------------------
-
- @36dGet address of reply port.
- @d
- @36dNo reply port. Set node type to
- @36dNT_FREEMSG and exit.
-
- @36dSet node type to NT_REPLYMSG.
- @d
- @36dSend the message via the reply port.
-
-
- ---------------------------------------------------------------------------
- message = WaitPort( port )
- D0 A0
- ---------------------------------------------------------------------------
-
- @36dGet head pointer of port's message list.
- @36dCheck if list is empty.
- @36dIf not empty, return right away.
-
- @36dList was empty. Get signal bit.
- @36dPoint A0 at message list.
- @d
- @36dCompute signal mask.
- @d
- @d
- @36dWait()
- @d
- @36dCheck message list.
- @36dIf still empty, go back and wait again.
- @d
- @36dReturn first message in the list.
- @d
-
-
- ---------------------------------------------------------------------------
- port = FindPort( name )
- D0 A1
- ---------------------------------------------------------------------------
-
- @36dPoint to the public port list.
- @36dSearch it for a port of the given name.
- @d
-
-
- ---------------------------------------------------------------------------
- AddResource( resource )
- A1
- ---------------------------------------------------------------------------
-
- @36dPoint to the resource list.
- @36dAdd the resource to the list.
-
-
- ---------------------------------------------------------------------------
- RemResource( resource )
- A1
- ---------------------------------------------------------------------------
-
- @36dUnlink the resource from the list.
-
-
- ---------------------------------------------------------------------------
- resource = OpenResource( resName )
- D0 A1
- ---------------------------------------------------------------------------
-
- @36dPoint to the resource list.
- @36dForbid()
- @36dFindName()
- @36dPermit()
- @d
-
-
- @8p@28wPadding.
-
- ---------------------------------------------------------------------------
- AddTask( task, initialPC, finalPC )
- A1 A2 A3
- ---------------------------------------------------------------------------
-
- @d
- @36dMake the task state TS_ADDED.
- @36dClear the task's flags.
- @36dSet IDNestCnt and TDNestCnt to -1.
- @d
- @36dTask is not waiting for any signals.
- @36dTask has not received any signals.
- @36dTask does not have any exception signals.
- @36dSet allocated traps.
- @36dNo traps are enabled.
-
- @36dInstall default system exception handler
- @36dif the user has not provided one.
- @d
- @d
- @d
- @d
-
- @36dGet the initial stack pointer.
- @36dPut the exit code address on the stack.
- @d
- @36dUse system default if no exit code.
-
- @36dClear 15 longwords below the process's
- @36dinitial stack pointer, so all registers
- @36dwill be zero when initially loaded.
-
- @36dClear the initial status register.
- @36dPut the initial PC on the stack.
-
- @36dIf we have a 68881, then put another
- @36dlongword on the stack.
- @d
- @d
- @36dPut the initial stack pointer back.
-
- @d
- @36dDisable()
- @d
- @36dMake the task state TS_READY.
- @36dPut the task on the TaskReady queue.
- @d
- @36dEnable()
- @d
- @d
- @36dIf the task ended up at the front of the
- @36dTaskReady queue, then
- @36dReschedule()
- @d
-
- ; System default task exit function
- ; ---------------------------------
-
- @36dGet ExecBase.
- @d
- @36dAsk for current task to be removed.
-
- ; fall through into RemTask.
-
-
- ---------------------------------------------------------------------------
- RemTask( task )
- A1
- ---------------------------------------------------------------------------
-
- @d
- @36dCheck address of task to be removed.
- @36dBranch if not zero.
- @36dIf zero, use the current task.
- @d
- @36dIf not zero, check if it was the current
- @36dtask anyway.
-
- ; The following is executed only if the task to be removed is not
- ; the current one. This is because the currently running task isn't
- ; on a queue anywhere.
-
- @36dDisable()
- @d
- @36dUnlink the task from its queue.
- @d
- @36dEnable()
- @d
-
- @36dGet the address of the task back.
- @36dMake the task TS_REMOVED.
- @36dCheck if it is the current task.
- @d
- @36dIf so, disable task switching now.
-
- @36dPoint to allocated memory list.
- @d
- @36dExit if the head pointer is zero,
- @36dor if the tail pointer points back at
- @36dthe list header.
- @36dZero the list head pointer.
-
- ; Loop: Release all the memory blocks which the task had allocated.
-
- @36dGet pointer to current list node.
- @36dGet pointer to next list node.
- @36dExit if the end of the list was reached.
- @36dFreeEntry() this list node.
- @36dBack to the head of the loop.
-
- @36dCheck if the current task was removed.
- @36dIf not, indicate success and exit.
- @d
- @36dGo to supervisor mode.
- @36dPop exception data from the stack.
- @36dDispatch() a new task.
-
- @36dIf the current task was not removed,
- @36dindicate success and return.
- @d
-
-
- ---------------------------------------------------------------------------
- task = FindTask( name )
- D0 A1
- ---------------------------------------------------------------------------
-
- @36dSee if a name was given.
- @d
- @36dIf not, use this task.
- @d
- @36dPoint at the TaskReady queue.
- @36dDisable()
- @d
- @36dCall FindName() to look for the task.
- @36dCheck if found, return address if so.
- @d
- @36dTask not found, try TaskWait queue.
- @36dCall FindName() to look for the task.
- @36dCheck if found, return address if so.
- @d
- @36dStill not found, compare name with that
- @36dof the current task.
- @d
- @36dIf names differ, return zero (not found).
- @d
- @d
- @36dTask was the current task.
- @36dEnable()
- @d
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- oldPriority = SetTaskPri( task, priority )
- D0 A1 D0
- ---------------------------------------------------------------------------
-
- @36dDisable()
- @d
- @36dSave the task's current priority.
- @36dSet the task's new priority.
- @36dCheck if it was the current task.
- @36dIf so, go reschedule it.
- @36dCheck if the task was TS_READY.
- @36dIf not, we're done.
- @d
- @36dTake the task out of the TaskReady queue.
- @d
- @36dAnd put it back in the right place
- @36dcorresponding to its new priority.
- @36dSee if it ended up at the front.
- @36dIf not, we're done.
-
- ; If we get here, either we've changed the priority of the current
- ; task, or we've moved another task to the front of the TaskReady
- ; queue. Either way, we have to check if the current task should
- ; be preempted.
-
- @36dReschedule()
- @d
- @36dEnable()
- @d
- @d
- @36dReturn the previous priority.
- @d
-
-
- ---------------------------------------------------------------------------
- oldSignals = SetExcept( newSignals, signalMask )
- D0 D0 D1
- ---------------------------------------------------------------------------
-
- @36dGet pointer to current task.
- @36dPoint to its SigExcept longword.
- @36dDrop into SetSignal.
-
-
- ---------------------------------------------------------------------------
- oldSignals = SetSignal( newSignals, signalMask )
- D0 D0 D1
- ---------------------------------------------------------------------------
-
- @36dGet pointer to current task.
- @36dPoint to its SigRecvd longword.
-
- ; This code is common to SetExcept and SetSignal.
-
- @36dMask out signals to be left alone.
- @36dDisable()
- @d
- @36dSave current value of signal word.
- @36dMake mask of singnals to leave alone.
- @36dGet those signals only.
- @36dOr in the changed signals.
- @36dPut the result back in the task.
-
- ; Now we drop into Signal(), which will process any new signals
- ; we may have set in the SigRecvd longword.
-
- @36dGet the SigRecvd data.
- @36dDrop into Signal.
-
-
- ---------------------------------------------------------------------------
- Signal( task, signals )
- A1 D0
- ---------------------------------------------------------------------------
-
- @36dGet the set of received signals.
- @36dDisable()
- @d
- @36dStore the signals.
- @36dOr the new signals into the old ones.
-
- ; The code from here down is common to SetExcept, SetSignal, and
- ; Signal. It checks if the task whose signals are being modified
- ; should be awakened.
-
- @36dCheck the exception signals,
- @36dand see if any of them have become set.
- @36dIf so, go process them.
- @36dSee if the task is in the TS_WAIT state.
- @36dIf not, we're done.
- @36dSee if a signal being waited for has been
- @36dset. If not, we are done.
-
- ; We have set a signal which the task was currently waiting for,
- ; so we must awaken it. First, we take it out of the TaskWait
- ; list then we make it TS_READY, then we put it on the TaskReady
- ; queue and check if it should preempt the current task.
-
- @d
- @36dSave pointer to the task.
- @36dGet pointer to the next task in the list.
- @36dGet pointer to the previous task.
- @36dUnlink from the previous task.
- @36dUnlink from the next task.
- @36dRestore pointer to the task.
- @36dMake the task TS_READY.
- @36dPoint to the TaskReady queue.
- @36dEnqueue the task in the right place.
- @36dCheck if it was put at the head of the
- @36dTaskReady queue, and exit if not.
- @d
- @36dEnable()
- @d
- @36dReturn old signals to caller eventually.
- @36dReschedule() so the task can run.
-
- ; Enter here if we have set an exception signal, or if a previously
- ; set signal has become an exception signal.
-
- @36dSet the task's TB_EXCEPT flag.
- @36dSee if it is in the TS_WAIT state.
-
- ; If the task for which the exception occurred was in the TS_WAIT
- ; state, make it TS_READY and move it from the TaskWait list to
- ; the TaskReady queue. Otherwise, just dispatch it.
-
- @d
- @d
-
- ; Exit here if the current task was allowed to keep running (i.e.
- ; the other task did not preempt it).
-
- @36dEnable()
- @d
- @d
- @36dReturn old signals.
- @d
-
-
- ---------------------------------------------------------------------------
- signals = Wait( signalSet )
- D0 D0
- ---------------------------------------------------------------------------
-
- @36dGet the pointer to the current task.
- @36dRecord which signals we are waiting for.
- @36dDisable()
- @d
- @36dEnter the loop at the bottom.
-
- ; Main loop: We stay here until we have a signal we want.
-
- @36dMake the task state TS_WAIT.
- @36dPoint to the TaskWait list.
- @d
- @36dUnlink the task from the TaskReady
- @36dqueue, and put it in the TaskWait
- @36dlist.
- @d
- @d
- @d
-
- ; Here we block. Calling Switch() gives control to any other
- ; process. Eventually, someone else doing a Signal() will put us
- ; back on the TaskReady list, and then we will return from the
- ; Switch() when our priority comes up again.
-
- @36dSave A5.
- @36dGet ready to call Switch(), but first...
- @36dEnter Supervisor mode.
-
- ; We're back. See if we now have a signal we want.
-
- @36dRestore A5.
- @36dGet pointer to current process.
- @36dGet the signals we are waiting for.
-
- ; We initially enter here to see if we have to block at all, and
- ; again each time we have been unblocked to see if we can now
- ; continue running.
-
- @36dGet the signals which are currently set.
- @36dCheck against signals to wait for.
- @36dIf not, go back and block again.
-
- ; Eventually, we end up here. We now have one or more signals
- ; that were being waited for. We take these out of the set of
- ; received signals, since we will return them to the caller.
-
- @36dUpdate the set of received signals.
- @d
- @36dEnable()
- @d
- @36dReturn the signals.
- @d
-
-
- ---------------------------------------------------------------------------
- Reschedule()
- ---------------------------------------------------------------------------
-
- ; This function is used when it is possible that a task should
- ; be preempted and another task run in its place. It sets the
- ; scheduling attention flag to force the scheduler to do its thing
- ; as soon as possible. If multitasking is disabled, that's all
- ; it does, since Permit() will do the rest when multitasking is
- ; turned on again. If interrupts are disabled, it sets the software
- ; generated interrupt. Since this is not accompanied by setting
- ; the software interrupt pending flag, it will do nothing but
- ; run ExitIntr() as soon as the interrupt level allows it.
- ; ExitIntr() will then cause the outstanding scheduling operation
- ; to be done.
-
- ; Note that part of Permit() is used to switch into supervisor
- ; mode and call the scheduler.
-
- @36dSet the scheduling attention flag.
- @36dSave its previous state.
- @36dCheck if multitasking enabled.
- @36dIf not, exit.
- @36dCheck if interrupts enabled.
- @36dIf so, go and do the scheduling.
- @36dCheck the (old) scheduling attn flag.
- @36dExit if it was already set.
- @36dAssert the software generated interrupt.
- @d
-
-
- ---------------------------------------------------------------------------
- Forbid()
- ---------------------------------------------------------------------------
-
- @36dIncrement the TDNestCnt.
- @d
-
-
- ---------------------------------------------------------------------------
- Permit()
- ---------------------------------------------------------------------------
-
- @36dDecrement the TDNestCnt.
- @36dExit if still positive.
- @36dCheck if interrupts disabled.
- @36dExit if yes.
-
- ; The current task has just reenabled multitasking. If the system
- ; is waiting to switch tasks, now is the time to do it.
-
- @36dCheck the scheduling attention flag.
- @36dExit if not pending.
- @36dSave A5.
- @36dSet address to go to in supervisor mode.
- @36dEnter supervisor mode.
- @36dRestore A5 and return.
- @d
-
- ; This is executed in supervisor mode.
-
- @36dCheck caller's supervisor mode flag.
- @36dIf the caller was in supervisor mode,
- @36dthen don't switch tasks.
-
- ; Eventually, this task will be dispatched again, using the program
- ; counter and status register left on the stack by the supervisor
- ; mode call. Then it continues running above, pops A5 from the
- ; stack, and returns to the caller.
-
- @36dGo and do the scheduling.
-
-
- ---------------------------------------------------------------------------
- trapNum = AllocTrap( trapNum )
- D0 D0
- ---------------------------------------------------------------------------
-
- @36dGet pointer to the current task.
- @36dGet the task's TrapAlloc flags.
- @36dSee if we want a particular trap number.
- @d
- @36dIf so, set this trap number's flag bit.
- @36dIf it wasn't set, indicate success.
- @36dIt was already set, indicate failure.
-
- ; Look for a free trap number.
-
- @36d16 traps to check. Start at #15.
- @36dTry to set this trap's flag bit.
- @36dIf not set before, indicate success.
- @36dLoop until all flags checked.
- @36dIndicate failure.
- @36dPut updated trap flags back.
- @d
-
-
- ---------------------------------------------------------------------------
- FreeTrap( trapNum )
- D0
- ---------------------------------------------------------------------------
-
- @36dGet pointer to the current task.
- @36dGet the task's TrapAlloc flags.
- @36dClear the specified flag.
- @36dPut the flags back.
- @d
-
-
- ---------------------------------------------------------------------------
- signalNum = AllocSignal( signalNum )
- D0 D0
- ---------------------------------------------------------------------------
-
- @36dGet pointer to the current task.
- @36dGet the task's SigAlloc flags.
- @36dSee if we want a particular signal.
- @d
- @36dIf so, try to set its flag.
- @36dIndicate success if it was clear.
- @36dIndicate failure if already set.
-
- ; Look for a free signal.
-
- @36d32 Signals to check. Start at 31.
- @36dTry to set the signal's flag.
- @36dIf it wasn't already set, success.
- @36dOtherwise, keep looking.
- @36dIndicate failure.
- @d
-
- @36dSuccess. Update allocated signal flags.
- @d
- @36dSet all but this signal bit in D1.
- @36dMake sure this signal isn't set.
- @36dMake sure it's not an exception signal.
- @36dIndicate that we are not waiting for it.
- @d
-
-
- ---------------------------------------------------------------------------
- FreeSignal( signalNum )
- D0
- ---------------------------------------------------------------------------
-
- @36dGet pointer to the current task.
- @36dGet the SigAlloc flags.
- @36dClear the indicated signal bit.
- @36dPut the flags back.
- @d
-
-
- ; Subroutines for RawDoFmt()
- ; --------------------------
-
- ; Find the length of a null-terminated string pointed to by A0.
- ; For efficiency, the length is counted up as a negative number.
-
- @a?fc200c
- @40dStart the length at -1.
- @40dGet string character, test for end.
- @40dCount, and loop until end of string.
- @d
- @40dConvert length to correct +ve value.
- @d
-
-
- ; Evaluate a decimal numeric constant pointed to by A4.
-
- @40dStart the result at 0.
- @d
- @40dGet a character from the input.
- @a?fc2020
- FC2020 cmp.b #'0',D2
- @a=fc2024
- @d
- FC2026 cmp.b #'9',D2 If not a numeric digit, exit.
- @a=fc202a
- @d
- @40dMultiply previous result by 10.
- @d
- @d
- @d
- @d
- @a?fc2036
- FC2036 sub.b #'0',D2 Convert digit to number 0 - 9.
- @a=fc203a
- @40dAdd to result.
- @40dGo evaluate next character.
-
- ; Finish up by pointing back at the non-digit character.
-
- @40dBackspace the input pointer.
- @d
-
-
- ; Convert the number in D4 to its decimal ASCII representation.
-
- @40dIs the number zero?
- @40dIf so, just output "0" and return.
- @40dIs it negative?
- @40dIf not, make it negative.
- @d
- @a?fc204c
- FC204C move.b #'-',(A5)+ If so, output a "-".
- @a=fc2050
-
- ; The minus sign is taken care of, and negative the number to
- ; be output is in D4.
-
- @40dPoint at table of divisors.
- @40dClear the "non-zero digit" flag.
-
- @40dGet a divisor from the table.
- @40dIf zero, output last digit and exit.
-
- ; Subtract the current divisor from the number as many times as
- ; possible (actually, add to its negative).
-
- @40dStart the counter at -1.
- @40dTry to add the divisor to D4.
- @40dLoop until D4 is greater than zero.
- @40dMake the number less than zero again.
- @40dIncrement the counter by 1.
-
- ; D0 now contains negative the current digit to output. Discard
- ; it if it is a leading zero.
-
- @40dIf the current digit is zero then
- @40dif no non zero digits have been
- @40doutput, then discard it.
-
- ; Output the digit.
-
- @40dSet "non-zero digit" flag.
- @40dMake D0 positive.
- @a?fc2072
- FC2076 add.b #'0',D0 Convert to an ASCII digit.
- @a=fc2076
- @40dPut it into the buffer.
- @40dGo do the next digit.
-
- ; Enter here to output the last digit, or the single "0" if the
- ; number is zero.
-
- @40dMake D0 positive.
- @a?fc207c
- FC207C add.b #'0',D4 Convert to an ASCII digit.
- @a=fc2080
- @40dPut it into the buffer.
- @d
-
-
- ; Table of divisors.
-
- @8p@32l1000000000 decimal.
- @8p@33l100000000 decimal.
- @8p@34l10000000 decimal.
- @8p@35l1000000 decimal.
- @8p@36l100000 decimal.
- @8p@37l10000 decimal.
- @8p@38l1000 decimal.
- @8p@39l100 decimal.
- @8p@40l10 decimal.
- @8p@41l0 decimal.
-
-
- ; Convert the number in D4 to its hexadecimal ASCII representation.
-
- @a?fc20ac
- @40dIs the number zero?
- @40dIf so, just output "0" and exit.
- @40dClear "non-zero digit" flag.
- @40dIs the data 32 bits long?
- @d
- @40dIf not, output 4 digits,
- @40dfrom the high word of D4.
- @d
- @40dIf so, output 8 digits.
-
- ; Digit output loop.
-
- @40dRotate leftmost digit into bits 0-3.
- @d
- @40dMask out all but bits 0-3.
-
- ; Skip leading zeros.
-
- @40dIf no non-zero digit has been
- @40dencountered yet, and this is a zero,
- @40dskip it.
-
- @40dSet "non-zero digit" flag.
- @40dIs the digit greater than 9?
- @d
- @a?fc20d6
- FC20D6 add.b #'0',D0 If not, convert to ASCII numeral.
- @a=fc20DA
- @d
- FC20DC add.b #$37,D0 If so, convert to upper case letter.
- @a=fc20e0
- @40dPut digit in buffer.
- @40dLoop until all digits done.
- @d
-
-
- ---------------------------------------------------------------------------
- RawDoFmt( FormatString, DataStream, PutChProc, PutChData )
- A0 A1 A2 A3
- ---------------------------------------------------------------------------
-
- @d
- @40dReserve stack space for buffer.
- @40dStore data stream pointer.
- @40dPoint to the format string.
- @40dGet a byte from the format string.
- @40dCheck for end and exit if found.
- @a?fc20f8
- FC20F8 cmp.b #'%',D0 Check for format specifier.
- @a=fc20fc
- @40dProcess it if found.
- @40dOtherwise, output the character,
- @40dand go on to the next one.
- @40dOutput the terminating zero.
- @40dDeallocate the output buffer.
- @d
- @d
-
- ; Enter here if the "%" format specifier was found. Next we check
- ; for the characters "-", signaling that the printed item should
- ; be left-aligned in its field, and "0", signaling that leading
- ; zeros should be attached.
-
- @40dPoint to the output buffer.
- @40dClear the option flags.
- @a?fc2112
- FC2112 cmp.b #'-',(A4) Left alignment desired?
- @a=fc2116
- @d
- @40dIf so, set the corresponding flag,
- @40dand go on to the next character.
- FC211E cmp.b #'0',(A4) Zero fill desired?
- @a=fc2122
- @d
- @40dIf so, set the corresponding flag.
- @40dGet the field width.
- @40dStore it in D6.
- @40dAssume no maximum length.
- @a?fc2130
- FC2130 cmp.b #'.',(A4) Maximum length specifier?
- @a=fc2134
- @d
- @40dIf so, go on to the next character,
- @40dand get the maximum length.
- @40dStore maximum length.
- FC213E cmp.b #'l',(A4) 32 bit data?
- @a=fc2142
- @d
- @40dIf so, set the corresponding flag,
- @40dand go on to the next character.
-
- ; At this point, we have interpreted a format string of the format
- ; "%-0xxx.yyyl". In D3, bit 0 is set if the "-" was present, bit 1
- ; is set if the "0" was present, and bit 2 is set if the "l"
- ; was present. D6 contains the value of "xxx" (numeric constant),
- ; and D5 contains the value of "yyy" if present, or 0 if not.
-
- ; Now we process the actual format characters: "s" for string, "c"
- ; for character, "d" for decimal, "x" for hex. In all cases, the
- ; goal is to build a null-terminated string, pointed to by A0,
- ; containing the formatted output.
-
- @40dGet the next character.
- @a?fc214c
- FC214C cmp.b #'d',D0 Decimal output?
- @a=fc2150
- @40dSkip to next option if not.
- @40dGet data item.
- @40dFormat as decimal number.
- @40dOutput the buffer.
- FC215A cmp.b #'x',D0 Hexadecimal output?
- @a=fc215e
- @40dSkip to next option if not.
- @40dGet data item.
- @40dFormat as hexadecimal number.
- @40dOutput the buffer.
-
- ; Subroutine to get a number from the data stream. We get either
- ; a word or a longword, depending on whether an "l" was in the
- ; format specification.
-
- @40dIf data size is 16 bits then
- @d
- @40d Get data stream pointer.
- @40d Get a word from the data stream.
- @40d Put data stream pointer back.
- @40d Extend to longword.
- @40dElse
- @40d Get data stream pointer.
- @40d Get a longword from data stream.
- @40d Put data stream pointer back.
- @40dEndif
-
- ; Continue here if not formatting a number.
-
- @a?fc2188
- FC2188 cmp.b #'s',D0 String output?
- @a=fc218c
- @40dIf not, skip to next.
- @40dGet data stream pointer.
- @40dPoint directly at the string.
- @40dPut data stream pointer back.
- @40dOutput the string.
- FC2196 cmp.b #'c',D0 Single character output?
- @a=fc219a
- @40dIf not, discard format specifier.
- @40dGet character from input stream.
- @40dPut it into the buffer.
-
- ; Numeric and character output, having put their formatted argument
- ; into the buffer, meet here.
-
- @40dZero-terminate the buffer.
- @40dPoint back to its start.
-
- ; All output options continue here. A5 now points to a
- ; null-terminated string to output.
-
- @d
- @40dFind the length of the string.
- @40dWas a maximum length specified?
- @d
- @40dIf so, and if the output string is
- @40dlonger, set the length to the
- @40dmaximum length.
- @40dCompute amount of padding needed.
- @d
- @40dSet to zero if negative.
- @40dWas left alignment desired?
- @d
- @40dIf not, output padding first.
- @d
- @40dLoop to copy the string to the output
- @40duntil its end or the given maximum
- @40dnumber of characters.
- @40dWas left alignment desired?
- @d
- @40dIf so, output padding now.
- @40dContinue with format string.
-
-
- ; Subroutine to output the right amount of padding.
-
- @a?fc21de
- FC21DE move.b #' ',D2 Assume padding with spaces.
- @a=fc21e2
- @40dWas zero-fill desired?
- @d
- FC21E8 move.b #'0',D2 If so, pad with zeros.
- @a=fc21ec
- @d
- @40dLoop to output the required number
- @40dof padding characters.
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- RawIOInit()
- ---------------------------------------------------------------------------
-
- ; Set the serial port for receiving 8 bit data at 9600 bps.
-
- @40dSet up the SERPER register.
- @d
-
-
- ---------------------------------------------------------------------------
- RawMayGetChar()
- ---------------------------------------------------------------------------
-
- @d
- @40dRead SERDATR.
- @40dIs a byte in the receive buffer?
- @40dIf not, return -1 and exit.
- @40dClear the serial receive interrupt.
- @40dGet the received character.
- @40dReturn it to the caller.
- @d
-
-
- ; Subroutine to wait for a character on the serial port.
-
- @40dRawMayGetChar()
- @40dDid we get a character?
- @40dContinue waiting if not.
- @40dReturn the character.
-
-
- ; This looks like a C entry point for RawPutChar.
-
- @40dGet the first C parameter.
-
- ---------------------------------------------------------------------------
- RawPutChar()
- ---------------------------------------------------------------------------
-
- ; Don't output code 0, and expand newlines to CRLF.
-
- @40dIs the character to send zero?
- @40dIf so, don't send it.
- @40dSave the character.
- @40dIs it a newline?
- @d
- @40dIf so, send a carriage return first.
- @d
- @40dGet the character back.
-
- ; Enter here to send the character in D0 on the serial port.
-
- @40dRead SERDATR.
- @40dTransmitter ready?
- @40dWait until true.
-
- @40dMask out all but bits 0-7.
- @40dSet the stop bit.
- @40dWrite to SERDAT.
-
- ; Handle XON/XOFF and/or escape into the debugger if DEL pressed.
-
- @40dRawMayGetChar()
- @40dDid we get an XOFF?
- @d
- @40dIf yes, wait for any other character.
- @d
- @40dDid we get a DEL?
- @40dReturn if not.
- @40dIf so, Debug()
- @40dOn return, check for XOFF again.
- @d
-
-
- ; C compatible routine to print a string.
-
- @40dGet first C parameter (string addr.)
-
- ; Assembly language entry point (address in A0).
-
- @40dGet a string character.
- @40dExit if is the terminating zero.
- @40dIs it a newline?
- @d
- @40dIf so, output a CR first.
- @d
- @d
- @40dOutput the character.
- @40dGo on to next character.
- @d
-
-
- ; C compatible function to output a hex number. First argument
- ; is the number, second one is the number of digits. The number
- ; will be output with one space following.
-
- @40dGet C parameters.
-
- ; Assembly language entry point.
-
- @d
- @d
- @d
- @40dCompute 8 - number of digits.
- @40dLoop that many times, rotating the
- @40dnumber left by a digit each time,
- @40dto left-align the number in D2.
-
- @40dGet number of digits.
- @d
- @40dShift current digit into bits 0-3.
- @d
- @40dExtract bits 0-3 from the number.
- @40dNumeric or alphabetic digit?
- @d
- @40dIf alphabetic, add ('A'-'9').
- @a?fc22ba
- FC22BA add.b #'0',D0 Convert to ASCII digit.
- @a=fc22be
- @40dOutput the digit.
- @40dLoop until all digits done.
- @d
- @40dOutput a space.
- @d
- @d
-
-
- ; Entry point to do a RawDoFmt() to the serial port.
-
- @40dSave A2.
- @40dPoint A2 to RawPutChar() function.
- @40dRawDoFmt()
- @40dRestore A2.
- @d
-
-
- ---------------------------------------------------------------------------
- Open()
- ---------------------------------------------------------------------------
-
- ; This gets executed if someone actually opens "exec.library".
-
- @40dReturn ExecBase.
- @40dIncrement exec.library open count.
- @d
-
-
- ---------------------------------------------------------------------------
- Close()
- ---------------------------------------------------------------------------
-
- ; This gets executed if someone tries to close "exec.library".
-
- @40dDecrement exec.library open count.
-
-
- ---------------------------------------------------------------------------
- Expunge()
- ---------------------------------------------------------------------------
-
- ; This gets executed if someone tries to Expunge() the exec.
- ; Needless to say, we won't do anything of the sort, but we'll make
- ; the caller happy by returning zero.
-
- ; The reserved jump vector (at ExecBase - 24) also points here.
-
- @d
- @d
-
-
- @a?fc22f0
- ; ROM-Wack
- ; --------
-
- ; This is the Amiga's ROM resident mini-debugger. The following
- ; string is sent out the serial port when it starts up.
-
- @8p@,10s
-
- ; ROM-Wack has a private, 236 byte data area at $000200. The
- ; following is a memory map of this area. Addresses are given as
- ; hex offsets from $000200.
-
- ;-------------------------------------------------------------------
- ; 00 (32 bit) Pointer to current key bindings.
- ; 04 (32 bit) Saved key binding pointer if not using main ones.
- ; 08 (32 bit) Value of last number entered by the user.
- ; 0C (32 bit) The "current address" for all operations.
- ; 10 - 13 (not used).
- ; 14 (32 bit) The current "frame size".
- ; 18 (32 bit) The upper limit address for searches and fills.
- ; 1C (16 bit) Number of characters in the input buffer.
- ; 1E (8 bit) Flag indicating whether the "frame" should be
- ; redisplayed after a command has executed.
- ; 1F (8 bit) Flag indicating whether we are in "alter" mode.
- ; 20 (16 bit) Flag indicating whether there is unprocessed data
- ; in the buffer (0 if yes, 1 if no).
- ; 22 (16 bit) Number of digits in the number most recently entered.
- ; 24 (16 bit) Flag indicating whether a number is being gathered as
- ; a parameter to a command, or being entered unprompted
- ; (in which case it becomes the current address).
- ; 26 (32 bit) Indirection stack pointer (for following pointers).
- ; 2A - 4F (not used).
- ; 50 - 81 Input buffer for user commands.
- ; 82 (16 bit) Last character typed by the user.
- ; 84 (32 bit) Pointer to data area on the stack, holding CPU and
- ; process related information (map farther down)
- ; 88 (16 bit) Instruction to use for breakpoints (TRAP #15).
- ; 8A - E9 Breakpoint table. Each entry consists of an address
- ; where an instruction was replaced with TRAP #15, and
- ; the word which had been there before.
- ; EA (16 bit) Value to be written to INTENA to restore serial
- ; port interrupts to their original state.
- ;-------------------------------------------------------------------
-
-
- ; This gets called from the exec initialization code.
-
- @40dSave ExecBase.
- @40dPoint to ROM-Wack's data area.
- @40dInitialize it.
- @40dRestore ExecBase.
- @40dInstall default ExecBase->DebugEntry.
- @40dInstall default Debug() vector.
- @40dRawIOInit()
- @d
-
-
- ; Special exception handlers for ROM-Wack
- ; ---------------------------------------
-
- ; ROM-Wack trace exception handler.
-
- @40dPush "Trace" exception number.
- @40dEnter the debugger.
-
- ; ROM-Wack breakpoint exception handler. A "TRAP #15" instruction
- ; is used for the breakpoint.
-
- @40dPush "TRAP #15" exception number.
- @40dEnter the debugger.
-
- ---------------------------------------------------------------------------
- Debug()
- ---------------------------------------------------------------------------
-
- ; This entry point is used when an actual function call to Debug()
- ; is made. We set up the supervisor stack to look like it would
- ; after an exception handled by the exec exception entry points.
-
- @40dSave A5.
- @40dWhere to go in supervisor mode.
- @40dSupervisor()
-
- ; We now have an exception stack frame from the Supervisor() call.
-
- @40dPop the return address from the
- @40dDebug() call from the user stack.
- @d
- @40dGet the return address back.
- @40dFake exception number zero.
-
- ; Now the supervisor and user stacks look as if an exception had
- ; occurred and was handled by the exec, with the difference that
- ; the original value of A5 is on the supervisor stack, and A5 now
- ; contains the return address from the Debug() call.
-
-
- ; Exception entry point.
- ; ----------------------
-
- ; The debugger is entered here with the stacks already set up as
- ; above (by the system exception handler). First, we verify if
- ; the stack is even working (pointing at RAM).
-
- @40dPut a signature on the stack.
- @40dCheck if it can be read back.
- @d
-
- ; A signature pushed on the supervisor stack could not be read
- ; back, so we are in serious trouble. Initialize the stack at
- ; the top of the first 256K of chip memory. Put a fake exception
- ; stack frame on the new stack.
-
- @40dStart stack at 256K.
- @40dFake program counter.
- @40dFake status register.
- @40dPush exception number -1.
- @d
-
- ; We now have a working supervisor stack with the exception
- ; number and stack frame on it.
-
- @40dSave most of the CPU registers.
- @40dPoint A5 at the exception number.
- @40dReserve 22 bytes of stack space,
- @40dand point A4 to the bottom of this.
- @d
- @40dGet the exception number.
- @40dStore it.
- @40dStore supervisor stack pointer.
- @d
- @40dStore user stack pointer.
-
- ; When a 680x0 hits an exception, it pushes the program counter, then
- ; the status register, onto the supervisor stack. For bus and
- ; address errors, however, more information is saved. On 68010 and
- ; 68020 processors, this comes before the program counter and status
- ; register, i.e. the stack pointer after an exception always points
- ; at these. On the 68000, however, 8 bytes of other information
- ; are pushed on the stack AFTER the PC and SP. The following code
- ; compensates for this.
-
- @40dCheck CPU/FPP configuration.
- @40dIs it a plain vanilla 68000?
- @d
- @40dWas it an address error?
- @d
- @40dWas it a bus error?
- @d
- @40dIf either, skip past bus error info.
-
- ; For all CPUs, A5 now points to where the status register and
- ; program counter are stored on the supervisor stack.
-
- @40dCheck the supervisor mode bit.
- @40dIf it was set,
- @40dget ExecBase,
- @40dand get the current task pointer.
- @40dGet and store the status register.
- @40dGet and store the program counter.
-
- ; Time for a summary (so I don't get confused). A4 currently
- ; points at a data structure, on the supervisor stack, containing
- ; the following:
-
- ; (60 bytes) Register dump (D0-D7, A0-A6).
-
- ; (32 bit) Current task pointer or zero.
- ; (32 bit) Number of the exception that got us here (see below).
- ; (32 bit) Saved supervisor stack pointer.
- ; (32 bit) Saved user stack pointer.
- ; (16 bit) Saved status register (from exception stack frame).
- ; (32 bit) Saved program counter (from exception stack frame).
-
- ; If the exception number is zero, Debug() was used to get here.
-
- ; If the exception number is -1, we somehow got here, but the
- ; supervisor stack pointer was clobbered and not pointing to RAM.
- ; In this case, we have just set it to 256K, and the saved
- ; program counter and status register are invalid.
-
- @40dPoint to ROM-Wack's data area.
-
- ; Disable serial port interrupts, and make a control word which,
- ; when written to INTENA, will return them to their original status.
-
- @40dStore interrupt enable status.
- @40dDisable serial port interrupts.
- @d
- @40dMake the control word to be used
- @40dto restore those two interrupts.
-
- @40dRawIOInit()
- @d
- @40dPrint a newline and "rom-wack".
-
- @40dSave pointer to stack-resident data.
- @40dMake the saved exception program
- @40dcounter even (if not already so),
- @40dand put it back.
- @40dSet the "current address" there.
- @40dDid a TRAP #15 get us here?
- @40dSkip the following if not.
-
- ; Special handling for breakpoints. Back the PC up by 2 (over
- ; the TRAP #15 instruction used for the breakpoint), and clear
- ; the breakpoint (restore the original instruction).
-
- @40dBack up to breakpoint address.
- @40d"clear" the breakpoint.
-
- @40dUpdate the saved program counter.
- @40dPoint to the stack-resident data.
-
- ; Install the exception vectors needed for breakpoints and
- ; single-stepping.
-
- @40dInstall TRAP #15 exception vector.
- @40dInstall "Trace" exception vector.
- @40dSet the search limit to 16 megabytes.
- @40dDisplay the ROM-Wack register frame.
- @40dEnter the ROM-Wack main loop.
-
-
- ; Entry point for <Tab> command.
-
- ; Entry point to run a single instruction in trace mode. This does
- ; everything required to resume running as below, but with the trace
- ; mode bit set in the saved status register, so only a single
- ; instruction will be executed after the RTE (and then we come back
- ; in at the top).
-
- @40dPoint to data on system stack.
- @40dGet the saved status register, set
- @40dthe trace mode bit, and store it.
- @d
-
- ; Set up to continue running after exit from ROM-Wack. Note that
- ; to compensate for the different exception stack frame formats of
- ; bus error and regular exceptions, we don't even try to compensate
- ; for the format of the exception stack frame, just build one
- ; containing a simple status register and program counter right
- ; above the register dump. This allows the RTE instruction to
- ; conveniently resume running whatever called ROM-Wack, but
- ; some garbage may be left on the stack.
-
- ; Entry point for "go" command.
-
- ; This starts running wherever the current address is pointing.
-
- @40dPoint to data on system stack.
- @40dMake PC the current address.
-
- ; Entry point for "^D" and "resume" commands.
-
- ; This continues running where it left off.
-
- @d
- @40dGet the saved status register.
- @40dClear the trace mode flag and put
- it on the stack.
- @40dRestore serial port interrupt status.
- @40dPut the program counter on the stack.
- @40dGet the saved user stack pointer,
- @40dand restore it.
- @40dPoint to the register dump.
- @40dRestore all the other registers.
- @40dPop the exception number.
- @40dReturn from the exception.
-
-
- ; Subroutine to initialize ROM-Wack's data area.
-
- @40dPoint to data area.
- @d
- @40dClear 236 bytes.
- @d
- @40dUse primary key bindings.
- @40dFrame size = 16 bytes.
- @40dUse "TRAP #15" for breakpoints.
- @d
-
- @8p@32wPadding.
-
- ; A lot of the functions in ROM-Wack have C compatible entry points
- ; (which get the parameters from the stack), and most of them have
- ; C compatible return values (in D0). I guess this is to interface
- ; them to other functions, written in C, in the bigger versions of
- ; Wack. Likewise, the following are probably C interface functions,
- ; but they (and most of the C entry points) aren't used anywhere.
-
-
- ; "Peek" function for C. Takes address, returns 16-bit contents.
-
- @a?fc2498
- @d
- @d
- @d
-
- ; I have no idea why this is here twice.
-
- @d
- @d
- @d
-
- ; "Poke" function for C. Takes address and a word, and stores the
- ; word at the address given.
-
- @d
- @d
- @d
-
-
- ; Entry point for "user" command.
-
- ; Takes all the data currently resident on the supervisor
- ; stack (exception stack frame, exception number, register dump,
- ; ROM-Wack data area, and any other stuff), and moves it onto the
- ; user stack. Then puts the CPU into user mode.
-
- ; In effect, this switches ROM-Wack from running as part of the
- ; exec kernel (in supervisor mode) to running as a plain, ordinary
- ; task, along with other tasks. The good side is that the system
- ; can now go and clean up (flush disk buffers, etc), while the
- ; user can go on playing with ROM-Wack. The bad side is that the
- ; task which did Debug() or trapped into ROM-Wack is stuck there
- ; forever. "go", and "resume" commands will no longer work.
-
- @40dPoint to data area on stack.
- @40dWas CPU in supervisor mode?
- @40dIf not, exit.
- @40dGet the user stack pointer.
- @40dReserve 92 bytes on user stack.
- @40dMake this the new data area.
- @40dPoint to top of new data area.
- @40dPoint to top of old data area.
- @40dSave the supervisor stack pointer.
- @d
- @d
- @40dCopy exception stack frame, register
- @40ddump, data area, and any other stuff
- @40dto the user stack.
- @40dBump supervisor stack pointer up.
- @40dBump user stack pointer down.
- @d
- @40dGet the saved status register.
- @40dPrint a newline.
- @d
-
-
- ; String compare function. This checks if a command entered by
- ; the user, pointed to by A1, matches a command, pointed to by A0,
- ; from the command table. It returns zero if so, else it returns
- ; the character number at which the mismatch occurred.
-
- ; C style entry point.
-
- @d
-
- ; Assembler entry point.
-
- @d
- @40dGet a byte from reference string.
- @40dEnd of string?
- @40dCompare to byte from second string.
- @40dLoop while strings are equal.
- @40dCompute number of equal characters.
- @40dExit.
-
- @40dCheck if other string ends also.
- @d
- @40dReturn zero (strings match).
- @d
-
-
- ; Entry point for <Return> command (Redisplay frame).
-
- @40dRequest redisplay of current frame.
- @d
-
-
- ; I don't know what this is for. It's not referenced anywhere.
-
- @d
- @d
- @d
- @d
-
-
- ; Entry point for ">", <Space> commands (Move forward a word).
-
- @40dIncrement current address by 1 word.
- @40dRequest frame display.
- @d
- @d
- @40dPrint a newline.
- @d
- @d
- @d
-
-
- ; Entry point for "<", <Backspace> commands (Move back a word).
-
- @40dDecrement current address by 1 word.
- @40dRequest frame display.
- @d
- @d
- @40dPrint a newline.
- @d
- @d
- @d
-
-
- ; Entry point for "." command (move forward a frame).
-
- @40dGet frame size.
- @40dAdd to current address.
- @40dRequest frame display.
- @d
-
-
- ; Entry point for "," command (move back a frame).
-
- @40dGet frame size.
- @40dSubtract from current address.
- @40dRequest frame display.
- @d
-
-
- ; Entry point for "[" command.
-
- ; This follows a pointer at the current address.
-
- @40dGet indirection stack pointer.
- @40dGet current location.
- @40dStore in indirection stack.
- @40dPut indirection stack pointer back.
- @40dMake the current location even.
- @40dGet the pointer.
- @40dPut it in the current location.
- @40dRequest display of frame.
- @d
-
-
- ; Entry point for "]" command.
-
- ; This walks undoes a "[" command, good for walking back along
- ; singly linked lists or backing out of nested structure pointers.
-
- @40dGet indirection stack pointer.
- @40dGet address from indirection stack.
- @40dRequest frame display.
- @40dUpdate the indirection stack pointer.
- @d
-
-
- ; Entry point for "+" command.
-
- @40dEcho "+" on the user's terminal.
- @d
- @40dRead a number from the keyboard.
- @d
- @40dIf none, print newline and exit.
- @40dGet the number which was entered.
- @40dAdd to current address.
- @40dRequest frame redisplay.
- @d
-
-
- ; Entry point for "-" command.
-
- @40dEcho "-" on the user's terminal.
- @d
- @40dRead a number from the keyboard.
- @d
- @40dIf none, print newline and exit.
- @40dGet the number which was entered.
- @40dSubtract from the current address.
- @40dRequest frame redisplay.
- @d
-
-
- ; The following isn't referenced anywhere. Perhaps an outdated
- ; bit of code to set the current address to the last number entered.
- ; This is now unnecessary.
-
- @d
- @d
- @d
-
-
- ; Entry point for ":" command (set frame size).
-
- @40dEcho ":" on the terminal.
- @d
- @40dGet a number from the terminal.
- @40dSet the frame size.
- @40dRequest frame redisplay.
- @d
-
-
- ; Routine to print a prompt for memory-modify commands.
-
- @40dGet the current address.
- @40dPrint it (6 digits).
- @40dIs the frame size zero?
- @40dIf frame size is not zero, then
- @d
- @40d Get word at current address.
- @40d Print it (4 digits).
- @40d Print "=".
- @d
- @40dElse
- @40d Print "xxxx ="
- @40dEndif
- @d
-
-
- ; Entry point for "=" command (modify one word of memory).
-
- ; This is also used by the "alter" routine below. It returns 1
- ; if a value was entered, and 0 if not.
-
- @40dPrint a prompt.
- @40dGet a number from the terminal.
- @40dDid we get one?
- @d
- @40dIf so, update the word pointed
- @40dto by the current address with the
- @40ddata which was entered, and return
- @40da non-zero value.
- @40dAre we in "alter" mode?
- @d
- @40dIf not, request frame redisplay.
- @d
-
- @8p@,8s
-
-
- ; Entry point for "alter" command.
-
- @40dSet "alter mode" flag.
- @40dPrint a newline.
- @40dDo an "=" command.
- @d
- @40dIf a value was entered, increase the
- @40dcurrent location by 2, and loop back.
- @d
-
- @40dClear "alter mode" flag.
- @40dPrint a newline.
- @d
-
-
- ; I don't know what this is for. Perhaps a remnant from an old
- ; version of ROM-Wack, or something from a bigger version of Wack.
- ; It's not called from anywhere.
-
- @a?fc2692
- @40dPoint to the string below.
- @40dPrint it.
- @d
-
- @8p@,22s
-
-
- ; Entry point for "list" command.
-
- ; This will traverse a standard exec list, displaying information
- ; about each node. It should be called when the current address is
- ; either that of the list header, or of any node.
-
- @d
- @40dGet the current address.
- @40dList header ("Tail" field zero)?
- @d
- @40dIf yes, go to first node.
- @40dSee if now at end of list (or empty).
- @40dIf no more nodes, exit.
- @40dGet the node's name.
- @40dIf name pointer is null, replace
- @40dit with a pointer to a zero.
- @40dSave name pointer on stack.
- @d
- @40dGet priority field.
- @40dPut it on the stack.
- @40dGet type field.
- @40dPut it on the stack.
- @40dPut node address to stack.
- @40dPoint to data on stack.
- @40dPoint to format string below.
- @40dRawDoFmt() to serial port.
- @40dPop data back off the stack.
- @40dMove to next node.
- @40dLoop until no more nodes.
- @40dPrint a newline.
- @d
- @d
-
- @a?fc26fc
- @8p@,36s
-
-
- ; Subroutine to display a "frame" of data from memory. On entry,
- ; the address of the frame is given in D0, and its size in D1.
-
- ; Data is displayed in lines of up to 8 words, and as an address,
- ; followed by hex words, followed by their ASCII character
- ; equivalents.
-
- @d
- @40dReserve 40 bytes of stack space.
- @40dPrint a newline.
- @d
- @40dSet number of bytes remaining.
- @40dJust exit if frame size is zero.
-
- ; Outer loop: Display one line of the frame.
-
- @a?fc2732
- @d
- @40dPrint the address.
- @40dMaximum 8 words per line.
- @40dPoint to reserved stack space.
-
- ; Inner loop: Display one word of data.
-
- @40dGet a word from memory.
- @40dPrint it.
- @d
- @40dGet high 8 bits of current word.
- @40dConvert to printable data.
- @40dAdd to character string.
- @d
- @40dDo likewise for low 8 bits.
- @d
- @40dDecrement number of bytes remaining.
- @40dExit if zero,
- @40dotherwise continue until line full.
-
- ; End of line reached.
-
- @40dMark end of character string.
- @40dPoint to beginning.
- @40dPrint the string and a newline.
- @40dGo and do next line.
-
- ; End of frame reached.
-
- @40dMark end of character string.
- @40dPoint to beginning.
- @40dPrint the string and a newline.
- @d
- @d
- @d
-
-
- ; Subroutine to display an 8-digit hex number.
-
- @d
- @40d8 digits.
- @d
-
-
- ; Subroutine to display a 6-digit hex number (address).
-
- @d
- @40d6 digits.
- @d
-
-
- ; Subroutine to display a 4-digit hex number.
-
- @d
- @40d4 digits.
- @40dGo print the number.
- @d
- @d
-
-
- ; Subroutine to print the "DR:", "AR:", and "SF:" portions of
- ; the ROM-Wack register frame.
-
- @d
- @d
- @40d7 Data registers.
- @40dPoint to "\nDR: " string.
- @40dDisplay data registers.
- @40d6 Address registers.
- @40dPoint to "\nAR: " string.
- @40dDisplay address registers.
- @40dSkip exception number on stack.
- @40dSupervisor mode?
- @d
- @40dIf not, get saved USP.
- @d
- @40dPoint to "\nSF: " string.
- @40dPrint it.
- @d
- @40dDisplay 14 words of stack data.
- @d
- @d
- @40dPrint a newline.
- @d
- @d
-
-
- ; Subroutine to print a string pointed to by A0, followed by (D2)
- ; longwords from memory pointed to by A2.
-
- @40dPrint the string.
- @d
- @40dLoop and print all the data.
- @d
- @d
-
-
- ; Subroutine to print the first ("PC: ...") line of the register
- ; frame, followed by the rest of the register frame via the routine
- ; above. Note, we just give RawDoFmt() a format string describing
- ; the data structure on the supervisor stack
-
- ; Also entry point for "regs" command.
-
- @40dGet pointer to stack-resident data.
- @d
- @40dPoint to format string.
- @40dFormat the data.
- @d
- @40dPoint to the register dump area.
- @40dPrint it.
-
-
- ; Text strings used to display register frames. The second one
- ; isn't used anywhere.
-
- @a?fc27fc
- @8p@,52s
- @8p@,19s
-
- @8p@,33s
-
- @8p@,6s
- @8p@,6s
- @8p@,6s
-
-
- ; Memory fill routine. Fills (D1) words, starting at (D0), with
- ; the value in D2. Not used anywhere.
-
- @d
- @d
- @d
- @d
- @d
- @d
- @d
-
-
- ; Subroutine to find a breakpoint in the breakpoint table, given
- ; its address. If successful, returns address of breakpoint table
- ; entry, if not, returns zero.
-
- @a?fc2886
- @40dPrint a newline.
- @40dPoint to breakpoint table.
- @d
- @40dScan breakpoint table for a
- @40dbreakpoint address matching A1.
- @d
- @d
- @40dNot found, so return zero.
- @d
- @40dReturn address of table entry.
- @d
-
- ; Entry point for "clear" command.
-
- ; Deactivate the breakpoint at the current program address,
- ; if there is one.
-
- @40dGet current address.
- @40dSee if it is a breakpoint address.
- @d
- @40dIf so, deactivate it and write the
- @40doriginal instruction back.
- @d
-
-
- ; Entry point for "reset" command.
-
- ; Deactivates all breakpoints.
-
- @40dPoint to ROM-Wack's breakpoint table.
- @40dSize of breakpoint table - 1.
- @40dGet breakpoint address.
- @40dIf breakpoint in use then
- @d
- @40d Clear breakpoint address.
- @40d Fix instruction at breakpoint.
- Endif
- @40dGo to next table entry.
- @40dLoop until whole table done.
- @40dPrint a newline.
- @d
-
-
- ; Entry point for "set" command.
-
- ; Activates a breakpoint at the current address.
-
- @40dGet current address.
- @40dSee if it is a breakpoint.
- @40dIf so, do nothing.
- @d
- @40dScan the breakpoint table for an
- @40dunused entry.
- @d
- @d
- @d
-
- ; No unused breakpoint table entry found.
-
- @40dPoint at "too many" string.
- @40dPrint it.
- @40dReturn.
-
- ; Unused entry in the breakpoint table found. Activate a breakpoint.
-
- @40dSave instruction at breakpoint.
- @40dReplace with TRAP #15.
- @40dSave the breakpoint address.
- @d
-
- @8p@,12s
-
-
- ; Entry point for "show" command.
-
- ; Lists all active breakpoints.
-
- @40dPoint to breakpoint table.
- @40dLoop for 16 entries.
- @40dGet current breakpoint address.
- @40dSkip if zero.
- @40dPrint a newline.
- @40dPrint the breakpoint address.
- @40dGo to next table entry.
- @40dLoop until done.
- @40dPrint a newline.
- @d
-
- @40dGarbage.
-
-
- ; Subroutine to get a character and echo it to the user.
-
- @40dGet a character.
- @d
- @40dEcho it back.
- @d
- @d
-
- ; Entry point for "!" command (Modify a register).
-
- @d
- @40dPrint "!".
- @d
- @40dGet a character.
- @40dConvert to upper case.
- @40dGet pointer to stack-resident data.
- @40dPoint to data register dump area.
- @40dMaximum data register # = 7.
- @a?fc2952
- FC2952 cmp.b #'D',D0 [D]ata register?
- @a=fc2956
- @d
- @40dPoint to address register dump.
- @40dMaximum address register # = 6.
- FC295E cmp.b #'A',D0 [A]ddress register?
- @a=fc2962
- @d
- @40dPoint to user stack pointer.
- FC2968 cmp.b #'U',D0 [U]SP?
- @a=fc296c
- @40dIf so, go change it.
- @40dOtherwise, exit.
-
- ; Enter here with A0 pointing to a dump area containing sequential
- ; images of the address or data registers, and D2 containing the
- ; maximum register number.
-
- @40dGet a character.
- @40dBackspace?
- @40dIf so, exit.
- @40dIs it a digit?
- @40dIf not, exit.
- @40dConvert to number.
- @40dGreater than maximum?
- @40dIf so, exit.
- @40dCompute offset to given register.
- @40dCompute address of register.
-
- ; Enter here with A2 pointing to a longword containing the image
- ; of the register to modify.
-
- @40dGet the current value.
- @40dPrint a space.
- @40dDisplay value as 8 hex digits.
- @40dPrint "="
- @d
- @40dGet the new value from the user.
- @40dWas a value entered?
- @40dIf not, exit.
- @40dUpdate the register.
- @40dPrint a newline.
- @d
- @d
-
-
- ; Entry point for "^" and "limit" commands.
-
- ; This copies the current address to the "limit" address, i.e. the
- ; address to stop searching or filling memory at.
-
- @40dCopy current address to limit.
- @40dRequest frame redisplay.
- @d
-
-
- ; Entry point for "find" command.
-
- @d
- @40dGet the search pattern.
- @40dExit if none entered.
- @40dDo the searching.
- @40dExit if not found.
- @40dRound result address down to even.
- @40dStore it in current address.
- @40dRequest frame redisplay.
- @d
- @d
-
- ; Search routine for the "find" command.
-
- @d
- @40dStart searching at start address - 2.
-
- @40dSet the number of bytes to match.
- @40dSet the search pattern address.
- @40dGo to next address.
- @d
- @40dSee if limit address reached.
- @40dIf so, return false.
- @40dCompare one byte.
- @40dGo to next address if mismatch.
- @40dDecrement byte counter.
- @40dLoop until all matched.
- @40dFound: return the address where.
- @d
- @40dReturn false.
- @d
- @d
-
- ; Search/fill pattern input routine. Prompts for a pattern,
- ; accepts it, and returns the following:
-
- ; D0: Number of bytes in search pattern.
- ; D1: True if pattern entered, false if aborted.
- ; A0: Lower bound for search.
- ; A2: Upper bound for search.
- ; A3: Address of search pattern.
-
- @40dPoint to "pattern? " string.
- @40dPrint it.
- @40dGet a number from the terminal.
- @40dDid we get one?
- @40dIf not, return false.
- @d
- @40dCompute 4-(d+1)/2, where d is the
- @40dnumber of digits entered.
- @d
- @40dGet the number entered.
- @40dGet the current address,
- @40dand the limit address.
- @40dReturn true.
- @d
-
- @a?fc2a2c
- @8p@,12s
-
-
- ; Entry point for "fill" command.
-
- @d
- @40dGet the fill pattern.
- @d
- @40dIf one entered, go do the fill.
- @40dRequest frame redisplay.
- @d
- @d
-
- ; Fill routine for the "fill" command.
-
- @40dAdjust number of bytes for "dbra".
- @40dInitialize loop counter.
- @40dInitialize pattern address.
- @40dUpper limit reached?
- @40dExit if so.
- @40dCopy one byte from the fill pattern.
- @40dLoop until pattern done.
- @40dLoop back and do pattern again.
- @d
-
-
- ; Subroutine to print a single space.
-
- @d
- @40dCharacter code for a space.
- @40dRawPutChar()
- @d
- @d
-
-
- ; Subroutine to print a single newline.
-
- @d
- @40dPoint to string below.
- @40dPrint it.
- @d
- @d
-
- @8p@,2s
-
-
- ; Subroutine to print string at address pointed to by A0, followed
- ; by a newline.
-
- @d
- @40dPrint the string.
- @40dPrint a newline.
- @d
- @d
-
-
- ; I don't know what this is for. It's not referenced anywhere.
-
- @d
- @d
-
-
- ; Subroutine to get a character. Returns with the zero flag clear
- ; if a character was received, set otherwise.
-
- @d
- @d
- @d
- @d
- @d
-
-
- ; Isdigit() type of function. Enter with a character in D0, returns
- ; with the zero flag set if the character is a numeric digit.
-
- @a?fc2aac
- FC2AAC cmp.b #'0',D0
- @a=fc2ab0
- @d
- FC2AB2 cmp.b #'9',D0
- @a=fc2ab6
- @d
- @d
- @d
-
-
- ; Subroutine to convert an 8-bit code in D0 to a 2 character
- ; printable ASCII version.
-
- ; Codes 0 and 128-255 return "..", control codes are shown as "^A"
- ; to "^\", other characters are shown as a space, then the actual
- ; character.
-
- @d
- @40dMove ".." into D2.
- @40dIs the code zero?
- @40dIf so, return ".." and exit.
- @40dIs the high bit set?
- @40dIf so, return ".." and exit.
- @40dMove space and null into D2.
- @d
- @40dIf the character is a control code,
- @d
- @40d Move "^" and null into D2.
- @a?fc2adc
- FC2ADC or.b #$40,D0 Convert to printable character.
- @a=fc2ae0
- @40d Put it into D2.
- Endif
- @40dReturn D2.
- @d
- @d
-
-
- ; ROM-Wack command execution function. Calls the command function
- ; given in A0, and on return, displays the current "frame" if
- ; requested by the command function.
-
- @d
- @40dGet the command function address.
- @40dExecute the function.
- @40dNeed to display frame?
- @40dExit if not.
- @40dGet current address.
- @40dGet frame size.
- @40dDisplay the frame.
- @d
-
-
- ; Entry point for "?" command (Display multi-character commands).
-
- @d
- @40dPoint to ROM-Wack command table.
- @40dGet a character.
- @d
- @40dIf not zero, print it, and loop
- @40dback to do the next one.
- @40dPrint a space.
- @40dAnother zero?
- @40dIf not, loop back & print next cmd.
- @40dPrint a newline.
- @d
- @d
-
-
- ; ROM-Wack command dispatch table scanner.
-
- ; Enter with a character code in D0. This routine runs through the
- ; command table, and returns either the address of the command table
- ; entry matching the character, or zero.
-
- ; Each command table entry either corresponds to exactly one
- ; character, or to a range of characters. This may sound confusing,
- ; but I've commented the command table itself, so you can just look
- ; there and it will be perfectly obvious.
-
- @d
- @40dPoint to command table.
- @d
- @40dGet link to next table entry.
- @40dStrip off high 8 bits.
- @40dExit if no next entry.
- @40dPoint ot next entry.
- @40dSee if command matches table entry.
- @40dExit if it does.
- @40dGo to next entry if smaller.
- @40dCheck if in range.
- @40dGo to next entry if not.
- @40dReturn table entry address.
- @d
-
-
- ; ROM-Wack command dispatcher. Given a command character, looks it
- ; up in the command dispatch table and executes the command if found.
-
- ; C style entry point.
-
- @d
-
- ; Assembler entry point.
-
- @40dLook command up in command table.
- @40dFound it?
- @40dExit if not.
- @d
- @40dGet execution address from table
- and store it on the stack.
- @40dExecute the function.
- @40dPop address back off the table.
- @d
-
-
- ; Multi-character command lookup function.
-
- ; This takes a pointer to a command string in A0, and looks it up
- ; in the table of multi-character commands. It returns the address
- ; of the table entry corresponding to the command, or zero if the
- ; command was not found.
-
- ; C style entry point.
-
- @d
-
- ; Assembler entry point.
-
- @d
- @d
- @40dPoint at command dispatch table.
- @d
- @40dGet pointer to next table entry.
- @40dExit if null (end of table).
- @d
- @40dGet pointer to string.
- @40dPoint to string to match.
- @40dCompare them.
- @40dGot a match?
- @40dKeep looking if not.
- @40dReturn table address.
- @d
- @d
-
-
- ; ROM-Wack main loop: Gets a character from the user, then
- ; interprets it, then gets next characer, etc.
-
- @40dGet a character from the user.
- @40dStore it.
- @40dProcess it.
- @40dGo get next character.
-
-
- ; Entry point for letters, numbers and underline characters typed
- ; at the ROM-Wack command level. This function collects them in
- ; a buffer.
-
- @40dAddress of secondary key bindings.
- @40dAlready using them?
- @d
-
- ; This is the first character of a multi character command, so
- ; clear the buffer and point to the other set of key bindings.
-
- @40dZero characters in buffer so far.
- @40dSave address of primary key bindings.
- @40dPoint at secondary key bindings.
-
- @a?fc2bbe
- FC2BBE cmp.b #' ',$82(A6) Was the key a space?
- @a=fc2bc4
- @40dIf so, ignore it (kludge, see below).
- @40dGet number of chars in buffer
- @40d50 characters already?
- @40dIf equal or more, ignore this one.
- @40dGet command character.
- @40dEcho it to the user.
- @40dPoint to buffer.
- @40dGet offset into buffer.
- @40dStore character in buffer.
- @40dIncrement buffer count.
- @40dThere is unprocessed data in the
- @40dbuffer, so set the flag.
-
-
- ; Entry point to get a number from the user.
-
- @a?fc2bf0
- FC2BF0 move.b #' ',$82(A6) Start using secondary key bindings.
- @a=fc2bf6
- @d
- @40d Indicate that input is being
- gathered for a specific function.
-
- ; Loop to read the digits. We stay in this loop, using the
- ; secondary (input gathering) key bindings until some command
- ; function switches us back to the primary ones. That means
- ; the user either canceled the line, or pressed RETURN.
-
- @40d Using secondary key bindings now?
- @40d Exit loop if not.
- @40d Get a key from the user.
- @40d Store it in "last key typed".
- @40d Dispatch it as a command character.
- @40d Loop.
-
- ; The input line has been processed. Either it was a command
- ; (and was executed), or it was a number, or it was an error.
-
- @40d Clear "parameter input" flag.
- @d
- @40d Get number of digits.
- @40d If no useful data in buffer (line
- @40d canceled, command already executed,
- @40d bad symbol...), return zero digits.
- @d
-
-
- ; Entry point for <Space> while using the secondary key bindings.
-
- @d
-
-
- ; Entry point for CTRL-U and CTRL-X. Point back to the original
- ; set of key bindings, and set the buffer to empty.
-
- @40d-1 characters in buffer.
- @40dRestore top-level key bindings.
- @40dPrint a linefeed.
- @40dBuffer contains no useful data.
- @d
-
-
- ; Entry point for <Backspace>. This deletes one charaacter from
- ; the input buffer.
-
- @40dAny characters in the buffer?
- @40dIf none, cancel input.
- @40dPoint to buffer.
- @40dGet buffer offset.
- @40dClear last character in buffer.
- @40dDecrement buffer count.
- @40dPoint to string below.
- @40dPrint it.
- @40dIs buffer now empty?
- @40dIf so, cancel input.
- @d
-
- ; String used to erase one character from the user's terminal.
-
- @8p@,4s
-
-
- ; Entry point for <Return>.
-
- @40dRestore previous key bindings.
- @40dPoint to input buffer.
- @40dGet number of characters in it.
- @d
- @40dIndicate that no data is in the
- buffer waiting for processing.
- @d
- @d
-
- ; There was data in the buffer, now interpret it.
-
- @40dZero-terminate the buffer.
- @40dPoint to it.
- @40dLook command up in table.
- @40dBranch if not found.
- @d
- @40dIndicate that buffer was processed.
- @40dGet the command table offset.
- @40dGet execution address from table.
- @40dExecute the command.
- @40dClear frame redisplay flag.
- @40dPop execution address of stack.
- @d
-
- ; Continue here if the buffer contained a string not found
- ; in the command table. For a full Wack, this means it would
- ; either be a number, or a symbol. For ROM-Wack, it's either
- ; a number or an error.
-
- @40dPoint to the string in the buffer.
- @40dPoint to input number location.
- @40dInterpret input buffer as a number.
- @40dStore number of digits.
- @d
- @40dIf 0 digits (bad hex number), print
- @40d"unknown symbol", indicate that no
- @40ddata is waiting in the buffer, and
- @40dexit.
-
- ; Continue here if number of digits was non-zero. If the number
- ; wasn't being gathered as a parameter to another command, make it
- ; the current location.
-
- @40dParameter being gathered?
- @40dExit if so.
- @40dRound number down to even.
- @d
- @40dSet the current location to it.
- @40dRequest (re)display of frame.
- @d
-
- @8p@,18s
-
-
- ; Hex number interpreting routine.
-
- @d
- @40dStart result at zero.
- @40dStart with "-1 digits".
- @d
- @40dJump into the loop.
- @40dEntry point for hex digits: Add 10.
- @d
- @40dShift previous number left by 4 bits.
- @40dAdd in new digit.
- @40dIncrement digit counter.
- @40dGet a digit from the input string.
- @40dExit if end of string reached.
- @a?fc2d14
- FC2D14 sub.b #'0',D0 Subtract '0'.
- @a=fc2d18
- @40dExit if result less than zero.
- @40dGreater than 9?
- @40dBranch if not.
- @40dSubtract 17.
- @40dExit if result less than zero.
- @40dBranch if less than 7.
- @d
- @a?fc2d2c
- FC2D2C sub.b #$20,D0 Subtract ('a' - 'A').
- @a=fc2d30
- @40dBranch if less than zero.
- @d
- @40dBranch if less than 7.
-
- ; If we branch here, the number entered contained an invalid
- ; hexadecimal digit.
-
- @40dReturn "0 digits".
-
- ; Branch here if end of string reached with no invalid digits.
-
- @40dStore result where indicated.
- @40dReturn number of digits.
- @d
- @d
-
-
- ; Some sort of format string. Not used anywhere.
-
- @a?fc2d42
- @8p@,6s
-
-
- ; Toupper() type of function. Converts character in D0 to upper
- ; case if necessary.
-
- @a?fc2d48
- FC2D48 cmp.b #'a',D0 Less than 'a'?
- @a=fc2d4c
- @d
- @a?fc2d4e
- FC2D4E cmp.b #'z',D0 Greater than 'z'?
- @a=fc2d52
- @d
- FC2D54 sub.b #$20,D0 If neither, convert to upper case.
- @a=fc2d58
- @d
-
- @8p@32wPadding.
-
- ---------------------------------------------------------------------------
- result = Procure( semaphore, bidMessage )
- D0 A0 A1
- ---------------------------------------------------------------------------
-
- ; A Procure/Vacate semaphore is a message port structure plus a
- ; counter. A task can "lock" the semaphore, by calling Procure().
- ; Further attempts to lock the semaphore won't succeed until the
- ; original locker unlocks the semaphore by Vacate().
-
- ; A sm_Bids value of -1 indicates that the semaphore is free, zero
- ; indicates it's locked and no one is waiting, 1 means one task is
- ; waiting, etc.
-
- ; Whenever Procure() is called, a pointer to a message must be
- ; given. This message is enqueued on the semaphore's port if the
- ; semaphore is not currently available, and returned when the
- ; caller's turn comes up to get the lock. If the semaphore was
- ; available (sm_Bids = -1), the message is not used.
-
- @40dIncrement the sm_Bids field.
- @40dCheck if the semaphore was free.
- @40dIf it was, store pointer to the
- current locker's message
- @40dand return TRUE.
- @d
- @40dIf it wasn't, enqueue the message
- @40don the semaphore's port and return
- @40dFALSE.
-
-
- ---------------------------------------------------------------------------
- Vacate( semaphore )
- A0
- ---------------------------------------------------------------------------
-
- ; A task which has successfully obtained a semaphore via Procure()
- ; calls this to release it again. The sm_Bids field is decremented.
- ; If it was zero and ends up at -1, nobody else was waiting to use
- ; the semaphore. If it ends up positive, someone else is waiting
- ; and we must send his bid message back to let him know he has it
- ; now. The first message enqueued on the semaphore's port is the
- ; task which has waited longest and gets it.
-
- @40dClear pointer to locker's message.
- @40dDecrement sm_Bids field.
- @40dReturn if it is now -1.
- @d
- @40dSave semaphore pointer.
- @40dDequeue the oldest bid message.
- @40dRestore semaphore pointer.
- @40dStore pointer to the message.
- @40dExit if no message (error).
- @d
- @40dReplyMsg() to inform the waiting
- @40dtask, then exit.
-
-
- ---------------------------------------------------------------------------
- InitSemaphore( signalSemaphore )
- A0
- ---------------------------------------------------------------------------
-
- @40dPoint to the waiting task list.
- @40dInitialize it to empty.
- @d
- @d
- @d
- @40dClear the ss_Owner field to null.
- @40dClear the ss_NestCount to zero.
- @40dSet the ss_QueueCount to -1.
- @d
-
-
- ---------------------------------------------------------------------------
- ObtainSemaphore( signalSemaphore )
- A0
- ---------------------------------------------------------------------------
-
- @40dForbid()
- @40dIncrement the ss_QueueCount.
- @d
-
- ; If the ss_Queuecount is now 0, then the semaphore was free and
- ; we got it. Set the pointer to the owning task, set the nesting
- ; level to 1, and exit.
-
- @40dStore pointer to owning task.
- @d
-
- ; The ss_Queuecount was not -1, so the semaphore was already owned
- ; by someone. Check if it is the calling task.
-
- @d
- @40dGet current task pointer.
- @40dDo we own the semaphore already?
- @40dIf so, increment nest count and exit.
-
- ; Another task owns the semaphore at the moment, so we must block.
- ; Since all non-running tasks must be on the TaskWait queue, we
- ; can't just enqueue the task on the semaphore. Instead, we build
- ; a temporary node on the stack, and enqueue that. Then we clear
- ; signal #2, and wait for someone to set it, which will occur when
- ; the current owner of the semaphore releases it. When we wake up,
- ; we deallocate the temporary node, and return to the user.
-
- @40dReserve 12 bytes of stack space.
- @40dStore pointer to this task.
- @40dClear signal #2.
- @40dPoint to waiting task list.
- @d
- @40dEnqueue the temporary list node.
- @d
- @40dWait for signal #2.
- @40dRelease the reserved stack space.
- @d
-
- @40dIncrement the nesting count.
- @40dPermit()
- @d
-
-
- ---------------------------------------------------------------------------
- ReleaseSemaphore( signalSemaphore )
- A0
- ---------------------------------------------------------------------------
-
- @40dDecrement the nesting count.
- @40dIf zero, release the semaphore.
- @40dIf it went negative, guru city!
- @40dOtherwise, just decrement the
- @40dss_QueueCount and exit.
-
- ; Continue here when the nesting count went to zero, and we
- ; therefore don't want the semaphore any more.
-
- @40dForbid()
- @40dDecrement the ss_QueueCount.
- @40dIf now -1, nobody was waiting.
-
- ; The ss_Queuecount is still positive, so someone is blocked on
- ; the semaphore and waiting to be awakened. The first (oldest)
- ; entry on the semaphore's queue gets it.
-
- @d
- @40dSave semaphore pointer.
- @40dPoint to semaphore's queue.
- @40dRemHead()
- @40dIf the queue was empty, guru city!
- @d
-
- ; We have a pointer (in D0) to a node which identifies the
- ; waiting process (the temporary one allocated on that process's
- ; stack).
-
- @d
- @d
- @40dGet pointer to waiting task.
- @40dMake this task the ss_Owner.
- @d
- @40dSet waiting task's signal #2.
- @d
- @40dExit.
-
- ; Continue here if nobody was waiting for the semaphore. In this
- ; case just clear the semaphore's owner field.
-
- @40dClear ss_Owner to null.
- @40dPermit()
- @d
-
- ; Put up an alert if the semaphore's nest count went negative
- ; (should never happen, we give away the semaphore when it reaches
- ; zero), or if the semaphore's queue was empty even though the
- ; ss_QueueCount said it isn't.
-
- @d
- @40dAlert number (fatal).
- @40dGet ExecBase.
- @40dPut up the alert.
- @40dNever executed.
- @d
-
-
- ---------------------------------------------------------------------------
- success = AttemptSemaphore( signalSemaphore )
- D0 A0
- ---------------------------------------------------------------------------
-
- @40dGet pointer to current task.
- @40dForbid()
- @40dIncrement the ss_QueueCount.
- @40dBranch if now zero.
- @40dDo we own the semaphore already?
- @40dBranch if true.
- @40dDecrement the ss_QueueCount again.
- @40dPermit()
- @40dReturn FALSE.
- @d
-
- ; Continue here if we were able to get the semaphore.
-
- @40dInstall pointer to owning task.
- @40dIncrement nest count.
- @40dPermit()
- @40dReturn TRUE.
- @d
-
-
- ---------------------------------------------------------------------------
- ObtainSemaphoreList( list )
- A0
- ---------------------------------------------------------------------------
-
- ; This function is given a linked list of semaphore structures, and
- ; obtains them all. This is done in two passes. On the first pass,
- ; a SemaphoreRequest is enqueued on all semaphores which aren't free,
- ; and all the free ones are grabbed.
-
- ; On the second pass, the list is traversed again. This time, if
- ; we already have a semaphore, we just pass it, otherwise, we wait
- ; for it.
-
- ; Note: Whereas ObtainSemaphore() builds its SemaphoreRequest node
- ; on the task's stack, this one uses the single copy inside the
- ; semaphore structure. This means that a crash is sure to result
- ; if more than one task tries to ObtainSemaphoreList and several
- ; end up waiting for the same semaphore. The documentation has
- ; a bit more to say about this.
-
- @d
- @40dClear the "need to wait" flag.
- @40dGet pointer to current task.
- @40dForbid()
- @d
- @40dPoint to first semaphore in list.
- @d
- @40dEnd of list reached?
- @40dExit loop if so.
- @40dIncrement current semaphore's count.
- @40dBranch if now zero.
- @40dCheck if the semaphore is ours.
- @40dBranch if true.
- @40dUse the ss_MultipleLink structure
- @40dto enqueue our semaphore request on
- @40dthe semaphore's wait queue.
- @d
- @40dIndicate that we need to wait.
- @40dGo to next semaphore in list.
-
- ; We got a semaphore.
-
- @40dMake us the owner of this semaphore.
- @40dIncrement its nest count.
- @40dTry next semaphore in the list.
-
- ; The end of the list was reached.
-
- @40dDid we get all the semaphores?
- @40dIf so, exit.
-
- ; We have to wait for at least one semaphore in the list.
-
- @40dGo to the start of the list.
- @d
- @40dEnd of list reached?
- @40dIf so, exit.
- @40dDo we own this semaphore?
- @d
- @40dIf we do, and its nest count is not
- @40dzero, go on to the next one.
- @40dIncrement the nest count.
- @40dGo on to the next one.
-
- ; Wait for a semaphore.
-
- @d
- @40dWait for signal #2.
- @40dGo back and check if we have it now.
- @40dPermit()
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- ReleaseSemaphoreList( list )
- A0
- ---------------------------------------------------------------------------
-
- @d
- @40dGo to the start of the list.
- @40dGo to first/next node.
- @40dEnd of list reached?
- @40dIf so, exit.
- @40dReleaseSemaphore()
- @40dLoop until all done.
- @d
- @d
-
-
- ---------------------------------------------------------------------------
- AddSemaphore( signalSemaphore )
- A1
- ---------------------------------------------------------------------------
-
- @40dInitSemaphore()
- @40dPoint to global semaphore list.
- @40dAdd the semaphore to the list.
-
-
- ---------------------------------------------------------------------------
- RemSemaphore( signalSemaphore )
- A1
- ---------------------------------------------------------------------------
-
- @40dUnlink semaphore from whatever
- list it's in.
-
- ---------------------------------------------------------------------------
- signalSemaphore = FindSemaphore( name )
- D0 A1
- ---------------------------------------------------------------------------
-
- @40dPoint to global semaphore list.
- @40dFindName()
- @d
-
-
- @8p@32wPadding.
-
-
- ---------------------------------------------------------------------------
- CopyMemQuick( source, dest, size )
- A0 A1 D0
- ---------------------------------------------------------------------------
-
- ; The caller guarantees that the source and destination are even,
- ; and that the transfer count is a multiple of 4. This allows us
- ; to skip some of the strategy below.
-
- @40d0 bytes left over after longword copy.
- @40dGo copy (at least) as longwords.
-
-
- ---------------------------------------------------------------------------
- CopyMem( source, dest, size )
- A0 A1 D0
- ---------------------------------------------------------------------------
-
- ; This is an interesting tutorial on efficient 68000 memory moving.
-
- ; Note that this is not necessarily the best way to move memory on
- ; a 68010 or 68020, since both of these processors have expanded
- ; features designed to make memory moving more efficient, and all
- ; the computational overhead of choosing the right copying method
- ; might not be worth it.
-
- @40dLess than 12 bytes to copy?
- @d
- @40dIf so, just copy byte by byte.
-
- ; The following bit of code handles odd/even source and destination
- ; addresses. The following is done:
-
- ; Source and destination even: Just continue.
- ; Source and destination odd: Copy 1 byte. Both addresses are now
- ; even, so we can continue.
- ; Source even, dest. odd: Copy byte by byte.
- ; Source odd, destination even: Copy one byte, then copy the rest
- ; byte by byte.
-
- ; Note that there is nothing we can do if the source and destination
- ; differ by an odd number, i.e. are "out of phase". In such a case,
- ; we must copy byte by byte.
-
- @d
- @40dIs the source address odd?
- @40dBranch past the following if not.
- @40dCopy one byte.
- @40dDecrement transfer count.
- @d
- @40dIs the destination address odd?
- @40dIf so, transfer byte by byte.
-
- ; Both the source and destination addresses are (now) even.
- ; The worst that can happen now is that we have to move the data
- ; as individual longwords. First, compute how many bytes will
- ; be left over after we move the data as longwords, and save this
- ; value.
-
- @40dFind how many bytes will be left
- @40dif data is copied as longwords.
- @40dSave this number.
-
- ; The "move multiple" approach below copies 48 bytes of data with
- ; only two instructions. But to use it, 48 bytes of registers need
- ; to be saved and restored, and so it's not worth it unless we have
- ; at least two 48 byte "batches" to copy.
-
- @d
- @40d96 or more bytes to move?
- @40dIf not, copy as longwords.
- @40dSave 12 registers on the stack.
- @40dGet 48 bytes with one instruction.
- @40dMove them to the destination.
- @d
- @40dAdd 48 to destination address.
- @40dSubtract 48 from transfer count.
- @40dCopy another batch if 48 or more
- @40dbytes remain to be copied.
- @40dRestore the 12 registers.
-
- ; Whatever the case, D0 now contains the number of bytes left over.
- ; Copy as many of these as possible as longwords.
-
- @40dSee how many longwords to copy.
- @40dBranch if none.
- @40dAdjust for dbra.
- @40dSplit up into two 16-bit values.
- @d
- @40dCopy the longwords.
- @d
- @d
-
- ; Done copying longwords. Get the number of bytes left over (0-3)
- ; from the stack and fall into the byte copy routine.
-
- @40dRestore number of bytes left over.
- @40dExit if none.
- @40dHigh 16 bits of byte count = 0.
- @40dEnter the byte copy loop.
-
- ; Copy as individual bytes, either to clean up odds and ends after
- ; copying in larger chunks, or because copying in larger chunks
- ; wasn't worth it.
-
- @40dSplit transfer count up into two
- @40d16-bit sections.
- @40dEnter loop at bottom (for dbra).
- @40dCopy the bytes.
- @d
- @d
- @d
-
-
- ; System exception alert entry point
- ; ----------------------------------
-
- ; If an exception occurs or a TRAP instruction is executed while the
- ; CPU is in supervisor mode, we jump here, since we have no task to
- ; blame it on. If a task was running, we use its tc_TrapCode vector
- ; instead, but at powerup, the exec default for this vector is also
- ; initialized to point here. Later, it is stolen by some other
- ; part of the system so the "Software error - task held" window can
- ; be put up before the guru.
-
-
- @40dDump the registers.
- @40dPoint at exception data on the stack.
- @40dGet ExecBase.
- @40dIs it even?
- @d
- @40dIf so, point where the current task
- @40dpointer probably is.
- @40dGet the exception number.
- @40dMask out any garbage.
-
- ; Fall into Alert(). alertNum is the exception number from the
- ; stack, and A5 points either to the current task pointer, or to
- ; the exception data on the stack.
-
-
- ---------------------------------------------------------------------------
- Alert( alertNum, parameters )
- D7 A5
- ---------------------------------------------------------------------------
-
- ; This routine has a relatively failsafe mechanism for getting an
- ; alert message up on the screen. I call this the "deferred guru".
-
- ; Right away, a signature ("HELP") is installed at location 0, and
- ; the guru data is stored at location $000100. If the system hangs
- ; now, the user will get the guru after he/she reboots manually
- ; via CTRL-Amiga-Amiga. If for any reason it decides it's in
- ; serious trouble, it will reset itself, with the same effect.
-
- @40dDisable all interrupts.
- @d
-
- ; If location 0 ALREADY contains "HELP", something is wrong, and
- ; no matter what the requested alert was, we reset the computer.
-
- @40dSee if "HELP" is at location zero.
- @40dIf so, unrecoverable crash.
-
- ; Store our own "deferred guru" data at 0 and $000100. Then see
- ; if we should use it. If ExecBase has been clobbered, or the
- ; stack is not working, or the unrecoverable alert bit is set,
- ; we blink the power light, and reset the computer. The guru will
- ; come up during the reboot.
-
- @40dMove "HELP" at location 0 now.
- @40dPoint at location $000100.
- @40dStore alert number there.
- @40dStore the parameter.
-
- @40dGet ExecBase.
- @d
-
- ; Without checking, I would assume that this is where the famous
- ; "Recoverable alert doesn't work with expansion memory" bug is.
-
- ; Namely, if the ExecBase structure isn't in the first 64K of
- ; memory, we assume that it isn't OK. With $C00000 memory, it
- ; will be at $C00276, and KABOOM, this fails, and the system
- ; resets, doing the unrecoverable alert thing via the "deferred
- ; alert" mechanism discussed earlier.
-
- @40dIs ExecBase in the first 64K?
- @40dIf not, unrecoverable crash.
- @d
- @40dCheck ExecBase complement pointer.
- @d
- @40dUnrecoverable crash if not valid.
- @40dCheck if the stack is working by
- @40dpushing a signature and trying to
- @40dpop it off again.
- @40dUnrecoverable crash if not working.
- @40dTest high bit of alert number.
- @40dBranch if unrecoverable.
-
- ; Processing for recoverable alerts. If we get this far, we have
- ; verified that the "dead end alert" flag was not set, that the
- ; ExecBase pointer and structure are probably OK, and that the
- ; stack is working (stack pointer pointing to RAM).
-
- @40dPoint to ExecBase->LastAlert.
- @40dStore alert number.
- @40dStore parameter.
- @40dCall the guru alert routine.
-
- @40dWas the subsystem ID field zero?
- @40dIf not, return to the caller.
-
- ; The alert number was of the form 0000xxxx. This means that it
- ; must have been a system exception. Presumably, the user has had
- ; the option of pressing the left or right mouse button, reflected
- ; in D0 as returned from the guru routine. Accordingly, we
- ; reset or go to the debugger.
-
- @40dTest the guru routine's return code.
- @40dRestore the registers.
- @40dReset if zero flag not set.
- @40dElse go to ROM-Wack.
-
- @40dEnable interrupts if they are
- @40dsupposed to be enabled.
- @d
- @d
-
-
- ; Unrecoverable system crash entry point
- ; --------------------------------------
-
- ; This routine blinks the power light slowly 6 times, and checks
- ; whether the user presses DEL on a terminal attached to the
- ; serial port. If DEL is received, it jumps to ROM-Wack. If
- ; DEL is not received, it resets the computer. This may or may
- ; not lead to a guru, depending on how locations 0 and $000100 were
- ; set up before this was called.
-
- ; Entry point for when the stack is not working (stack pointer
- ; clobbered). Set the stack pointer to 256K, and build a fake
- ; exception stack frame below it.
-
- @40dSet stack pointer to 256K
- @40dBuild fake exception stack frame.
- @d
-
- ; Entry point for when the stack was working.
-
- @40dSet CIA data direction register.
- @40dSet power light to bright.
-
- ; Force the CPU into supervisor mode. If the MOVE.W #$2700,SR
- ; instruction bombs the first time, it will work the second time.
-
- @40dSet privilege violation vector.
- @a?fc3076
- FC3076 move.w #$2700,SR Mask all maskable interrupts.
- @a=fc307a
-
- ; Blink the power light slowly 6 times and look for a DEL character
- ; coming in through the serial port at 9600 bps. If such a character
- ; is received, go to the debugger.
-
- @40dSet loop counter to 5.
- @40dSet serial port for 8 bits, 9600 bps.
- @d
- @40dSet power light to dim.
- @40dDelay.
- @40dSet power light to bright.
- @40dDelay.
- @40dRead the serial port.
- @40dClear serial port interrupt bit.
- @d
- @40dDid we receive a DEL character?
- @40dIf not, keep blinking the light.
- @40dIf DEL not pressed, reset.
-
- ; The user pressed DEL. Push the exception number on the stack
- ; and enter the debugger.
-
- @d
- @40dGo to ROM-Wack.
-
-
- ; "Deferred Guru" support routines
- ; --------------------------------
-
- ; The following routine is called early in the startup code. Since
- ; there is no stack at that point, it returns via a jump, rather
- ; than an RTS. It removes the "HELP" at zero, if present, and
- ; loads D6 and D7 with the data for ExecBase->LastAlert.
-
- @40dLoad -1 into D6
- @40dSee if location 0 contains "HELP".
- @40dIf not, go back to init. code.
- @40dClear location 0.
- @40dLoad D6 and D7 from location $0100.
- @40dGo back to init. code.
-
- ; The following subroutine is called later, after the ExecBase
- ; structure has been built. It writes the data determined above
- ; (still in D6 and D7) into ExecBase->LastAlert.
-
- @d
- @d
-
-
- ; Guru Alert Routine
- ; ------------------
-
- ; This routine puts the big red "Guru" message up on the screen,
- ; waits for the user to click the mouse button, then returns.
-
- ; The routine is called with the alert number and parameters stored
- ; at LastAlert in the ExecBase structure. This routine reads the
- ; alert number from there and decides what to do with it.
-
- ; An alert number of -1 means that no alert was outstanding, and
- ; therefore, the routine returns right away. This means that if
- ; it is called via the "alert.hook" mechanism, and no alert was
- ; pending from before the reboot, nothing will happen.
-
- ; If the alert number is not -1, an alert will be generated. The
- ; following algorithm is used to decide what the first string in
- ; the alert should say.
-
- ; IF the alert number is of the form xxxx01xxxxxxxx THEN
- ; Make the alert message "Not enough memory".
- ; ELSEIF the high bit in the alert number is clear, and the
- ; "general error" field is not zero THEN
- ; Make the alert message "Recoverable Alert".
- ; ELSE
- ; Make the alert message "Software Failure".
- ; ENDIF
-
- ; When the alert is finished (the user pressed the mouse button),
- ; the LastAlert field in ExecBase is cleared to -1, and the longword
- ; at location 0 is cleared to zero.
-
-
- @d
-
- @40dDelay for a while.
- @d
- @d
- @d
-
- @40dGet the alert number.
- @40dCompare to -1 (indicates no alert).
- @d
- @40dExit if equal.
- @40dReserve 200 bytes of stack space.
- @40dPoint to base of reserved area.
-
- ; Decide which alert message to use.
-
- @40dPoint to "Software Failure" string.
- @40dGet the alert number.
- @40dGet the general error number.
- @40dIs it an AG_NoMemory type of alert?
- @40dIf so, point to "Not enough Memory"
- @40dstring.
- @d
- @40dIf otherwise, check the dead-end
- @40dalert flag. If it is clear, but
- @40dthe Subsystem/General error fields
- @40dare not zero, then point to the
- @40d"Recoverable Alert" string.
-
- @40dCopy the string into the buffer.
- @40dPoint to "Press left mouse button..."
- @40dCopy the string into the buffer.
- @40dPut a zero into the buffer.
- @40dPoint to "Guru Meditation..." string.
- @40dPoint to alert data.
- @40dPoint to character output routine.
- @40dRawDoFmt()
-
- @40dPoint to "intuition.library".
- @40dMinimum version is 0 (any).
- @40dOpenLibrary()
- @40dDid it open OK?
- @40dIf not, skip the following.
- @40dSave ExecBase.
- @40dGet IntuitionBase.
- @40dTell intuition that the alert # is 0.
- @40dPoint to the alert string.
- @40dAlert should be 40 video lines high.
- @40dDisplayAlert()
- @d
- @40dGet IntuitionBase.
- @40dRestore ExecBase.
- @40dCloseLibrary()
-
- @40dDeallocate string space on stack.
- @40dRemove "HELP" at 0, if present.
- @d
- @40dSet LastAlert to -1.
-
- ; Set the return code. If intuition.library didn't open, A2 contains
- ; a non-zero address, so a non-zero return value results. If
- ; intuition could be called, this is the return code from the
- ; DisplayAlert() call.
-
- @40dSet return code.
- @d
- @d
-
- ; Character output routine for RawDoFmt() while putting together
- ; the "Guru Meditation #..." message.
-
- @40dPut character in buffer.
- @40dZero-terminate the buffer.
- @d
-
- ; Routine to copy a given string to the output buffer while
- ; building the guru message.
-
- @40dPut a zero into the buffer.
- @40dCopy the given string.
- @d
- @40dTerminate buffer with $FF.
- @d
-
- ; Strings used for the guru message.
-
- @8p@,22s
- @8p@,21s
- @8p@,22s
- @8p@,39s
- @8p@,31s
-
- ; Name used to open intuition to put up the alert.
-
- @8p@,18s
-
-
- ; The "alert.hook" mechanism
- ; --------------------------
-
- ; This is a RomTag. At system startup, this will be found and added
- ; to the resident module list. Since it has the RTW_COLDSTART flag
- ; set, it will be initialized along with the other libraries,
- ; devices, etc. The RTF_AUTOINIT flag is not set, therefore, the
- ; code at RT_INIT is called.
-
- ; The code at RT_INIT is the Guru routine. This reads the LastAlert
- ; field in ExecBase. If this is not -1, then an alert is still
- ; outstanding (from before the reboot), and this puts it up, lets
- ; the user click the mouse button, then returns. The resident
- ; module initialization then continues, the DOS boots, and the
- ; system comes up.
-
- ; The purpose of all this is to allow the system to defer display
- ; of a guru message until after the system has been cold-started.
-
-
- @8p@,13s
-
- @a?fc323a
- @8p@24wRTC_MATCHWORD (start of ROMTAG marker)
- @8p@24lRT_MATCHTAG (pointer RTC_MATCHWORD)
- @8p@24lRT_ENDSKIP (pointer to end of code)
- @8p@24bRT_FLAGS (RTW_COLDSTART)
- @8p@24bRT_VERSION (33 decimal)
- @8p@24bRT_TYPE (NT_UNKNOWN)
- @8p@24bRT_PRI (priority = 5)
- @8p@24lRT_NAME (pointer to name)
- @8p@24lRT_IDSTRING (pointer to ID string)
- @8p@24lRT_INIT (execution address)
-
-
- ; ROM-Wack command dispatch tables ("Key bindings").
- ; --------------------------------------------------
-
- ; ROM-Wack can be in one of two modes when a key is pressed. It can
- ; be waiting for a command, or it can be in the process of gathering
- ; a multi character command. The two tables below decide what to do
- ; with the key in each case.
-
- ; Each table entry has 4 fields. These are, address of next table
- ; entry to try if key doesn't match this one, lowest key value for
- ; this table entry, highest key value (if several) or zero, address
- ; to jump to.
-
- ; Primary command dispatch table.
-
- @8p@9l@3b@3b@17l^D
- @8p@9l@3b@3b@17l<Return>
- @8p@9l@3b@3b@17l<Tab>
- @8p@9l@3b@3b@17l?
- @8p@9l@3b@3b@17l.
- @8p@9l@3b@3b@17l,
- @8p@9l@3b@3b@17l>
- @8p@9l@3b@3b@17l<
- @8p@9l@3b@3b@17l<Backspace>
- @8p@9l@3b@3b@17l<Space>
- @8p@9l@3b@3b@17l[
- @8p@9l@3b@3b@17l]
- @8p@9l@3b@3b@17l:
- @8p@9l@3b@3b@17l+
- @8p@9l@3b@3b@17l-
- @8p@9l@3b@3b@17l=
- @8p@9l@3b@3b@17l!
- @8p@9l@3b@3b@17l^
- @8p@9l@3b@3b@17l_
- @8p@9l@3b@3b@17l0 - 9
- @8p@9l@3b@3b@17la - z
- @8p@9l@3b@3b@17lA - Z
-
- @8p@32lEnd of table marker.
-
-
- ; Secondary command dispatch table (used while a command
- ; and/or address is being typed).
-
- @8p@9l@3b@3b@17l<Backspace>
- @8p@9l@3b@3b@17l<Return>
- @8p@9l@3b@3b@17l<CTRL-X>
- @8p@9l@3b@3b@17l<CTRL-U>
- @8p@9l@3b@3b@17l>
- @8p@9l@3b@3b@17l<
- @8p@9l@3b@3b@17l<Space>
- @8p@9l@3b@3b@17l_
- @8p@9l@3b@3b@17l0 - 9
- @8p@9l@3b@3b@17la - z
- @8p@9l@3b@3b@17lA - Z
-
- @8p@32lEnd of table marker.
-
-
- ; Table of multi-character ROM-Wack commands.
-
- @8p@,22s
- @8p@,22s
- @8p@,22s
- @8p@,12s
-
-
- ; Dispatch table for multicharacter commands.
-
- ; The fields are link to next table entry, address of command string,
- ; an unused value (presumably from a larger version of Wack), and
- ; the address to jump to for that command.
-
- @a?fc33f4
- @8p@9l@9l@5w@13l"alter"
- @8p@9l@9l@5w@13l"boot"
- @8p@9l@9l@5w@13l"clear"
- @8p@9l@9l@5w@13l"fill"
- @8p@9l@9l@5w@13l"find"
- @8p@9l@9l@5w@13l"go"
- @8p@9l@9l@5w@13l"ig"
- @8p@9l@9l@5w@13l"limit"
- @8p@9l@9l@5w@13l"list"
- @8p@9l@9l@5w@13l"regs"
- @8p@9l@9l@5w@13l"reset"
- @8p@9l@9l@5w@13l"resume"
- @8p@9l@9l@5w@13l"set"
- @8p@9l@9l@5w@13l"show"
- @8p@9l@9l@5w@13l"user"
- @8p@l
-
- @8p@32wPadding.
-
- ; That's it. The next RomTag (for the audio.device) comes right
- ; after the two bytes of padding shown above.
-