home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 215.lha / ExecDis / dis.data < prev    next >
Text File  |  1996-02-15  |  214KB  |  7,580 lines

  1. @a=fc0000
  2. ****************************************************************************
  3. *                                                                          *
  4. *  Comments copyright (c) 1989 Markus Wandel                               *
  5. *                                                                          *
  6. *  Release date:  February 3, 1989.                                        *
  7. *                                                                          *
  8. *  The following is a complete disassembly of the Amiga 1.2 "exec", as     *
  9. *  found on a kickstart disk for an Amiga 1000.  Everything is shown,      *
  10. *  right down to the padding introduced by the linker, and unused code     *
  11. *  fragments which probably made it in by accident.                        *
  12. *                                                                          *
  13. *  Thorough familiarity with the Rom Kernel Manual: Exec, with suitable    *
  14. *  updates to version 1.2, and the exec subdirectory of the include files, *
  15. *  is assumed in all comments.  Where existing documentation appears to    *
  16. *  be inadequate, or a particular section of code is judged to be more     *
  17. *  interesting than most, comments are more extensive.                     *
  18. *                                                                          *
  19. *  Absolutely no guarantee is made of the correctness of all information   *
  20. *  supplied below, nor of its usefulness.                                  *
  21. *                                                                          *
  22. *  Note that virtually all references to "ROM" actually refer to the       *
  23. *  write-protected RAM which the kickstart disk loads into.  The genuine   *
  24. *  ROMs on Amiga 500 and 2000 computers may not contain exactly the same   *
  25. *  code, although most of it should be similar.                            *
  26. *                                                                          *
  27. *  The completed disassembly file is not redistributable, and contains     *
  28. *  code which is copyrighted by Commodore-Amiga, and comments which are    *
  29. *  copyrighted by Markus Wandel.  The source file used to make the         *
  30. *  disassembly is distributable under a limited set of conditions as       *
  31. *  outlined in the accompanying documentation.                             *
  32. *                                                                          *
  33. *  For Commodore-Amiga's copyright notice, see a few lines farther down.   *
  34. *                                                                          *
  35. ****************************************************************************
  36.  
  37.         ; This match word is used when looking for ROMs.
  38.  
  39. @8p@w
  40.  
  41.         ; The ROM can be started by jumping to its base address plus 2,
  42.         ; or by mapping it at location zero and resetting.  Either way,
  43.         ; the machine starts running at FC00D2 (in the latter case, because
  44.         ; the 68000's PC is loaded from location 4 at cold start).
  45.  
  46. @d
  47. @a?fc0008
  48.  
  49. @8p@28wGarbage.
  50. @8p@w
  51.  
  52.         ; The following version number doesn't appear to be used
  53.         ; from within exec.library.
  54.  
  55. @8p@w
  56. @8p@w
  57.  
  58.         ; The following version number appears in the exec.library
  59.         ; node, and this copy is checked to ensure it is still valid.
  60.  
  61. @8p@28wVersion.
  62. @8p@28wRevision.
  63.  
  64. @8p@28lGarbage.
  65.  
  66.         ; The exec's ID string
  67.         ; --------------------
  68.  
  69. @8p@,28s
  70.  
  71. @8p@28lGarbage.
  72.  
  73.         ; Copyright notice.
  74.         ; -----------------
  75.  
  76. @8p@,45s
  77. @8p@,43s
  78. @8p@,24s
  79.  
  80.         ; Library name
  81.         ; ------------
  82.  
  83. @8p@,14s
  84.  
  85.         ; The RomTag structure.
  86.         ; ---------------------
  87.  
  88. @8p@28wRTC_MATCHWORD   (start of ROMTAG marker)
  89. @8p@28lRT_MATCHTAG     (pointer RTC_MATCHWORD)
  90. @8p@28lRT_ENDSKIP      (pointer to end of code)
  91. @8p@28bRT_FLAGS        (no flags)
  92. @8p@28bRT_VERSION      (version number)
  93. @8p@28bRT_TYPE         (NT_LIBRARY)
  94. @8p@28bRT_PRI          (priority = 126)
  95. @8p@28lRT_NAME         (pointer to name)
  96. @8p@28lRT_IDSTRING     (pointer to ID string)
  97. @8p@28lRT_INIT         (execution address)
  98. @a?fc00d0
  99.  
  100.  
  101. @d
  102.  
  103.         ; We start running here.
  104.  
  105. @36dSet stack pointer to top of first 128K.
  106. @d
  107. @36dDelay loop.
  108. @d
  109.  
  110.         ; If the ROM is also visible at F00000, or if there is another
  111.         ; ROM there, jump there.
  112.  
  113. @36dLoad base address of ROM we're in.
  114. @36dLoad (absolute address) F00000.
  115. @36dAre we at F00000?
  116. @36dIf so, don't execute the following.
  117. @36dThis is relative, i.e. always points
  118.                                     12 bytes down from where we are.
  119. @36dIf "1111" not found at F00000, then
  120. @36dcontinue running below, else start
  121. @36drunning at F00002.
  122.  
  123.         ; Set up port A on the first CIA (8520-A).
  124.  
  125. @36dSet low two bits for output.
  126. @36dSet boot ROM off, power light dim.
  127.  
  128.         ; Disable interrupts and DMA.
  129.  
  130. @36dBase address of custom chip area.
  131. @d
  132. @36dDisable all interrupts.
  133. @36dClear all pending interrupts.
  134. @36dDisable all DMA.
  135.  
  136.         ; Set a blank, dark gray display.
  137.  
  138. @36dBPLCON0 = Blank screen.
  139. @36dBitplane 0 data = all zeros.
  140. @36dBackground colour = dark gray.
  141.  
  142.         ; Set up the Exception Vector Table.  Vectors 2 through 47
  143.         ; (Bus Error through TRAP #15) are all all set to the initial
  144.         ; exception handler.  If any exception occurs now, the screen
  145.         ; will turn yellow, the power light will flash, and the computer
  146.         ; will be reset.
  147.  
  148. @36dStart at address 8 (vector #2).
  149. @36dDo 46 vectors.
  150. @36dAddress of initial exception handler.
  151. @36dSet one vector
  152. @36dLoop back.
  153.  
  154.         ; See if the system wants a guru put up after reboot.
  155.  
  156.         ; This works as follows:  If for some reason, a guru can't be put
  157.         ; up in the normal fashion, the system writes "HELP" at location
  158.         ; zero, writes the alert data (number and 32-bit parameter) at
  159.         ; location $000100, and resets.
  160.  
  161.         ; Early in the startup code (right here), this "HELP" is checked
  162.         ; for.  If it is present, it is removed, and the data at location
  163.         ; $000100 is loaded into registers D6 and D7.  If no "HELP" is
  164.         ; found, register D6 is loaded with -1.  This data will later be
  165.         ; put at ExecBase->LastAlert, once the ExecBase structure has been
  166.         ; built.  The following subroutine call does all this.
  167.  
  168. @36dCheck for "HELP" at location 0.
  169.  
  170.         ; Check whether there is already a valid ExecBase data structure.
  171.         ; This is important, since it indicates whether we need to clear and
  172.         ; reconfigure memory (wiping out recoverable RAM disks and such),
  173.         ; or whether we already know the memory configuration and can leave
  174.         ; it untouched.
  175.  
  176.         ; Note that if the machine crashed in such a way that the ExecBase
  177.         ; structure got clobbered, memory will be cleared.
  178.  
  179. @36dGet pointer at location 4.
  180. @36dCheck if it is an odd address.
  181. @36dGo reconfigure memory if it is.
  182. @36dAssume we are pointing to ExecBase.
  183. @36dGet complement of ExecBase.
  184. @36dCheck it.
  185. @36dGo reconfigure memory if it didn't match.
  186. @d
  187. @36dChecksum the static part of the ExecBase
  188. @36ddata structure.
  189. @d
  190. @d
  191. @36dVerify the checksum.
  192. @36dGo reconfigure memory if not valid.
  193.  
  194.         ; If we get this far, we are reasonably confident that the ExecBase
  195.         ; structure is OK, and run the cold start capture code if there
  196.         ; is any.
  197.  
  198. @36dGet the cold start capture vector.
  199. @36dBranch if it is zero.
  200. @d
  201. @36dWhere to come back afterward.
  202. @36dClear the cold start capture vector.
  203. @36dJump to the cold start capture code.
  204.  
  205.         ; We come here if the cold start capture vector was zero, or
  206.         ; upon return from the cold-start capture code.  We continue
  207.         ; to verify the ExecBase structure.
  208.  
  209. @36dFlip the power light to bright.
  210.  
  211. @36dCheck the version/revision numbers
  212. @36dstored in ExecBase against those in ROM.
  213. @36dGo reconfigure memory if no match.
  214.  
  215. @36dGet end address of chip memory.
  216. @36dGreater than 512K?
  217. @36dIf so, it must be invalid.
  218. @36dLess than 256K?
  219. @36dIf so, it must be invalid.
  220.  
  221. @36dGet end address of $C00000 memory.
  222. @d
  223. @36dAll OK if no $C00000 memory.
  224. @36dCheck more than 1.5 meg (invalid).
  225. @36dGo reconfigure memory if so.
  226. @36dCheck if less than 256K (invalid).
  227. @36dGo reconfigure memory if so.
  228. @d
  229. @36dCheck that ends on a 256K boundary.
  230. @36dAll OK if it does.
  231.  
  232.         ; If we come here, it was decided that there is no valid ExecBase
  233.         ; data structure.  This means we have to figure out what the memory
  234.         ; configuration of the machine is.
  235.  
  236.         ; First, calculate ExecBase based on the assumption that the ExecBase
  237.         ; structure will end up in chip RAM.  This would put it at $0676,
  238.         ; just far enough past the exception vector table to make room for
  239.         ; the jump table.
  240.  
  241. @36dCalculate $0676.
  242. @36d(don't ask me why they do it like this).
  243.  
  244.         ; Now go and check for memory in the $C00000 - $DC0000 area.
  245.         ; This allows for a maximum of 1.75 megabytes of non-chip memory
  246.         ; to be automatically configured if located at $C00000.
  247.  
  248. @36dLower bound for $C00000 memory.
  249. @36dHigh bound for $C00000 memory.
  250. @36dReturn address.
  251. @36dGo check how much we have.
  252. @36dDid we find any expansion memory?
  253. @36dIf not, skip the following.
  254.  
  255.         ; The machine has expansion RAM at $C00000.  We put the ExecBase
  256.         ; structure there to save chip memory.  This puts it at $C00276.
  257.  
  258. @36dCalculate $C00276.
  259. @d
  260.  
  261.         ; Now we clear the expansion memory to zeros.
  262.  
  263. @36dGet end address of expansion memory.
  264. @36dGet start address of expansion memory.
  265. @36dSet return address.
  266. @36dGo clear the memory.
  267.  
  268.         ; Having figured out the end address of expansion memory (in A4),
  269.         ; and the value to use for ExecBase (in A6), we now check how much
  270.         ; chip memory we have.  Any memory in the first 2 megabytes of
  271.         ; address space is considered to be chip memory.  Less than 256K
  272.         ; of chip memory is considered a fatal error.
  273.  
  274. @36dStart looking at location 0.
  275. @36dDon't look past 2 megabytes.
  276. @36dSet the return address.
  277. @36dGo check the memory.
  278. @36dDo we have at least 256K of chip memory?
  279. @36dBomb if not.
  280.  
  281.         ; Clear chip memory.  Everything from $C0 (right after the end of
  282.         ; the initial exception vector table we've set up) to the end of
  283.         ; chip memory is cleared.
  284.  
  285. @36dClear location 0.
  286. @d
  287. @36dSet start address to $C0 (end of vectors)
  288. @36dSet return address.
  289. @36dGo clear the chip memory.
  290.  
  291.         ; Since we have found less than 256K of chip memory, some of it
  292.         ; must not be working.  Turn the screen bright green, blink the
  293.         ; power light, and reset.
  294.  
  295. @d
  296. @d
  297.  
  298.         ; We continue here after we've figured out where the chip memory
  299.         ; ends (256K or greater) and where the $C00000 memory ends
  300.         ; (0 if none present).  The two addresses are in A3 and A4,
  301.         ; respectively.
  302.  
  303. @36dPoint to base of custom chip area.
  304. @36dDisable all DMA.
  305. @36dSet BPLCON0 for a blank screen.
  306. @36dSet bitplane 0 data to zeros.
  307. @36dSet background colour to medium gray.
  308.  
  309.         ; Clear most of the ExecBase structure to zeros.
  310.  
  311. @36dPoint at ExecBase->IntVects.
  312. @36dGet KickMemPtr, KickTagPtr, KickCheckSum.
  313. @d
  314. @36dClear all of ExecBase from IntVects
  315. @36dto the end of the structure.
  316. @d
  317. @36dRestore Kick variables saved above.
  318.  
  319.         ; Set up the ExecBase pointer at location 4, and its complement
  320.         ; in the ExecBase structure.
  321.  
  322. @36dInstall ExecBase pointer at location 4.
  323. @d
  324. @d
  325. @36dInstall ExecBase complement check value.
  326.  
  327.         ; Set up the system stack.
  328.  
  329. @36dTry to put stack in $C00000 RAM.
  330. @36dDo we have any $C00000 RAM?
  331. @36dIf not, use chip RAM.
  332. @36dSet system stack pointer.
  333. @36dStore system stack upper bound.
  334. @36dAllow 6K bytes for system stack.
  335. @36dStore system stack lower bound.
  336.  
  337.         ; Store the memory configuration.  Next reset will use this if
  338.         ; still intact, and not clear memory.
  339.  
  340. @36dStore top of chip memory.
  341. @36dStore top of $C00000 memory.
  342.  
  343.         ; Part 2 of the deferred-guru procedure.  Long ago, we set up
  344.         ; registers D6 and D7 with the data for ExecBase->LastAlert.
  345.         ; The following call writes them there.  Now all is ready for
  346.         ; the "alert.hook" mechanism to put up the deferred guru, if
  347.         ; one was wanted.
  348.  
  349. @36dSetup ExecBase->LastAlert.
  350.  
  351. @36dCheck CPU type, and if 68881 present.
  352. @36dOr the result into the Attention flags.
  353.  
  354.         ; Initialize the exec lists.  This is driven from a data table which
  355.         ; contains the offsets from ExecBase where the various lists are,
  356.         ; and the list types.
  357.  
  358. @36dPoint to the table.
  359. @36dGet a table entry.
  360. @36dZero marks the end.
  361. @36dAdd to ExecBase to get absolute address.
  362. @36dClear the list by setting its head
  363. @36dpointer to point to itself,
  364. @36dclearing its "Tail" field,
  365. @36dand setting up the "TailPred" pointer.
  366. @36dGet the list type.
  367. @36dPut it into the list header.
  368. @36dLoop back to do next list.
  369. @a?fc02d2
  370.  
  371.         ; Table of list header offsets and types.
  372.  
  373. @8p@5w@11wMemList       (ExecBase + $142, type = NT_MEMORY)
  374. @8p@5w@11wResourceList  (ExecBase + $150, type = NT_RESOURCE)
  375. @8p@5w@11wDeviceList    (ExecBase + $15E, type = NT_DEVICE)
  376. @8p@5w@11wLibList       (ExecBase + $17A, type = NT_LIBRARY)
  377. @8p@5w@11wPortList      (ExecBase + $188, type = NT_MSGPORT)
  378. @8p@5w@11wTaskReady     (ExecBase + $196, type = NT_TASK)
  379. @8p@5w@11wTaskWait      (ExecBase + $1A4, type = NT_TASK)
  380. @8p@5w@11wIntrList      (ExecBase + $16C, type = NT_INTERRUPT)
  381. @8p@5w@11wSoftInts[0]   (ExecBase + $1B2, type = NT_SOFTINT)
  382. @8p@5w@11wSoftInts[1]   (ExecBase + $1C2, type = NT_SOFTINT)
  383. @8p@5w@11wSoftInts[2]   (ExecBase + $1D2, type = NT_SOFTINT)
  384. @8p@5w@11wSoftInts[3]   (ExecBase + $1E2, type = NT_SOFTINT)
  385. @8p@5w@11wSoftInts[4]   (ExecBase + $1F2, type = NT_SOFTINT)
  386. @8p@5w@11wSemaphoreList (ExecBase + $214, type = NT_SIGNALSEM)
  387.  
  388. @8p@16wEnd of table marker.
  389.  
  390.         ; Table used to initialize the exec's library node.
  391.  
  392. @8p@16bType     = NT_LIBRARY.
  393. @8p@16bPriority = 0.
  394. @8p@16lName     = pointer to "exec.library".
  395. @8p@16bFlags    = LIBF_CHANGED | LIBF_SUMUSED.
  396. @8p@16bPad.
  397. @8p@16wNegSize    (not set yet).
  398. @8p@16wPosSize.
  399. @8p@16wVersion.
  400. @8p@16wRevision.
  401. @8p@16lIdString = pointer to "exec ..."
  402. @8p@16lChecksum   (not set yet).
  403. @8p@16wOpenCnt  = 1.
  404.  
  405.         ; Names to use in the system free-memory lists.
  406.  
  407. @8p@,12s
  408. @8p@,12s
  409.  
  410.  
  411. @36dGet address of task crash routine.
  412. @36dInstall in default trap code.
  413. @36dInstall in default exception code.
  414. @a?fc034a
  415.  
  416. @40dSet the default task exit address.
  417. @40dPreallocate the lower 16 signals.
  418. @40dPreallocate TRAP #15 (for use
  419.                                         in ROM-Wack breakpoints).
  420.  
  421. @36dInitialize the exec.library node
  422. @36dup to and including the OpenCnt
  423. @36dfield, from the table above.
  424. @d
  425. @d
  426.  
  427. @36dMake the library jump vector, using the
  428. @36dtable at $FC1A40, and the MakeFunctions()
  429. @36droutine.  Setting A2 to the table address
  430. @36dsignals that the table is relative.
  431. @36dInstall library negative size.
  432.  
  433. @36dSee if we have expansion memory.
  434. @36dBranch past this if we don't.
  435.  
  436.         ; Add expansion memory at $C00000 to the free memory lists.
  437.  
  438. @36dFirst free location = ExecBase + $024C.
  439. @36dName = "Fast Memory".
  440. @36dPut in memory list at priority 0.
  441. @36dAttributes = MEMF_FAST | MEMF_PUBLIC.
  442. @36dGet end address of expansion memory.
  443. @36dSubtract address of first free location.
  444. @36dSubtract system stack size.
  445. @36dBuild free list and add it to system.
  446.  
  447. @36dFree chip memory starts at $0400.
  448. @36dSpace for stack already reserved.
  449. @d
  450.  
  451.         ; Add chip memory to free memory lists.  Enter here if there is
  452.         ; no expansion memory, and ExecBase therefore resides at the bottom
  453.         ; of chip memory.
  454.  
  455.         ; Note how chip memory is added to the system list at a lower
  456.         ; priority than expansion memory.  This causes it to be allocated
  457.         ; only when specifically requested or when expansion memory is full.
  458.  
  459. @36dFree chip memory is at ExecBase + $024C.
  460. @36dReserve 6K for system stack.
  461.  
  462.         ; Enter here if we do have expansion memory, with D0 and A0 set
  463.         ; up as above.
  464.  
  465. @36dAttributes = MEMF_CHIP | MEMF_PUBLIC.
  466. @d
  467. @36dName = "Chip Memory".
  468. @36dPriority = -10.
  469. @36dGet end address of free chip memory.
  470. @36dSubtract address of first free location.
  471. @36dBuild free list and add it to system.
  472.  
  473. @36dGet ExecBase.
  474. @36dAdd the exec to the system library list.
  475.  
  476.         ; Set the exception vector table up for actual system operation.
  477.         ; Up to this point, any interrupt or exception would have caused
  478.         ; the screen to turn yellow and the computer to reset.
  479.  
  480.         ; The format of the data table used here is explained in comments
  481.         ; at the front of the data table.
  482.  
  483. @36dPoint to data table.
  484. @36dSet up base address for the offsets.
  485. @36dPoint to exception vector #2.
  486. @36dEnter the loop at the bottom.
  487.  
  488. @36dConvert table entry to absolute address.
  489. @36dStore the handler address in the EVT.
  490. @36dGet the next data table entry.
  491. @36dLoop until end of table reached.
  492.  
  493. @36dSee if we are running on a 68010/020.
  494. @d
  495. @36dSkip the following if not.
  496.  
  497.         ; Special initialization for machines using a 68010/020.
  498.  
  499. @36dPoint at 68010/020 bus error handler.
  500. @d
  501. @36dFix the bus error vector.
  502. @36dFix the address error vector.
  503.  
  504. @36d    Use a different Supervisor() routine.
  505.  
  506.         ; Fix GetCC() for 68010/020 processors.
  507.  
  508.         ; We simply load the instruction sequence "MOVE.W CCR,D0 / RTS" into
  509.         ; the place where the library jump vector to GetCC() normally is.
  510.  
  511. @d
  512.  
  513.         ; Check if we have a 68881 numeric coprocessor, and if so, fix up
  514.         ; some more vectors.  This needs to be done since we also need to
  515.         ; save the 68881's context when we switch tasks.
  516.  
  517. @40dDo we have a 68881?  If so,
  518. @d
  519. @40dUse a different Switch() function.
  520. @40dUse a different Dispatch() funciton.
  521.  
  522.         ; Regular 68000's continue here.
  523.  
  524. @36dInitialize the exec interrupt handlers.
  525.  
  526. @36dPoint to the custom chips.
  527. @36dEnable all DMA.
  528. @36dEnable the interrupt system.
  529. @36dSet the interrupt disable level to -1.
  530.  
  531. @36dInitialize ROM-Wack.
  532.  
  533. @36dChecksum the static part of the ExecBase
  534. @36ddata structure.
  535. @36dThis is used after a reset to see if
  536. @36dthe data structure has been clobbered.
  537. @d
  538. @d
  539. @36dStore the checksum.
  540.  
  541.         ; Now we are going to manufacture the very first task.
  542.         ; We use AllocEntry() to obtain a block of memory.  This is then
  543.         ; used to hold the MemList from AllocEntry(), the task's stack,
  544.         ; and the task descriptor.
  545.  
  546. @36dPoint to the MemList.
  547. @36dAllocEntry()
  548. @36dGet the address of the MemList.
  549.  
  550.         ; It's assumed here that the allocated memory follows directly
  551.         ; after the MemList.  A safe assumption, since we still have
  552.         ; unfragmented memory.  We now create a task descriptor at the
  553.         ; top of the allocated memory.  The stack pointer for the task
  554.         ; is initialized below the task descriptor.
  555.  
  556. @36dPoint near the top of the memory block.
  557. @36dPoint to the future task descriptor.
  558. @d
  559. @36dStore stack lower bound.
  560. @36dStore stack upper bound.
  561. @36dSet the initial stack pointer image.
  562. @36dSet the stack pointer itself.
  563. @36dPriority = 0.
  564. @36dNode type = NT_TASK.
  565. @36dTask name = "exec.library".
  566.  
  567.         ; We initialize the task's memory list to empty, then enqueue
  568.         ; the MemList holding all this memory there.  This means that
  569.         ; when the task dies, the memory will automatically be deallocated.
  570.  
  571. @36dPoint to the task's memory list.
  572. @36dInitialize it to empty.
  573. @d
  574. @d
  575. @d
  576. @36dEnqueue the MemList from AllocEntry()
  577. @36don the task's memory list.
  578. @36dGet the task address back.
  579.  
  580.         ; Make this the current task, and make it ready to run.
  581.         ; initialPC and finalPC are both initialized as zero, but no
  582.         ; harm results, since the task can't start running yet.
  583.  
  584. @36dMake this the current task.
  585. @36dClear A2.
  586. @36dClear A3.
  587. @36dAddTask()
  588. @36dGet the pointer to the task again.
  589. @36dMake the task state TS_RUN.
  590. @36dUnlink it from the TaskReady queue.
  591.  
  592.         ; A historic moment:  We turn the supervisor mode flag off.
  593.         ; Starting right now, we are running as a task named "exec.library",
  594.         ; and the multitasking system is operational.
  595.  
  596. @a?fc04be
  597. FC04BE  and.w     #0,SR             Turn the supervisor bit off.
  598. @a=fc04c2
  599. @36dForbid()
  600. @36dPermit()
  601. @d
  602.  
  603.  
  604.        ; The MemList used to allocate memory for the initial task.
  605.  
  606. @7p@9l@9l@9l@8wA dummy list node.
  607.  
  608. @7p@35w1 block of memory desired.
  609. @7p@35lMEMF_PUBLIC | MEMF_CLEAR
  610. @7p@35l1124 bytes.
  611.  
  612.  
  613.        ; Table of areas to look for RomTags in.  I don't know why the
  614.        ; FC0000 - 1000000 area is covered twice.  The F00000 to F80000
  615.        ; area appears to be an alternate or additional place to put ROMs.
  616.  
  617. @7p@9l@l
  618. @7p@9l@l
  619. @7p@9l@l
  620.  
  621. @7p@35lEnd of list marker.
  622.  
  623.  
  624.         ; Scan for RomTags, process the KickMemPtr and KickTagPtr
  625.         ; variables, and build a table of all the resident modules found.
  626.         ; The address of the table of resident modules is stored in
  627.         ; the ExecBase data structure.
  628.  
  629. @36dPoint to table of ROM address spaces.
  630. @36dScan for RomTags, etc.
  631. @36dStore the result in ExecBase->ResModules.
  632.  
  633. @36dSet the power light to bright.
  634.  
  635.         ; Handle the "cool start" capture vector.  Note that if we decided
  636.         ; (much) earlier that ExecBase had been clobbered, it will have
  637.         ; been rebuilt from scratch, and the cool start capture vector
  638.         ; will be zero.  Thus, we don't have to verify it further.
  639.  
  640. @36dGet the "cool start" capture vector.
  641. @36dBranch past the following if zero.
  642. @d
  643. @36dCall the "cool start" capture code.
  644.  
  645.         ; Another historic moment.  We call InitCode() to initialize the
  646.         ; resident modules.  This is where all the other stuff in the ROMs,
  647.         ; stuff in RAM which survived the reboot, etc. comes online.  We
  648.         ; indicate that all those modules with the RTF_COLDSTART flag set
  649.         ; should be initialized now.
  650.  
  651. @36dRTF_COLDSTART flag must be set.
  652. @36dMinimum version is 0 (any will do).
  653. @36dInitCode().
  654.  
  655.         ; Yet another capture vector, this time the "WarmCapture" one.
  656.  
  657. @36dCheck the "WarmCapture" vector.
  658. @36dBranch past this if zero.
  659. @d
  660. @36dCall the warm start capture code.
  661.  
  662.         ; I assume that when the DOS came online, it took over.  This
  663.         ; task looks like it's heading into a dead end.
  664.  
  665.         ; Clear all the CPU registers except for ExecBase and the stack
  666.         ; pointer.
  667.  
  668. @38dPush 14 longwords of zero on
  669. @38dthe stack.
  670. @d
  671. @38dRead them off again into the registers.
  672.  
  673.         ; This is the end of the road.
  674.  
  675.                                     Do forever
  676. @38dDebug()
  677. @38dGet ExecBase.
  678. @36dEnd
  679.  
  680.  
  681.         ; Determine CPU type and whether FPP is present.
  682.         ; ----------------------------------------------
  683.  
  684.         ; We need to know whether a non-68000 CPU is present for two
  685.         ; reasons:  First, on the 68000, at least one instruction
  686.         ; (MOVE.W SR,<ea>) is available in user mode, whereas on the
  687.         ; newer CPU's, it is privileged.  Second, on the newer CPU's,
  688.         ; when an exception occurs, more information is saved on the
  689.         ; stack, and in the case of a bus error, the CPU's entire state
  690.         ; is dumped there so that virtual memory computers (big UNIX
  691.         ; boxes for example) can recover from page faults.
  692.  
  693.         ; Note that the 68020 can do everything the 68010 can, and thus,
  694.         ; if a 68020 is detected, both the AFB_68010 and the AFB_68020
  695.         ; flags will be set.
  696.  
  697.         ; We need to know whether there's an FPP present since, for task
  698.         ; switches, we want to save the FPP registers on the stack as
  699.         ; as the CPU registers, so each task can think it has the FPP
  700.         ; all to itself.
  701.  
  702. @d
  703.  
  704.         ; We are going to try 68010/020 and 68881 instructions.  These will
  705.         ; cause error exceptions if the respective parts aren't present, so
  706.         ; we set up to trap these.
  707.  
  708. @36dSave "Illegal Instruction" error vector.
  709. @36dSave "1111 Opcode" error vector.
  710. @36dPoint to temporary exception handler.
  711. @36dInstall this address in both vectors.
  712. @d
  713. @36dSave the stack pointer.
  714.  
  715.         ; Initialize the flags to zero (D0), and point to address zero (D1).
  716.         ; Then we try to set the 68010 Vector Base Register, which determines
  717.         ; where the exception vector table is.  In the 68000, this is hard
  718.         ; wired at zero.  If the 68010 is present, we set it to zero.
  719.  
  720. @d
  721. @d
  722. @a?fc0564
  723. FC0564  movec     D1,VBR            Set Vector Base Register to 0.
  724. @a=fc0568
  725.  
  726.         ; If we're still here, the CPU is at least a 68010.  We thus set
  727.         ; the AFB_68010 flag.  Then we try to access a 68020-specific
  728.         ; feature, namely, we try to enable its instruction cache.
  729.  
  730. @36dSet AFB_68010 flag.
  731. @d
  732. @a?fc056e
  733. FC056E  movec     D1,CACR           Try enabling the 68020 cache.
  734. @a=fc0572
  735.  
  736.         ; If we're still here, we have a 68020, and so we set the AFB_68020
  737.         ; flag.  Then we see if we also have a 68881 FPP, by trying to
  738.         ; access one of its registers.  Note that this will not cause an
  739.         ; exception if no FPP is present.
  740.  
  741. @36dSet AFB_68020 flag.
  742. @a?fc0576
  743. FC0576  fmove.l   FPCR,D1           Try reading a 68881 register.
  744. @a=fc057a
  745. @36dDid it work?
  746. @d
  747. @36dIf so, set the AFB_68881 flag.
  748.  
  749.         ; We continue here either from above, or, on plain Amigas, by
  750.         ; an error exception from one of the foreign instructions above.
  751.         ; D0 contains all the flags which have been set along the way.
  752.         ; We restore the two changed entries in the EVT and the stack
  753.         ; pointer, then exit.
  754.  
  755. @36dRestore the stack pointer.
  756. @36dRestore the exception vectors.
  757. @d
  758. @d
  759. @d
  760.  
  761.  
  762.         ; Chip Memory Checking Routine
  763.         ; ----------------------------
  764.  
  765.         ; This routine checks for the presence of memory.  It is used at
  766.         ; startup to determine how much chip memory is available.  Note
  767.         ; that it can't be used to check for memory at $C00000, and a
  768.         ; special routine is provided to do this further on.
  769.  
  770.         ; On entry, A0 is the lower bound of the area to check, and A1 is
  771.         ; the high bound.  Memory is checked in 4K blocks.
  772.  
  773. @d
  774. @40dWrite a zero to the first location.
  775. @40dSave the first location.
  776. @40dUse this as a signature value.
  777.  
  778.         ; Main loop:  We enter here to check each 4K block.
  779.  
  780. @40dIncrement current location by 4K.
  781. @40dSee if upper bound reached.
  782. @40dIf so, exit from the loop.
  783. @40dWrite the signature into memory.
  784.  
  785.         ; Longword 0 of the block being checked was initially cleared to
  786.         ; zero.  If it is now no longer zero, we have "wrapped around",
  787.         ; i.e. due to incomplete address decoding, we have written the
  788.         ; signature value at the beginning of the block.  When this
  789.         ; occurs, we have reached the end of memory, even though the
  790.         ; signature value would read back correctly.
  791.  
  792. @40dCheck location 0.
  793. @40dExit if signature appears there.
  794. @40dSee if signature can be read back.
  795. @40dIf successful, go check more memory.
  796.  
  797.         ; Done, return the end address of memory to the user.  Return
  798.         ; via indirect jump through A5 since we don't have a stack yet.
  799.  
  800. @d
  801. @d
  802.  
  803.  
  804.         ; Error System Reset Routine
  805.         ; --------------------------
  806.  
  807.         ; This is the routine which blinks the power light, then resets
  808.         ; the computer.  It is called from the startup code if a failure
  809.         ; of any sort is detected.  The colour of the screen indicates
  810.         ; the type of failure.
  811.  
  812.         ; This is the exception entry point.  All vectors in the
  813.         ; Exception Vector Table point here while the ROM kernel is
  814.         ; initializing itself.  A yellow screen means an unexpected
  815.         ; exception has occurred.
  816.  
  817. @40dColour number for yellow.
  818.  
  819.         ; This is the non-exception entry point.  From here on down it's
  820.         ; a general purpose routine which can be entered with a coulour
  821.         ; number in D0.
  822.  
  823. @40dPoint to the custom chips.
  824. @40dSet BPLCON0 for a blank screen.
  825. @40dSet bitplane 0 data to zeros.
  826. @40dSet background colour to yellow.
  827.  
  828. @40dFor D1 = 1 to 10 do
  829. @42dSet delay to 1 time unit.
  830. @42dMake power light dim.
  831. @42dDelay.
  832. @42dSet delay to 0.5 time unit.
  833. @42dMake power light bright.
  834. @42dDelay.
  835. @40dEndfor
  836.  
  837.         ; Note:  The "boot" and "ig" commands from ROM-Wack jump here.
  838.  
  839. @40dDelay some more.
  840. @d
  841. @d
  842.  
  843. @40dReset everything external to the CPU.
  844.  
  845.  
  846.         ; Get the initial PC from the ROM (now mapped at zero due to the
  847.         ; reset instruction) and start over.
  848.  
  849. @d
  850. @d
  851.  
  852.  
  853.         ; Memory Clear Subroutine
  854.         ; -----------------------
  855.  
  856.         ; This subroutine clears a block of memory.  The start address is
  857.         ; in A0, the end address is in D0.  Since we may not have a stack,
  858.         ; the return address is provided in A5.
  859.  
  860. @40dValue to store in memory.
  861. @40dCompute number of bytes to clear.
  862. @40dDivide by 4 (number of longwords).
  863. @40dPut the low-order 16 bits in D0,
  864. @40dand the high-order ones in D1, and
  865. @40dstart at the bottom (for dbra's).
  866. @40dClear a longword.
  867. @40dLoop until current 256K block done.
  868. @40dLoop until everything done.
  869. @40dReturn to caller.
  870.  
  871.  
  872.         ; $C00000 Expansion RAM Checker
  873.         ; -----------------------------
  874.  
  875.         ; The following routine checks for the presence of memory
  876.         ; in the $C00000 - $DC0000 area.  This is a nontrivial exercise,
  877.         ; since if there is no memory there, we see images of the custom
  878.         ; chip registers there instead, due to incomplete address decoding.
  879.         ;
  880.         ; This took a while to figure out, so I'm commenting it
  881.         ; very heavily for my own satisfaction.
  882.  
  883.         ; Register A4 holds the end address of the block where we know
  884.         ; RAM to reside.  At first, we initialize this to the start address.
  885.         ; Then, each time through the loop, we copy A4 to a temporary
  886.         ; register, which we increment by 256K.
  887.  
  888. @40dCopy start address into A4.
  889. @40dCopy A4 into temporary register.
  890. @40dAdd 256K to temporary register.
  891.  
  892.         ; Now we write to an address $0F66 bytes less than the temporary
  893.         ; register.  If there is RAM here, this will write into it near
  894.         ; the top of the 256K block.  If there isn't, this will write to
  895.         ; the INTENA register and disable all interrupts.
  896.  
  897. @40dWrite to RAM or INTENA.
  898.  
  899.         ; Now we read an address $0FE4 bytes below the temporary address.
  900.         ; If there is memory here, this will read it.  Otherwise, it will
  901.         ; read the INTENAR register.  If we find a non-zero value, it must
  902.         ; be memory, since all bits in INTENAR were reset above.  Otherwise,
  903.         ; it could be either (memory could happen to contain zero).
  904.  
  905. @40dRead RAM or INTENAR.
  906. @40dIf not zero, we've found memory.
  907.  
  908.         ; We got a zero.  Make sure this isn't INTENAR by causing bits
  909.         ; to be set in it.  We set all of them except for the master
  910.         ; interrupt enable.  Again, if there's RAM here, this won't do
  911.         ; anything to INTENAR, and we'll continue to see a zero.
  912.  
  913. @40dWrite to RAM or INTENA.
  914.  
  915.         ; Read the same location as before.  If this returns anything but
  916.         ; $3FFF, it's fine.  $3FFF means we're seeing INTENAR.  If it's
  917.         ; still zero, it's RAM.  Anything else would be a fatal error, but
  918.         ; that isn't checked for.
  919.  
  920. @40dRead RAM or INTENAR.
  921. @40dExit from loop if INTENAR seen.
  922.  
  923.         ; Now we bump up A4 by copying the temporary register back.  This
  924.         ; means we have found a valid 256K block.  We then go on looking
  925.         ; until we've reached the upper limit of the address space to check.
  926.  
  927. @40dUpdate A4 (means memory was found).
  928. @40dCompare to upper limit.
  929. @40dKeep looking if not reached.
  930.  
  931.         ; Continue here when we've reached the end of the space to check,
  932.         ; or finally seen an image of the INTENAR register.  We return the
  933.         ; end address of the detected RAM in A4, or zero A4 if no RAM
  934.         ; was found.
  935.  
  936. @40dDisable all interrupts.
  937. @40dWas A4 ever updated?
  938. @40dIf so, return it.
  939. @40dZero A4 (indicates no memory).
  940. @40dReturn to caller.
  941.  
  942. @8p@32wPadding
  943.  
  944. ---------------------------------------------------------------------------
  945.   AddDevice( device )
  946.              A1
  947. ---------------------------------------------------------------------------
  948.  
  949. @36dPoint to the system device list.
  950. @36dAdd the device to the list.
  951. @36dUpdate the device's vector checksum.
  952. @d
  953.  
  954.  
  955. ---------------------------------------------------------------------------
  956.   RemDevice( device )
  957.              A1
  958. ---------------------------------------------------------------------------
  959.  
  960.         ; NOTE: Some other part of the system, presumably DOS, will patch
  961.         ; itself in ahead of this.
  962.  
  963. @36dJust go to RemLibrary().
  964.  
  965.  
  966. ---------------------------------------------------------------------------
  967.   error = OpenDevice( devName, unitNumber, ioRequest, flags )
  968.   D0                  A0       D0          A1         D1
  969. ---------------------------------------------------------------------------
  970.  
  971.         ; NOTE: Some other part of the system, presumably DOS, will patch
  972.         ; itself in ahead of this, presumably so it can pull devices off
  973.         ; disk if they aren't already in the device list.
  974.  
  975. @d
  976. @36dPoint to the ioRequest.
  977. @36dClear the io_Error field in it.
  978. @d
  979. @d
  980. @36dPoint to the system device list.
  981. @36dForbid()
  982. @36dFindName()
  983. @36dGet the pointer to the device.
  984. @d
  985. @36dStore it in the ioRequest.
  986. @36dReturn -1 if device not found.
  987. @36dClear the io_Unit pointer.
  988. @d
  989. @36dSave ExecBase.
  990. @36dPoint A6 to the device's base address.
  991. @36dCall the device's Open() function.
  992. @36dRestore ExecBase.
  993. @36dGet the io_Error (from the Open() call).
  994. @36dExtend to a longword for return to
  995. @36dthe caller.
  996. @36dPermit()
  997. @d
  998. @d
  999.  
  1000.         ; Continue here if the device was not found.
  1001.  
  1002. @36dSet the return value to -1.
  1003. @36dSet the io_Error field to -1.
  1004. @d
  1005.  
  1006.  
  1007. ---------------------------------------------------------------------------
  1008.   CloseDevice( ioRequest )
  1009.                A1
  1010. ---------------------------------------------------------------------------
  1011.  
  1012.         ; NOTE: Some other part of the system, presumably DOS, will patch
  1013.         ; itself in ahead of this.
  1014.  
  1015. @36dForbid()
  1016. @36dSave ExecBase.
  1017. @36dGet the pointer to the device node.
  1018. @36dCall the device's Close() function.
  1019. @36dRestore ExecBase.
  1020. @36dPermit()
  1021. @d
  1022.  
  1023.  
  1024. ---------------------------------------------------------------------------
  1025.   SendIO( ioRequest )
  1026.           A1
  1027. ---------------------------------------------------------------------------
  1028.  
  1029.         ; The command is sent to device with the "quick I/O" bit not set.
  1030.         ; This means the device must always respond by sending the
  1031.         ; I/O request back as a reply message when done.
  1032.  
  1033. @36dClear the "quick I/O" bit.
  1034. @36dSave ExecBase.
  1035. @36dGet pointer to device node.
  1036. @36dCall the device's "BeginIO" entry point.
  1037. @36dRestore ExecBase.
  1038. @d
  1039.  
  1040.  
  1041. ---------------------------------------------------------------------------
  1042.   error = DoIO( ioRequest )
  1043.   D0            A1
  1044. ---------------------------------------------------------------------------
  1045.  
  1046.         ; The command is sent to the device with the "quick I/O" bit set.
  1047.         ; This allows the device to decide whether to process the request
  1048.         ; synchronously or asynchronously.
  1049.  
  1050. @36dSave ioRequest pointer for later.
  1051. @36dSet the "quick I/O" bit.
  1052. @36dSave ExecBase.
  1053. @36dGet pointer to device node.
  1054. @36dCall the device's "BeginIO" entry point.
  1055. @36dRestore ExecBase.
  1056. @36dGet ioRequest pointer back.
  1057.  
  1058.         ; Now fall through to WaitIO.
  1059.  
  1060.  
  1061. ---------------------------------------------------------------------------
  1062.   error = WaitIO( ioRequest )
  1063.   D0              A1
  1064. ---------------------------------------------------------------------------
  1065.  
  1066.         ; If the "quick I/O" bit is set, then the call to the device
  1067.         ; in BeginIO() finished the I/O operation synchronously, and
  1068.         ; we can return to the caller.  Otherwise, we must wait for
  1069.         ; the reply message from the device.
  1070.  
  1071. @36dCheck the "quick I/O" bit.
  1072. @36dIf still set, the I/O is complete.
  1073.  
  1074.         ; "quick I/O" bit was not (or no longer) set, so we need to
  1075.         ; wait for the reply message from the device.
  1076.  
  1077. @36dSave A2.
  1078. @36dSave pointer to the ioRequest.
  1079. @36dGet pointer to the reply port.
  1080. @36dGet the reply port's signal bit.
  1081. @d
  1082. @36dConvert to signal mask.
  1083.  
  1084. @36dDisable()
  1085. @d
  1086.  
  1087. @36dCheck if the ioRequest became NT_REPLYMSG
  1088. @d
  1089. @36dWait for the signal.
  1090. @36dGo back and check the ioRequest again.
  1091.  
  1092. @36dUnlink the ioRequest from the reply
  1093. @36dport's message queue.
  1094. @d
  1095. @d
  1096. @d
  1097.  
  1098. @36dEnable()
  1099. @d
  1100. @d
  1101.  
  1102. @36dRestore pointer to the ioRequest.
  1103. @36dRestore A2.
  1104. @36dGet the error field from the ioRequest.
  1105. @36dExtend to long word.
  1106. @d
  1107. @d
  1108.  
  1109.  
  1110. ---------------------------------------------------------------------------
  1111.   result = CheckIO( ioRequest )
  1112.   D0                A1
  1113. ---------------------------------------------------------------------------
  1114.  
  1115. @a?fc074e
  1116. @36dCheck the "quick I/O" bit.
  1117. @36dIf set, request is done, so...
  1118. @36dReturn address of ioRequest.
  1119. @d
  1120. @36dCheck if ioRequest type is NT_REPLYMSG
  1121. @36dIf so, it is finished.
  1122. @36dReturn zero.
  1123. @d
  1124. @36dReturn address of ioRequest.
  1125. @d
  1126.  
  1127.  
  1128. ---------------------------------------------------------------------------
  1129.   AbortIO( ioRequest )
  1130.            A1
  1131. ---------------------------------------------------------------------------
  1132.  
  1133. @36dSave ExecBase.
  1134. @36dGet pointer to the device node.
  1135. @36dCall the device's "AbortIO" entry point.
  1136. @36dRestore ExecBase.
  1137. @d
  1138.  
  1139.  
  1140.         ; Table used to set up the exception vector table.
  1141.  
  1142.         ; Each entry is a 16-bit offset from the table's base address
  1143.         ; to the address of the exception handler for that exception.
  1144.         ; The final longword of zeros marks the end of the table.
  1145.  
  1146.         ; The first entry means that the handler for exception number 2
  1147.         ; (bus error) is at $FC0778 + $64.  The next entry is for exception
  1148.         ; number 3, and so on through to the end of the TRAP instruction
  1149.         ; vectors.
  1150.  
  1151. @7p@9l@9l@9l@l
  1152. @7p@9l@9l@9l@l
  1153. @7p@9l@9l@9l@l
  1154. @7p@9l@9l@9l@l
  1155. @7p@9l@9l@9l@l
  1156. @7p@9l@9l@l
  1157.  
  1158. @7p@29wEnd of table marker.
  1159.  
  1160. @7p@29wPadding.
  1161.  
  1162.  
  1163.         ; Exception entry points.  The indicated entries in the Exception
  1164.         ; Vector Table are set to point here.
  1165.  
  1166.         ; The BSR instructions are used so that the stacked return address
  1167.         ; from the BSR can be used to find out which exception occurred.
  1168.  
  1169. @d
  1170. @d
  1171. @36dBus error.
  1172. @36dAddress error.
  1173. @36dIllegal instruction.
  1174. @36dDivide by zero.
  1175. @36dCHK instruction.
  1176. @36dTRAPV instruction.
  1177. @d
  1178. @36dTrace mode.
  1179. @36d"1010" opcode.
  1180. @36d"1111" opcode.
  1181. @36dReserved vector #12.
  1182. @36dReserved vector #13.
  1183. @36dReserved vector #14.
  1184. @36dReserved vector #15.
  1185. @36dReserved vectors #16-23, spurious int.
  1186. @36dTRAP #0
  1187. @36dTRAP #1
  1188. @36dTRAP #2
  1189. @36dTRAP #3
  1190. @36dTRAP #4
  1191. @36dTRAP #5
  1192. @36dTRAP #6
  1193. @36dTRAP #7
  1194. @36dTRAP #8
  1195. @36dTRAP #9
  1196. @36dTRAP #10
  1197. @36dTRAP #11
  1198. @36dTRAP #12
  1199. @36dTRAP #13
  1200. @36dTRAP #14
  1201. @36dTRAP #15
  1202.  
  1203.         ; Handler for reserved exceptions #16-23 and spurious interrupts.
  1204.         ; These are dead ends (click for Guru).
  1205.  
  1206. @a?fc081a
  1207. FC081A  or.w      #$0700,SR         Disable all maskable interrupts.
  1208. @a=fc081e
  1209. @36dAlert number (fatal).
  1210. @36dFreeze the task.
  1211.  
  1212.         ; Another exception handler.  This one is a dead end also.
  1213.  
  1214. @a?fc0828
  1215. FC0828  or.w      #$0700,SR         Disable all maskable interrupts.
  1216. @a=fc082c
  1217. @d
  1218. @36dMake alert number.
  1219. @36dFreeze the task.
  1220.  
  1221.         ; Handler for bus and address errors (long stack frame).
  1222.         ; These two can be caught by the task if set up to do so.
  1223.  
  1224. @36dUse the return address on the stack
  1225. @36dto compute the exception number.
  1226. @36dSee if error occurred in supervisor mode.
  1227. @36dIf not, go to task's trap routine.
  1228. @36dFreeze the task.
  1229.  
  1230.         ; Handler for miscellaneous other errors.
  1231.         ; These can be caught by the task.
  1232.  
  1233. @36dUse the return address on the stack
  1234. @36dto compute the exception number.
  1235. @36dSee if error occurred in supervisor mode.
  1236. @36dIf not, go to task's trap routine.
  1237. @36dGuru time if in supervisor mode.
  1238.  
  1239.         ; Handler for TRAP instructions.
  1240.  
  1241. @36dUse the return address on the stack
  1242. @36dto compute the exception number.
  1243. @36dSee if error occurred in supervisor mode.
  1244. @36dGuru time if in supervisor mode.
  1245. @36dElse go to task specific trap routine.
  1246.  
  1247.         ; Bus error handler for 68010/020 processors.  These processors
  1248.         ; produce a more detailed stack frame when they hit a bus error
  1249.         ; (for use in virtual memory systems).  The bus and address
  1250.         ; error exception vectors are set to point here at system startup
  1251.         ; if such a processor is being used.
  1252.  
  1253. @36dPush a zero from the stack.
  1254. @36dRead the exception number.
  1255. @36dConvert it to a format compatible
  1256. @36dwith the numbering scheme used
  1257. @36delsewhere.
  1258. @36dProcess the exception normally.
  1259.  
  1260.         ; We get here if various exceptions occurred in user mode.
  1261.         ; This looks up an exception handler address in the current task's
  1262.         ; descriptor, and jumps there.  This allows each task to specify
  1263.         ; what is to happen if it causes an exception or executes a
  1264.         ; TRAP instruction.
  1265.  
  1266.         ; The task can clean up the stack and continue running if it
  1267.         ; wants to.  All its registers are preserved.
  1268.  
  1269. @36dReserve 4 words on stack and save A0.
  1270. @36dGet ExecBase
  1271. @36dGet the current task pointer.
  1272. @36dGet current task's tc_TrapCode address
  1273.                                     and put it on the stack for the RTS.
  1274. @36dRestore A0.
  1275. @d
  1276.  
  1277.  
  1278. ---------------------------------------------------------------------------
  1279.   Supervisor( code_to_execute )
  1280.               A5
  1281. ---------------------------------------------------------------------------
  1282.  
  1283.         ; This routine is used to run things with the CPU in supervisor
  1284.         ; mode.  The address of the code to execute once we're in supervisor
  1285.         ; mode is passed in A5.
  1286.  
  1287.         ; First, we tamper with the status register (attempt to set the
  1288.         ; supervisor mode bit).  If successful, we are already in supervisor
  1289.         ; mode.  If not, there will be a privilege violation, handled by
  1290.         ; the exception handler below.
  1291.  
  1292. @a?fc08aa
  1293. FC08AA  or.w      #$2000,SR         Tamper with the status register.
  1294. @a=fc08ae
  1295.  
  1296.         ; Are we still here?  If so, we are already in supervisor mode.
  1297.         ; Fake an exception by pushing status register and PC on the stack.
  1298.  
  1299. @36dPush a fake program counter.
  1300. @36dPush the status register.
  1301. @36dGo execute the caller's code.
  1302. @d
  1303.  
  1304.         ; The following is 68010/020 version of the above.  It is used
  1305.         ; if the startup code has detected such a processor and pointed
  1306.         ; the Supervisor() vector here.
  1307.  
  1308. @a?fc08ba
  1309. FC08BA  or.w      #$2000,SR         Tamper with the status register.
  1310. @a=fc08be
  1311. @36dMake room on the stack.
  1312. @36dStore status register.
  1313. @36dStore fake program counter.
  1314. @36dStore 68010/020 stack frame type.
  1315. @36dGo execute the caller's code.
  1316.  
  1317.         ; Privilege violation exception handler.
  1318.  
  1319.         ; First, we find out where the CPU was when it got the privilege
  1320.         ; violation.
  1321.  
  1322. @36dWas it the 68000 Supervisor() function?
  1323. @d
  1324. @36dWas it the 68010/020 version?
  1325. @d
  1326. @36dYes, fix return address, and go
  1327. @36dexecute the caller's code.
  1328.  
  1329.         ; If we get here, it was a real privilege violation, i.e. not one
  1330.         ; of the intentionally caused ones above.
  1331.  
  1332. @a?fc08f0
  1333. FC08F0  or.w      #$0700,SR         Disable all maskable interrupts.
  1334. @a=fc08f4
  1335. @36dMake alert number.
  1336. @36dFreeze the current task or guru.
  1337.  
  1338.  
  1339. @8p@28wPadding.
  1340.  
  1341.  
  1342.  
  1343.         ; ROMTAG Scanner and "KickMemPtr/KickTagPtr" Processor
  1344.         ; ----------------------------------------------------
  1345.  
  1346.         ; The routines in this section do two things.  One, they scan a
  1347.         ; section of the CPU addressing space for resident modules, each
  1348.         ; flagged by a "RomTag".  For an example of what a RomTag looks
  1349.         ; like, check out the one at the very beginning of the exec.
  1350.  
  1351.         ; The start and end addresses of each piece of CPU address space
  1352.         ; to look for RomTags in are given in a table, to which A0 must
  1353.         ; point on entry.
  1354.  
  1355.         ; A temporary list is built, containing nodes which each point to
  1356.         ; a RomTag.  Each resident module has a name, and no two modules
  1357.         ; with the same name are allowed.  If there is a conflict, the
  1358.         ; one with the higher version number or priority wins and the
  1359.         ; other one is discarded.
  1360.  
  1361.         ; After the list of RomTags has been compiled, we process something
  1362.         ; called the KickMemPtr and the KickTagPtr, found in the ExecBase
  1363.         ; structure.  The former points to a chain of MemLists.  The latter
  1364.         ; points to an odd type of chain containing pointers to RomTags.
  1365.         ; If you really need to know the format of this chain, read the
  1366.         ; comments at the appropriate code.
  1367.  
  1368.         ; All the MemList structures, and tables of RomTag addresses, pointed
  1369.         ; to by these pointers, have a checksum, also stored in ExecBase.
  1370.         ; If the checksum we calculate doesn't match that checksum, we
  1371.         ; discard all the data (assume it has been damaged in a system crash
  1372.         ; before the reboot).
  1373.  
  1374.         ; If the checkum matches, then we try to allocate all the pieces
  1375.         ; of memory pointed to by the KickMemPtr MemLists.  If this is
  1376.         ; successful, we add all the KickTagPtr RomTags to the RomTag list.
  1377.         ; Presumably, the KickMemPtr list will indicate where RAM-resident
  1378.         ; modules are located, and if we were able to reclaim them before
  1379.         ; the memory got allocated for something else, we add them to the
  1380.         ; system again after a reboot.
  1381.  
  1382.         ; Finally, we process the RomTag list.  This takes the form of
  1383.         ; building a table of resident module addresses, terminated with
  1384.         ; a zero, in memory allocated for that purpose.  The RomTag list is
  1385.         ; deallocated.  Note that the table of module addresses has the
  1386.         ; same format as one of the entries in the KickTagPtr list.
  1387.  
  1388.         ; Each resident module can have a flag set in its RomTag which
  1389.         ; which causes it to be automatically initialized later.
  1390.  
  1391.  
  1392. @d
  1393.  
  1394.         ; First, create a temporary list structure to hold the found RomTags
  1395.         ; in.  The list header is put on the stack.
  1396.  
  1397. @36dReserve 14 bytes on the stack (enough
  1398. @36dfor a list header), and get the address.
  1399. @36dClear the list to empty.
  1400. @d
  1401. @d
  1402. @d
  1403.  
  1404.         ; Now process the table of areas to look for RomTags in.  Call the
  1405.         ; RomTag scanning routine with the data from each table entry to
  1406.         ; find all the RomTags in that section of address space.
  1407.  
  1408. @36dPoint to the start of the address table.
  1409. @36dSee if end of table reached.
  1410. @36dNegative value indicates end.
  1411. @36dGet the start address and the end address
  1412. @36dof an area to look for RomTags in.
  1413. @36dScan the  area for RomTags.
  1414. @36dLoop until end of list reached.
  1415.  
  1416.         ; Now process the "Kick" variables in ExecBase.  These apparently
  1417.         ; exist to allow a set of resident modules (such as a RRD) to
  1418.         ; survive a system reboot.  If the checksum of all the data tables
  1419.         ; is still valid, we claim the memory and add the RomTags to
  1420.         ; the list.
  1421.  
  1422. @36dSumKickData()
  1423. @36dVerify the checksum against the old one.
  1424. @36dSkip the following if not valid.
  1425. @36dTry to reallocate all the MemLists.
  1426. @36dDid we get all the memory back?
  1427. @36dIf not, don't bother with the KickTags.
  1428. @36dProcess the list of "KickTags".
  1429. @36dBuild a table of RomTag addresses.
  1430. @36dDeallocate the RomTag list header.
  1431. @d
  1432. @d
  1433.  
  1434.  
  1435.         ; This routine scans an area indicated by A4 (start address) and
  1436.         ; D4 (end address) for RomTag structures, and puts any found RomTags
  1437.         ; on the RomTag list.  If there is more than one version of any
  1438.         ; given RomTag, the newest one wins, the older ones are discarded.
  1439.  
  1440. @d
  1441. @36dLoad the RomTag matchword.
  1442. @36dGet the end address.
  1443. @36dSubtract the start address.
  1444. @36dIf less than zero, return.
  1445. @36dDivide the result by 2 (number of words).
  1446. @36dDecrement by 1 (for DBcc instruction).
  1447. @36dSplit into two halves (since DBcc can
  1448. @36donly use 16-bit counters).
  1449. @d
  1450. @36dLook for the RomTag matchword.
  1451. @d
  1452. @36dLoop until entire area scanned.
  1453. @36dExit if end reached.
  1454.  
  1455.         ; We've found a RomTag matchword.  A4 points to it.  Check if
  1456.         ; this is really a RomTag by verifying the pointer directly
  1457.         ; after the matchword.
  1458.  
  1459. @36dPoint to the matchword.
  1460. @36dSee the longword directly after the
  1461.                                     matchword points to it.
  1462. @36dNot a valid RomTag if not.
  1463.  
  1464.         ; We are pointing to a valid RomTag.  Add it to the RomTag list.
  1465.  
  1466. @36dAdd RomTag to list of found ones.
  1467.  
  1468.         ; Each RomTag has in it a pointer (RT_ENDSKIP) which points to
  1469.         ; the address where to start looking for the next RomTag, i.e.
  1470.         ; the end of whatever code/data is associated with it.
  1471.  
  1472. @36dSkip to the end of the module.
  1473. @36dStart looking for the next one.
  1474. @d
  1475. @d
  1476.  
  1477.  
  1478.         ; This subroutine adds a RomTag to the list of found RomTags.
  1479.         ; If the current RomTag has the same name as a RomTag already in
  1480.         ; the list, the older (or if same age, lower priority) version
  1481.         ; is discarded.  Memory is allocated to hold each node as needed.
  1482.  
  1483. @36dPoint to the temporary list on the stack.
  1484. @36dGet the name of this RomTag.
  1485. @36dFindName()
  1486. @36dDid we find a node with this name?
  1487. @36dIf not, go and add the tag to the list.
  1488. @36dPoint to the node we found.
  1489. @36dCompare the version numbers of the list
  1490. @36dnode and the newly found RomTag to find
  1491. @36dout which is more recent.
  1492. @36dDiscard current RomTag if older.
  1493. @36dUse current one if newer.
  1494. @36dVersion numbers match, so compare
  1495. @36dthe priority fields.
  1496. @36dDiscard current RomTag if lower priority.
  1497.  
  1498.         ; This RomTag supersedes a previous one, which is already in the
  1499.         ; list.  Therefore we discard the one in the list.
  1500.  
  1501. @36dPoint to the node in the list.
  1502. @36dUnlink it from the list.
  1503. @36dKeep a pointer to the node's memory.
  1504. @36dGo and make a new node out of it.
  1505.  
  1506.         ; We enter here if this RomTag doesn't supersede some other one.
  1507.         ; This means we have to allocate some memory for a list node to
  1508.         ; store information about it.
  1509.  
  1510. @36dNo particular memory requirements.
  1511. @36d14 bytes.
  1512. @36dGo and allocate the memory.
  1513. @36dDid we get the memory?
  1514. @36dIf not, skip the following.
  1515. @36dPoint to the memory.
  1516.  
  1517.         ; We have obtained 14 bytes of memory one way or another, and we
  1518.         ; now build a list node and add it to the list of found RomTags.
  1519.  
  1520. @36dCopy the RomTag's priority.
  1521. @36dCopy the RomTag's name.
  1522. @36dStore the RomTag's address.
  1523. @d
  1524. @36dAnd enqueue on the RomTag list.
  1525. @d
  1526.  
  1527.  
  1528.         ; RomTag list to resident module table converter.
  1529.  
  1530.         ; This routine scans the temporary RomTag list, and builds a table
  1531.         ; of resident module addresses from it.  The list itself is
  1532.         ; deallocated.
  1533.  
  1534. @36dStart with 1 longword needed.
  1535. @36dStart at the head node of the list.
  1536. @36dGet pointer to the current node.
  1537. @36dGet pointer to the next node.
  1538. @36dEnd of list reached if zero.
  1539. @36d4 longwords needed for this node.
  1540. @36dScan the rest of the list.
  1541. @36dMEMF_PUBLIC | MEMF_CLEAR.
  1542. @36dAllocate memory.
  1543. @36dGet pointer to allocated memory.
  1544. @36dSave a copy of it.
  1545. @36dStart at the head of the RomTag list.
  1546. @36dGet pointer to current node.
  1547. @36dGet pointer to next node.
  1548. @36dEnd of list reached if zero.
  1549. @36dStore pointer to this RomTag.
  1550. @36d14 bytes.
  1551. @36dFreeMem() the list node.
  1552. @36dGo process next list node.
  1553. @36dMark end of "KickTag" list.
  1554. @36dReturn its base address.
  1555. @d
  1556.  
  1557.  
  1558.         ; KickTagPtr processor.
  1559.  
  1560.         ; This routine steps through the table(s) of RomTag addresses
  1561.         ; pointed to by the KickTagPtr, and adds all the RomTags pointed
  1562.         ; to by these addresses to the list of found RomTags.
  1563.  
  1564. @d
  1565. @36dGet the KickTagPtr.
  1566. @36dJust exit if it is zero.
  1567. @36dPoint to the first tag.
  1568. @36dRead a longword from the current tag.
  1569. @36dExit if end of list reached.
  1570. @36dIf this is a link, handle it.
  1571. @36dData must be a pointer to a RomTag.
  1572. @36dAdd the RomTag to the list.
  1573. @36dContinue with current node.
  1574. @36dStrip high bit from pointer to next
  1575. @36dnode in the list of "KickTags".
  1576. @36dGo process the next node.
  1577. @d
  1578. @d
  1579.  
  1580.  
  1581. ---------------------------------------------------------------------------
  1582.   SumKickData()
  1583. ---------------------------------------------------------------------------
  1584.  
  1585.         ; This routine computes the KickCheckSum by checksumming all the
  1586.         ; tables associated with the KickMemPtr and KickTagPtr pointers.
  1587.         ; The result should is the KickCheckSum.
  1588.  
  1589. @a?fc0a3c
  1590. @d
  1591. @36dPoint to the KickMemPtr in ExecBase.
  1592. @36dGet the KickMemPtr and the KickTagPtr.
  1593. @36dClear both to zero in the ExecBase
  1594. @36dstructure.
  1595. @36dStart checksum at -1.
  1596. @36dStart at the old KickMemPtr.
  1597.  
  1598. @36dEnd of list reached?
  1599. @36dExit from loop if so.
  1600. @36dPoint to current MemList.
  1601. @36dGet pointer to next MemList.
  1602. @36dGet the number of entries in the MemList.
  1603. @36dDouble it and add 4 more longwords, to
  1604. @36dget the size (in longwords) of this list.
  1605. @36dChecksum the MemList.
  1606. @36dGo process next MemList, if any.
  1607.  
  1608. @36dGet the old KickTagPtr.
  1609. @36dSkip the following if none.
  1610. @36dPoint to the start of the list.
  1611. @36dStart checksumming the list.
  1612.  
  1613. @36dAdd a longword to the checksum.
  1614. @36dGet first data word at this node.
  1615. @36dExit if end of list reached.
  1616. @36dIf high bit clear, add the data to the
  1617.                                     checksum and go on to the next longword.
  1618. @36dClear the high bit.
  1619. @36dUse result as pointer to next node.
  1620. @36dContinue processing the list.
  1621. @36dPut KickMemPtr/KickTagPtr back.
  1622. @d
  1623. @d
  1624.  
  1625.         ; Subroutine to checksum all the entries in a MemList.
  1626.  
  1627. @d
  1628. @d
  1629. @d
  1630.  
  1631.  
  1632.         ; The KickMemPtr points to a list of MemLists, each pointing to
  1633.         ; some number of chunks of memory.  This routine steps through
  1634.         ; all the MemLists, allocating all those chunks.  If any can't
  1635.         ; be allocated (memory already grabbed by someone else), it returns
  1636.         ; zero.  If successful, it returns 1.
  1637.  
  1638.  
  1639. @36dStart where the KickMemPtr points.
  1640. @36dEnd of list reached?
  1641. @36dIf so, return 1 and exit.
  1642. @36dPoint to the current MemList.
  1643. @36dGet pointer to the next MemList.
  1644. @36dAdvance past the MemList header.
  1645. @36dGet number of entries in this MemList.
  1646. @36dFake "successful allocation" return code.
  1647. @36dEnter the loop.
  1648.  
  1649.         ; Allocate all the pieces of memory indicated by this MemList.
  1650.  
  1651. @36dGet the address of this entry.
  1652. @36dGet the size of this entry.
  1653. @36dAllocAbs()
  1654. @36dSuccessful?
  1655. @36dIf so and moreLamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!Lamer!!!
  1656.   D0                       A1
  1657. ---------------------------------------------------------------------------
  1658.  
  1659. @d
  1660. @36dGet pointer to the resident module table.
  1661. @d
  1662.  
  1663.         ; Outer loop:  Step through the table(s) of RomTags, looking
  1664.         ; for one whose name matches the wanted one.
  1665.  
  1666. @36dGet a RomTag address from the table.
  1667. @36dReturn zero if end of table reached.
  1668. @36dIf table entry is a link then
  1669. @38dclear its high bit.
  1670. @38duse it as a new table pointer.
  1671. @38dGo to the top of the loop.
  1672. @36dEndif
  1673. @36dGet pointer to desired name.
  1674. @36dPoint to RomTag's name field.
  1675.  
  1676.         ; Inner loop:  Compare the wanted name with that in the RomTag.
  1677.  
  1678. @36dCompare a character.
  1679. @36dBack to top of loop if not equal.
  1680. @36dDid we reach the terminating zeros?
  1681. @36dCompare more characters if not.
  1682.  
  1683.         ; Fall through with the module's address in D0.
  1684.  
  1685. @d
  1686. @d
  1687.  
  1688.  
  1689. ---------------------------------------------------------------------------
  1690.   InitCode( startClass, version )
  1691.             D0          D1
  1692. ---------------------------------------------------------------------------
  1693.  
  1694.         ; This function initializes modules from the resident module list.
  1695.  
  1696.         ; The resident module list is one or more tables of RomTag addresses.
  1697.         ; Such tables can be linked together by including the address of the
  1698.         ; next table, with the high bit set, as the last address in a table.
  1699.  
  1700.         ; We are given a set of required flags in D0, and a minimum
  1701.         ; version number in D1.  Modules which have flags not set whose bits
  1702.         ; appear in D0, or are of a lower version than D1, will not be
  1703.         ; initialized.
  1704.  
  1705. @d
  1706. @40dGet the ResModules pointer.
  1707. @40dGet forbidden flags.
  1708. @40dGet cutoff version number.
  1709. @40dRead a module address from the table.
  1710. @40dExit if end of table reached.
  1711. @40dIs the high bit set?  If so, it's
  1712. @40da pointer to another table, so strip
  1713. @40dthe high bit off, point to the next
  1714. @40dtable, and process it.
  1715.  
  1716. @40dCheck the module's version number
  1717. @40dagainst the cutoff.
  1718. @40dIgnore module if too low.
  1719. @40dGet the module's flags.
  1720. @40dCheck against mask.
  1721. @40dIgnore it if required ones not set.
  1722. @d
  1723. @40dInitResident()
  1724. @40dProcess next resident module.
  1725. @d
  1726. @d
  1727.  
  1728.  
  1729. ---------------------------------------------------------------------------
  1730.   InitResident( resident, segList )
  1731.                 A1        D1
  1732. ---------------------------------------------------------------------------
  1733.  
  1734.         ; This initializes a resident module.  The pointer to the module
  1735.         ; is in register A1.  If the RT_FLAGS byte at offset 10 from
  1736.         ; the module pointer has the RTF_AUTOINIT flag set, we let the
  1737.         ; module initialize itself by calling its initialization code.
  1738.  
  1739.         ; Otherwise we assume it's a library type of thing, and call
  1740.         ; MakeLibrary with a set of parameters taken from the module.
  1741.         ; If the MakeLibrary succeeds, we add the module to the appropriate
  1742.         ; system list.
  1743.  
  1744. @40dCheck the RTF_AUTOINIT flag.
  1745. @d
  1746. @40dGet the RT_INIT address.
  1747. @d
  1748. @40dGet the segList pointer.
  1749. @40dCall the module's init code.
  1750. @d
  1751.  
  1752.         ; The RTF_AUTOINIT flag was not set, so we MakeLibrary() the
  1753.         ; module instead.  Note that the address at RT_INIT points to
  1754.         ; a data structure containing parameters for MakeLibrary().
  1755.  
  1756. @d
  1757. @40dGet the initialization address.
  1758. @40dGet parameters for MakeLibrary.
  1759. @40dMakeLibrary()
  1760. @d
  1761. @40dStore the library pointer.
  1762. @40dIf zero, just return it and exit.
  1763.  
  1764.         ; The library has been created successfully.
  1765.  
  1766. @40dGet the library pointer.
  1767. @40dGet the module's node type.
  1768. @40dIf the node type is NT_DEVICE then
  1769. @d
  1770. @42dAddDevice().
  1771. @d
  1772. @40dElse if it is NT_LIBRARY then
  1773. @d
  1774. @42dAddLibrary().
  1775. @d
  1776. @40dElse if it is NT_RESOURCE then
  1777. @d
  1778. @42dAddResource().
  1779. @40dEndif.
  1780. @d
  1781.  
  1782.  
  1783.         ; InitStruct entry point to copy one byte several times (-186).
  1784.  
  1785. @40dGet the byte initially.
  1786. @40dCopy it the required number of times.
  1787. @d
  1788. @40dBack to main loop.
  1789.  
  1790.         ; Entry ponint for invalid InitStruct commands (-176).  Guru time.
  1791.  
  1792. @40dSave registers.
  1793. @40dAlert number (fatal).
  1794. @40dGet ExecBase
  1795. @40dPut up the Alert.
  1796. @40dThis never gets executed.
  1797.  
  1798.         ; InitStruct entry point to copy one longword several times (-154).
  1799.  
  1800. @40dRound A1 up to next even address.
  1801. @d
  1802. @d
  1803. @d
  1804. @40dGet the longword initially.
  1805. @40dCopy it the required number of times.
  1806. @d
  1807. @40dBack to main loop.
  1808.  
  1809.         ; InitStruct entry point to copy one word several times (-134).
  1810.  
  1811. @40dRound A1 up to next even address.
  1812. @d
  1813. @d
  1814. @d
  1815. @40dGet the word initially.
  1816. @40dCopy it the required number of times.
  1817. @d
  1818. @40dBack to main loop.
  1819.  
  1820.  
  1821. ---------------------------------------------------------------------------
  1822.   InitStruct( initTable, memory, size )
  1823.               A1         A2      D0
  1824. ---------------------------------------------------------------------------
  1825.  
  1826. @36dGet structure base address.
  1827. @36dDivide size by 2 (get size in words)
  1828. @d
  1829. @36dLoop: Clear the structure's memory.
  1830. @d
  1831.  
  1832. @36dGet structure base address again.
  1833. @d
  1834. @36dRead a byte from the initTable.
  1835. @36dIf it is zero, we're done.
  1836. @36dCheck and reset offset flag.
  1837. @36dBranch if it was not set.
  1838.  
  1839.         ; Process an offset command (10ssnnnn or 11ssnnnn).
  1840.  
  1841. @36dCheck and reset byte/rptr flag.
  1842. @36dBranch if it was not set.
  1843. @36dBack up over command byte.
  1844. @36dGet cmd byte + 24 bit data.
  1845. @36dMask out the command byte.
  1846. @d
  1847.  
  1848.         ; Process an offset/byte command (10ssnnnn).
  1849.  
  1850. @d
  1851. @36dGet next byte from table into D1.
  1852.  
  1853.         ; Continue here for both offset commands.  In each case, A1 now
  1854.         ; points at the next even address in the initTable, and D1 contains
  1855.         ; the offset we have just fetched from it, as a longword.
  1856.  
  1857. @36dGet structure base address.
  1858. @36dAdd offset just computed.
  1859.  
  1860.         ; Continue here for all commands,  A0 now holds the absolute
  1861.         ; address where the next operand should go, D0 contains what is
  1862.         ; left of the command byte, and A1 points at the current even
  1863.         ; address in the table.
  1864.  
  1865. @38dGet the command byte
  1866. @38dShift and mask it so it becomes
  1867. @38d2 * (sdd)
  1868. @38dGet the jump offset from the table.
  1869. @38dMask all but (nnnn) out of the command.
  1870. @38dJump to the right routine.
  1871.  
  1872.         ; Entry point for copying multiple bytes (-42).
  1873.  
  1874. @36dCopy one byte.
  1875. @36dLoop until required number done.
  1876.  
  1877. @36dRound A1 up to next even address.
  1878. @d
  1879. @d
  1880. @d
  1881. @36dGo back to main loop.
  1882.  
  1883.         ; Entry point for copying multiple longwords (-24).
  1884.  
  1885.         ; Simply falls through to word copy routine, set up to copy twice as
  1886.         ; many words.  An extra 1 must be added to compensate for the effects
  1887.         ; of the "dbra" instruction.
  1888.  
  1889. @36dD0 = (2 * D0) + 1.
  1890. @d
  1891.  
  1892.         ; Entry point for copying multiple words (-20).
  1893.  
  1894. @36dRound A1 up to next even address.
  1895. @d
  1896. @d
  1897. @d
  1898. @36dMove the data.
  1899. @d
  1900. @36dGo back to top of main loop.
  1901.  
  1902. @d
  1903.  
  1904.         ; Dispatch table for InitStruct.
  1905.  
  1906. @8p@10w-24               (sdd = 000) longword, count.
  1907. @8p@10w-20               (sdd = 001) word, count.
  1908. @8p@10w-42               (sdd = 010) byte, count.
  1909. @8p@10w-176              (sdd = 011) Invalid.
  1910. @8p@10w-154              (sdd = 100) longword, repeat.
  1911. @8p@10w-134              (sdd = 101) word, repeat.
  1912. @8p@10w-186              (sdd = 110) byte, repeat.
  1913. @8p@10w-176              (sdd = 111) Invalid.
  1914.  
  1915. @8p@28w                  Padding.
  1916.  
  1917.  
  1918.         ; The following is used to bail out of an interrupt which we should
  1919.         ; have ignored.
  1920.  
  1921. @d
  1922. @d
  1923.  
  1924.         ; Level 1 Autovector interrupt entry point.
  1925.         ; -----------------------------------------
  1926.  
  1927. @d
  1928.  
  1929. @36dPoint to custom chip register area.
  1930. @36dGet ExecBase.
  1931. @36dGet interrupt enable register.
  1932. @36dCheck master interrupt enable.
  1933. @36dBail out if no interrupts enabled.
  1934. @36dCheck for pending & enabled interrupts.
  1935.  
  1936. @36dSerial port transmit interrupt?
  1937. @d
  1938. @36dGet IntVects[0] handler data.
  1939. @36dPush address of ExitIntr()
  1940. @d
  1941.  
  1942. @36dDisk block finished interrupt?
  1943. @d
  1944. @36dGet IntVects[1] handler data.
  1945. @36dPush address of ExitIntr()
  1946. @d
  1947.  
  1948. @36dSoftware generated interrupt?
  1949. @d
  1950. @36dGet IntVects[2] handler data.
  1951. @36dPush address of ExitIntr()
  1952. @d
  1953.  
  1954. @36dBail out if nothing found.
  1955.  
  1956.         ; Level 2 Autovector interrupt entry point.
  1957.         ; -----------------------------------------
  1958.  
  1959. @d
  1960.  
  1961. @36dSee level 1 for comments.
  1962. @d
  1963. @d
  1964. @d
  1965. @d
  1966. @d
  1967.  
  1968. @36dI/O port or timer interrupt?
  1969. @d
  1970. @36dGet IntVects[3] handler data.
  1971. @36dPush address of ExitIntr()
  1972. @d
  1973.  
  1974. @36dBail out if nothing found.
  1975.  
  1976.         ; Level 3 Autovector interrupt entry point.
  1977.         ; -----------------------------------------
  1978.  
  1979. @a?fc0cd8
  1980. @d
  1981.  
  1982. @36dSee level 1 for comments.
  1983. @d
  1984. @d
  1985. @d
  1986. @d
  1987. @d
  1988.  
  1989. @36dBlitter finished?
  1990. @d
  1991. @36dGet IntVects[6] handler data.
  1992. @36dPush address of ExitIntr()
  1993. @d
  1994.  
  1995. @36dStart of vertical blank?
  1996. @d
  1997. @36dGet IntVects[5] handler data.
  1998. @36dPush address of ExitIntr()
  1999. @d
  2000.  
  2001. @36dCopper interrupt?
  2002. @d
  2003. @36dGet IntVects[4] handler data.
  2004. @36dPush address of ExitIntr()
  2005. @d
  2006.  
  2007. @36dBail out if nothing found.
  2008.  
  2009.         ; Level 4 Autovector interrupt entry point.
  2010.         ; -----------------------------------------
  2011.  
  2012. @d
  2013.  
  2014. @36dSee level 1 for comments.
  2015. @d
  2016. @d
  2017. @d
  2018. @d
  2019. @d
  2020.  
  2021. @36dAudio channel 1?
  2022. @d
  2023. @36dGet IntVects[8] handler data.
  2024. @36dUse special ExitIntr() below.
  2025. @d
  2026. @a?fc0d62
  2027.  
  2028. @36dAudio channel 3?
  2029. @d
  2030. @36dGet IntVects[10] handler data.
  2031. @36dUse special ExitIntr() below.
  2032. @d
  2033.  
  2034. @36dAudio channel 0?
  2035. @d
  2036. @36dGet IntVects[7] handler data.
  2037. @36dUse special ExitIntr() below.
  2038. @d
  2039.  
  2040. @36dAudio channel 2?
  2041. @d
  2042. @36dGet IntVects[9] handler data.
  2043. @36dUse special ExitIntr() below.
  2044. @d
  2045.  
  2046. @36dBail out if nothing found.
  2047.  
  2048.         ; This routine allows a single invocation of the level 4 interrupt
  2049.         ; handler to service all level 4 interrupts which are pending or
  2050.         ; become pending while one is serviced.
  2051.  
  2052. @36dPoint at custom chip register area.
  2053. @36dGet ExecBase.
  2054. @36dMask for all level 4 interrupt bits.
  2055. @d
  2056. @36dFind enabled and pending level 4 ints.
  2057. @36dIf any still pending, go service them.
  2058.  
  2059. @36dOtherwise, do ExitIntr()
  2060.  
  2061.         ; Level 5 Autovector interrupt entry point.
  2062.         ; -----------------------------------------
  2063.  
  2064. @d
  2065.  
  2066. @36dSee level 1 for comments.
  2067. @d
  2068. @d
  2069. @d
  2070. @d
  2071. @d
  2072.  
  2073. @36dDisk sync interrupt?
  2074. @d
  2075. @36dGet IntVects[12] handler data.
  2076. @36dPush address of ExitIntr()
  2077. @d
  2078.  
  2079. @36dSerial port receive interrupt?
  2080. @d
  2081. @36dGet IntVects[11] handler data.
  2082. @36dPush address of ExitIntr()
  2083. @d
  2084.  
  2085. @36dBail out if nothing found.
  2086.  
  2087.         ; Level 6 Autovector interrupt entry point.
  2088.         ; -----------------------------------------
  2089.  
  2090. @d
  2091.  
  2092. @36dSee level 1 for comments.
  2093. @d
  2094. @d
  2095. @d
  2096. @d
  2097. @d
  2098.  
  2099. @36dSpecial copper interrupt?
  2100. @d
  2101. @36dGet IntVects[14] handler data.
  2102. @36dPush address of ExitIntr()
  2103. @d
  2104.  
  2105. @36dExternal level 6 interrupt?
  2106. @d
  2107. @36dGet IntVects[13] handler data.
  2108. @36dPush address of ExitIntr()
  2109. @d
  2110.  
  2111. @36dBail out if nothing found.
  2112.  
  2113.         ; Level 7 Autovector interrupt entry point.
  2114.         ; -----------------------------------------
  2115.  
  2116. @d
  2117. @d
  2118. @36d  Get IntVects[15] handler data.
  2119. @d
  2120. @d
  2121. @d
  2122.  
  2123.  
  2124. ---------------------------------------------------------------------------
  2125.   ExitIntr()
  2126. ---------------------------------------------------------------------------
  2127.  
  2128.         ; This routine is called after an interrupt handler has finished.
  2129.         ; It checks if a task switch is necessary.  If not, it returns
  2130.         ; from the interrupt.  Otherwise, it drops into the scheduler.
  2131.  
  2132.         ; The initial check for supervisor mode is very important.  If
  2133.         ; the CPU was in supervisor mode, then there either was no task
  2134.         ; running (CPU stopped), or the task had already been interrupted
  2135.         ; by a lower priority interrupt.  In either case, we may not do
  2136.         ; a task switch.  In the former case, it will be done after the
  2137.         ; CPU comes out of the STOP instruction in the dispatcher, and
  2138.         ; in the latter, it will be taken care of by the lowest priority
  2139.         ; interrupt handler (which interrupted the CPU while it was not
  2140.         ; in supervisor mode).
  2141.  
  2142. @38dCheck if CPU was in supervisor mode.
  2143. @38dIf so, just return from interrupt.
  2144. @38dGet ExecBase.
  2145. @38dSee if task switching is disabled.
  2146. @38dIf so, just return from interrupt.
  2147.  
  2148. @38dCheck the scheduling attention flag.
  2149. @38dReturn from interrupt if not set.
  2150.  
  2151. @a?fc0e7a
  2152. FC0E7A  move.w    #$2000,SR           Enable all interrupts.
  2153. @a=fc0e7e
  2154. @d
  2155.  
  2156. @d
  2157. @d
  2158.  
  2159.  
  2160. ---------------------------------------------------------------------------
  2161.   Schedule()
  2162. ---------------------------------------------------------------------------
  2163.  
  2164.         ; This is the scheduler.  It is called with the current task's
  2165.         ; registers saved on the system stack, as put there by the interrupt
  2166.         ; entry point, and PC/SR as put there by the interrupt itself.
  2167.         ;
  2168.         ; The scheduler checks if the task should be suspended and another
  2169.         ; task run in its place.  The following decision is made:
  2170.         ;
  2171.         ; IF the current task has an exception pending THEN
  2172.         ;    reschedule the current task, so that it will be redispatched,
  2173.         ;    so that the dispatcher can process the exception.
  2174.         ; ELSEIF the TaskReady queue is empty THEN
  2175.         ;    the current task is the only runnable task in the system, so
  2176.         ;    let it continue running.
  2177.         ; ELSEIF the TaskReady queue contains a higher priority task THEN
  2178.         ;    do a task switch.
  2179.         ; ELSEIF the current task's time slice has expired THEN
  2180.         ;    reschedule the current task (it may be redispatched right away,
  2181.         ;    with a new time slice).
  2182.         ; ELSE
  2183.         ;    let the current task keep running.
  2184.         ; ENDIF
  2185.  
  2186. @d
  2187. @a?fc0e8a
  2188. FC0E8A  move.w    #$2700,SR           Mask all maskable interrupts.
  2189. @a=fc0e8e
  2190. @38dReset the scheduling attention flag.
  2191. @38dGet the current task pointer.
  2192. @38dCheck the task's TB_EXCEPT flag.
  2193. @d
  2194. @38dPoint to the TaskReady queue.
  2195. @38dCheck if the queue is empty.
  2196. @38dIf so, return from interrupt.
  2197. @38dGet the queue's head node.
  2198. @38dGet the head node's priority.
  2199. @38dCompare to the current task's priority.
  2200. @38dSwitch tasks if higher priority.
  2201. @38dCheck the time slice expired flag.
  2202. @38dIf not expired, return from interrupt.
  2203.  
  2204.         ; If we get this far, it is necessary to put the current task on
  2205.         ; the TaskReady queue and then run the one at the head of the queue.
  2206.         ; This may be the same one if a TB_EXCEPT is being processed.
  2207.  
  2208. @38dPoint to the TaskReady queue.
  2209. @38dEnqueue the current task.
  2210. @38dMake the task's state TS_READY.
  2211. @a?fc0ecc
  2212. FC0ECC  move.w    #$2000,SR           Enable all interrupts.
  2213. @a=fc0ed0
  2214.  
  2215.         ; Get the current task's saved registers back.  They may have been
  2216.         ; put on the stack when an interrupt occurred, or at the start of
  2217.         ; this routine.
  2218.  
  2219. @d
  2220.  
  2221. @38dInsert some space in the system stack.
  2222. @38dPut in the address of Switch().
  2223. @38dGet A6 from the stack.
  2224. @38dGo to Switch().
  2225.  
  2226.  
  2227. ---------------------------------------------------------------------------
  2228.   Switch()
  2229.  
  2230.   [Version for machines without a numeric coprocessor]
  2231. ---------------------------------------------------------------------------
  2232.  
  2233.         ; The ExecBase "Switch()" vector points here if no FPP is installed.
  2234.  
  2235.         ; This routine does a task switch.  It stores the context of
  2236.         ; the currently running task, then drops into the dispatcher.
  2237.  
  2238.         ; The routine stores the current CPU context on the user
  2239.         ; stack.  The status register and program counter are popped from
  2240.         ; the supervisor stack.  The current interrupt disable nesting
  2241.         ; level and the user stack pointer are then saved in this task's
  2242.         ; task descriptor.
  2243.  
  2244.         ; If the TB_SWITCH bit is set in the task descriptor, the task's
  2245.         ; TC_SWITCH function is called.
  2246.  
  2247. @a?fc0ee0
  2248. FC0EE0  move      #$2000,SR             Enable all interrupts.
  2249. @a=fc0ee4
  2250. @40dStack A5 on the supervisor stack.
  2251. @40dGet the user stack pointer.
  2252. @40dStack all registers on user stack.
  2253.  
  2254. @40dGet ExecBase
  2255.  
  2256. @40dGet current interrupt disable level.
  2257. @40dSet interrupt disable level to -1.
  2258. @40dEnable interrupts.
  2259.  
  2260. @40dFix A5 in the saved register set.
  2261. @40dSave the status register.
  2262. @40dSave the program counter.
  2263.  
  2264. @40dAddress of context-restore routine
  2265.                                         for machines without an FPP.
  2266.  
  2267. @40dFind the current task descriptor.
  2268. @40dStore interrupt disable level.
  2269. @40dStore user stack pointer.
  2270. @40dCheck the TB_SWITCH bit
  2271. @d
  2272. @40dIf TB_SWITCH bit was set, then
  2273. @40dcall this task's TC_SWITCH function.
  2274. @d
  2275.  
  2276.  
  2277. ---------------------------------------------------------------------------
  2278.   Dispatch()
  2279.  
  2280.   [Version for machines without a numeric coprocessor]
  2281. ---------------------------------------------------------------------------
  2282.  
  2283.         ; This routine dispatches the next runnable task, if there is one.
  2284.  
  2285.         ; If the TaskReady queue is empty, the routine waits, stopping
  2286.         ; the processor and checking the queue again each time it resumes
  2287.         ; running (after an interrupt).
  2288.  
  2289.         ; When a runnable task is found, it is dispatched.  Its context
  2290.         ; and interrupt disable level are restored, and the TB_LAUNCH
  2291.         ; and TB_EXCEPT flags are checked.  If either is set, they are
  2292.         ; handled.
  2293.  
  2294. @40dAddress of context-restore routine
  2295.                                         for machines without an FPP.
  2296.  
  2297. @40dInitialize interrupt disable level
  2298. @40dat -1, and enable interrupts.
  2299.  
  2300. @40dPoint at the TaskReady queue.
  2301. @a?fc0f40
  2302. FC0F40  move      #$2700,SR             Mask all maskable interrupts.
  2303. @a=fc0f44
  2304. @40dCheck for a task descriptor at
  2305. @40dthe front of the queue.
  2306. @d
  2307.  
  2308.         ; TaskReady queue is empty.  Halt the processor until the next
  2309.         ; interrupt, then check for runnable tasks again.
  2310.  
  2311. @40dIncrement the idle counter.
  2312. @40dSet the rescheduling attention flag.
  2313. @a?fc0f54
  2314. FC0F54  stop      #$2000                Enable all interrupts and stop.
  2315. @a=fc0f56
  2316. @d
  2317. @40dGo back and check for runnable tasks.
  2318.  
  2319.         ; We have a runnable task.
  2320.  
  2321. @40dUnlink the task descriptor from
  2322. @40dthe TaskReady queue.
  2323. @d
  2324. @40dIncrement the dispatch counter.
  2325.  
  2326. @40dSet the current task pointer.
  2327.  
  2328. @40dInitialize the time-slice counter.
  2329.  
  2330. @40dReset the time slice expired flag.
  2331. @40dSet the task's state to TS_RUN.
  2332.  
  2333. @40dRestore the interrupt disable level.
  2334. @d
  2335. @40dDisable interrupts if interrupt
  2336. @40ddisable level >= 0.
  2337.  
  2338. @a?fc0f90
  2339. FC0F90  move      #$2000,SR             Enable all interrupts.
  2340. @a=fc0f94
  2341. @40dGet the task's flags.
  2342. @40dCheck for TB_EXCEPT or TB_LAUNCH.
  2343. @d
  2344. @40dProcess the flags if either was set.
  2345.  
  2346. @40dGet the user stack pointer.
  2347.  
  2348. @40dRestore the CPU context.
  2349.  
  2350.  
  2351.         ; Context Restore routine (non-FPP version)
  2352.         ; -----------------------------------------
  2353.  
  2354.         ; Pop the task's CPU context off the user stack, and start it
  2355.         ; running.  The program counter and status register are set by
  2356.         ; storing them on the supervisor stack for the "RTE" instruction.
  2357.  
  2358. @40dGet the user stack pointer.
  2359. @40dSet it.
  2360. @40dGet the program counter.
  2361. @40dGet the status register.
  2362. @40dRestore all the other registers.
  2363. @40dAnd start running the task.
  2364.  
  2365.         ; Subroutine to handle TB_LAUNCH and TB_EXCEPT.
  2366.  
  2367. @40dCheck the TB_LAUNCH bit.
  2368. @d
  2369. @40dIf it was set, call the task's
  2370. @40dTC_LAUNCH routine.
  2371. @d
  2372. @40dRestore D0.
  2373. @40dCheck the TB_EXCEPT bit.
  2374. @d
  2375. @40dReturn if it was clear.
  2376.  
  2377.  
  2378. ---------------------------------------------------------------------------
  2379.   Exception()
  2380. ---------------------------------------------------------------------------
  2381.  
  2382.         ; This routine handles task-level exception processing.
  2383.  
  2384.         ; It checks whether any signals have occurred which should cause
  2385.         ; a software exception.  If so, it calls the task's exception
  2386.         ; processing routine.  After this returns, it restores everything
  2387.         ; so that the task itself can be dispatched.
  2388.  
  2389. @40dReset the TB_EXCEPT bit.
  2390.  
  2391. @40dDisable()
  2392. @d
  2393.  
  2394. @40dGet received signals.
  2395. @40dCompare with exception signals.
  2396. @40dIf any exception signals were set,
  2397. @40dreset them in both places.
  2398.  
  2399. @40dEnable()
  2400. @d
  2401. @d
  2402.  
  2403. @40dGet the user stack pointer.
  2404.  
  2405.         ; Store tc_Flags, tc_State, tc_IDNestCnt, tc_TDNestCnt on user stack.
  2406.  
  2407. @d
  2408.  
  2409.         ; If interrupts have been disabled exactly once, then enable them.
  2410.  
  2411. @d
  2412. @d
  2413. @d
  2414. @d
  2415. @d
  2416.  
  2417.         ; Put the address of an exception post-processing routine on the
  2418.         ; user stack.  This gets executed when the exception routine
  2419.         ; does an RTS.
  2420.  
  2421. @40dPut return address on user stack.
  2422. @40dSet user stack pointer.
  2423. @40dSee if this is a plain 68000.
  2424. @d
  2425. @40dMake 68010/020 extended stack frame.
  2426.  
  2427. @40dPut exception code and a fake status
  2428. @40dword on the supervisor stack.
  2429. @40dPoint to the exception handler's
  2430.                                         data segment.
  2431. @d
  2432.  
  2433.         ; Continue here after the user's exception handling routine has run.
  2434.  
  2435. @40dGet ExecBase.
  2436. @40dWhere to go in supervisor mode.
  2437. @40dGo to supervisor mode.
  2438.  
  2439. @40dAddress of context restore routine.
  2440.  
  2441. @40dIs this a 68010/020?
  2442. @d
  2443. @40dIf so, handle extended stack frame.
  2444.  
  2445. @40dDo we have a 688881?
  2446. @d
  2447. @40dIf so, use the other context-restore.
  2448.  
  2449. @40dPop PC and SR from stack.
  2450. @40dGet current task descriptor.
  2451. @40dSet the exception signals up again.
  2452. @40dGet the user stack pointer.
  2453.  
  2454.         ; Restore tc_Flags, tc_State, tc_IDNestCnt, tc_TDNestCnt from
  2455.         ; user stack.
  2456.  
  2457. @d
  2458. @40dSet USP image in task descriptor.
  2459. @40dRestore interrupt disable level.
  2460. @d
  2461. @d
  2462. @40dDisable interrupts if needed.
  2463. @d
  2464.  
  2465.  
  2466. ---------------------------------------------------------------------------
  2467.   Switch()
  2468.  
  2469.   [Version for machines with a 68881 FPP]
  2470. ---------------------------------------------------------------------------
  2471.  
  2472. @a?fc108a
  2473. FC108A  move      #$2000,SR             Enable all interrupts.
  2474. @a=fc108e
  2475. @40dStore A5 on the supervisor stack.
  2476. @40dGet the user stack pointer.
  2477. @40dSave all registers on user stack.
  2478. @40dGet ExecBase.
  2479. @40dGet current interrupt disable level.
  2480. @40dSet interrupt disable level to -1.
  2481. @40dEnable interrupts.
  2482. @40dFix A5 in the saved register set.
  2483. @40dSave the status register.
  2484. @40dSave the program counter.
  2485.  
  2486.         ; 68020/68881 specific material.  Without documentation for those
  2487.         ; processors, I can't comment this.
  2488.  
  2489. @a?fc10b4
  2490. FC10B4  fsave     -(A5)
  2491. @a=fc10b6
  2492. @d
  2493. @d
  2494. @d
  2495. @d
  2496. @d
  2497. @d
  2498. @d
  2499. @d
  2500. @d
  2501. @d
  2502. @d
  2503. @d
  2504. @d
  2505. @a?fc10d6
  2506. FC10D6  fmovem.x  FP0-FP7,-(A5)
  2507. FC10DA  fmovem.l  FPCR/FPSR/FPIAR,-(A5)
  2508. @a=fc10de
  2509. @d
  2510.  
  2511. @40dPoint to 68881 context restore.
  2512.  
  2513.         ; The rest of the processing for Switch() is the same, so enter
  2514.         ; the "plain" version in the middle.
  2515.  
  2516. @d
  2517.  
  2518.  
  2519. ---------------------------------------------------------------------------
  2520.   Dispatch()
  2521.  
  2522.   [Version for machines with a 68881 FPP]
  2523. ---------------------------------------------------------------------------
  2524.  
  2525. @40dPoint to 68881 context-restore.
  2526.  
  2527.         ; The regular Dispatch() can be used for the rest.
  2528.  
  2529. @d
  2530.  
  2531.  
  2532.         ; Special 68881 FPP compatible context restore
  2533.         ; --------------------------------------------
  2534.  
  2535.         ; 68020/68881 specific material.  Without documentation for those
  2536.         ; processors, I can't comment this.
  2537.  
  2538. @d
  2539. @d
  2540. @d
  2541. @a?fc10f6
  2542. FC10F6  fmovem.l  (A5)+,FPCR/FPSR/FPIAR
  2543. FC10FA  fmovem.x  (A5)+,FP0-FP7
  2544. @a=fc10fe
  2545. @d
  2546. @d
  2547. @d
  2548. @d
  2549. @d
  2550. @d
  2551. @d
  2552. @a?fc1110
  2553. FC1110  frestore  (A5)+
  2554. @a=fc1112
  2555.  
  2556. @40dThis part is the same as the regular
  2557. @40dcontext-restore routine.
  2558. @d
  2559. @d
  2560. @d
  2561. @d
  2562.  
  2563.  
  2564. ---------------------------------------------------------------------------
  2565.   oldSR = SetSR( newSR, mask)
  2566.   D0             D0     D1
  2567. ---------------------------------------------------------------------------
  2568.  
  2569. @d
  2570. @36dWhat to execute in supervisor mode.
  2571. @36dEnter supervisor mode.
  2572. @d
  2573.  
  2574. @36dNow in supervisor mode.  Restore A5.
  2575. @36dGet status register from stack.
  2576. @36dMask unwanted bits out of newSR.
  2577. @d
  2578. @36dGet unchanged bits from old status reg.
  2579. @36dOr in the bits to be changed.
  2580. @d
  2581. @36dReturn old status codes in D0.
  2582. @36dLoad status reg. and return to user mode.
  2583.  
  2584.  
  2585. ---------------------------------------------------------------------------
  2586.   conditions = GetCC()
  2587.   D0
  2588.  
  2589.   [Version for 68000 machines only]
  2590. ---------------------------------------------------------------------------
  2591.  
  2592.         ; The ExecBase vector will have been changed not to point here
  2593.         ; unless the CPU is a 68000, since the following instruction would
  2594.         ; bomb with a privilege violation on 68010/020 processors.
  2595.  
  2596. @a?fc1140
  2597. FC1140  move      SR,D0             Get the status register.
  2598. @a=fc1142
  2599. @36dClear all but the condition codes.
  2600. @d
  2601.  
  2602.  
  2603. ---------------------------------------------------------------------------
  2604.   oldSysStack = SuperState()
  2605.   D0
  2606. ---------------------------------------------------------------------------
  2607.  
  2608. @d
  2609. @36dWhat to execute in supervisor mode.
  2610. @36dEnter supervisor mode.
  2611. @d
  2612.  
  2613. @36dContinue here.  Restore A5.
  2614. @d
  2615. @36dSet supervisor bit in status word.
  2616. @36dDo nothing more if it was already set.
  2617.  
  2618. @a?fc115e
  2619. FC115E  move      (SP)+,SR          Get status register from stack.
  2620. @a=fc1160
  2621. @36dSave supervisor stack pointer.
  2622. @36dLoad user stack pointer.
  2623.  
  2624. @36dCheck if running on a plain 68000.
  2625. @d
  2626. @36dPop 68010/020 exception info from stack.
  2627. @36dPop exception return address from stack.
  2628.  
  2629. @36dReturn to user.
  2630.  
  2631. @d
  2632.  
  2633.  
  2634. ---------------------------------------------------------------------------
  2635.   UserState( sysStack )
  2636.              D0
  2637. ---------------------------------------------------------------------------
  2638.  
  2639. @d
  2640. @36dWhere to go in supervisor mode.
  2641. @36dEnter supervisor mode (just in case).
  2642. @36dRestore A5.
  2643. @36dGet status register from stack.
  2644. @36dCopy stack pointer to user stack pointer.
  2645. @36dSet the system stack pointer.
  2646. @36dClear the supervisor mode bit.
  2647. @a?fc118a
  2648. FC118A  move      D1,SR
  2649. @a=fc118c
  2650. @36dReturn to the user.
  2651.  
  2652.  
  2653. ---------------------------------------------------------------------------
  2654.   oldInterrupt = SetIntVector( intNumber, interrupt )
  2655.   D0                           D0         A1
  2656. ---------------------------------------------------------------------------
  2657.  
  2658.         ; This routine makes an interrupt node the active interrupt node
  2659.         ; for a given interrupt number.  This node corresponds to an
  2660.         ; interrupt handler.  There can only be one node associated with
  2661.         ; each interrupt number.
  2662.  
  2663.         ; Note: Never try to SetIntVector() one of the interrupts which are
  2664.         ; dispatched as chains of servers.  The handler which does this
  2665.         ; does not use regular interrupt vectors or nodes, and it would not
  2666.         ; be possible to hook it up to the interrupt again if it became
  2667.         ; disconnected.
  2668.  
  2669. @36dCompute address of
  2670. @36dExecBase->IntVects[intNumber]
  2671.  
  2672. @36dDisable()
  2673. @d
  2674.  
  2675. @36dGet pointer to current interrupt node.
  2676. @36dInstall pointer to new interrupt node.
  2677.  
  2678. @36dIf there is a new node, then
  2679. @36d  Install interrupt data pointer.
  2680. @36d  Install interrupt code pointer.
  2681. @36dElse
  2682. @36d  Set code and data pointers to -1.
  2683. @d
  2684. @36dEndif
  2685.  
  2686. @36dEnable()
  2687. @d
  2688. @d
  2689. @d
  2690.  
  2691.  
  2692. ---------------------------------------------------------------------------
  2693.    AddIntServer( intNumber, interrupt )
  2694.                  D0         A1
  2695. ---------------------------------------------------------------------------
  2696.  
  2697.         ; Adds an interrupt server to the server chain for a given
  2698.         ; interrupt number.  The interrupt number must be one of the
  2699.         ; set for which interrupt server lists have been set up.
  2700.  
  2701.         ; The interrupt for which the server is being added will be enabled
  2702.         ; if it is not already enabled.
  2703.  
  2704. @d
  2705. @36dSave interrupt number.
  2706. @d
  2707. @36dCompute
  2708. @36dExecBase->IntVects[intNumber].is_Node
  2709. @d
  2710.  
  2711. @36dDisable()
  2712. @d
  2713.  
  2714. @36dEnqueue the interrupt server.
  2715.  
  2716. @36dHardware-enable the interrupt
  2717. @36dcorresponding to the server just added.
  2718. @d
  2719.  
  2720. @36dEnable()
  2721. @d
  2722. @d
  2723.  
  2724. @d
  2725. @d
  2726.  
  2727.  
  2728. ---------------------------------------------------------------------------
  2729.    RemIntServer( intNumber, interrupt )
  2730.                  D0         A1
  2731. ---------------------------------------------------------------------------
  2732.  
  2733.         ; This routine takes an interrupt server off the server chain for
  2734.         ; a given interrupt.  The interrupt is disabled if this leaves the
  2735.         ; server chain empty.
  2736.  
  2737. @d
  2738. @36dCompute
  2739. @36dExecBase->IntVects[intNumber].is_Node
  2740. @d
  2741.  
  2742. @36dSave interrupt number and node.
  2743. @d
  2744.  
  2745. @36dDisable()
  2746. @d
  2747.  
  2748. @36dUnlink interrupt server from the chain.
  2749. @d
  2750. @36dCheck if the chain is now empty.
  2751. @d
  2752.  
  2753. @36dChain is empty.  Disable the interrupt
  2754. @36dcorresponding to this node.
  2755. @d
  2756.  
  2757. @36dEnable()
  2758. @d
  2759. @d
  2760.  
  2761. @d
  2762. @d
  2763.  
  2764.  
  2765.         ; The following routine is used at system startup to initialize
  2766.         ; the exec's internal interrupt handlers.
  2767.  
  2768.         ; It initializes the server chains used to dispatch servers for
  2769.         ; I/O and timer, Copper, vertical blank, external level 6, and
  2770.         ; non-maskable interrupts, and establishes vectors to the exec's
  2771.         ; built-in interrupt handlers.
  2772.  
  2773.         ; For each server chain, a 22-byte data structure is built,
  2774.         ; consisting of a list header and 4 words of control data.  The
  2775.         ; 5 server chain headers are put into a contiguous 110-byte
  2776.         ; section of memory.  The server chains are initialized to empty,
  2777.         ; and the rest of the data structure is initialized with the
  2778.         ; data required to assert, deassert, and cancel the interrupt.
  2779.  
  2780.  
  2781. @d
  2782. @36d110 bytes needed.
  2783. @36dAttributes = MEMF_PUBLIC | MEMF_CLEAR.
  2784. @36dRequest memory.
  2785. @36dSee if we got the memory.
  2786. @d
  2787. @36dIf not, it's guru time!
  2788. @36dUse this alert number.
  2789. @36dGet ExecBase.
  2790. @36dGo put up the alert.
  2791. @36dNever reached.
  2792.  
  2793. @36dLoop 5 times (4 + 1 for dbra).
  2794. @36dGet pointer to allocated memory.
  2795. @36dPoint to the data table below.
  2796.  
  2797.         ; Loop:  Divide the 110 byte data area up into five data
  2798.         ; structures, each consisting of a list header and some control
  2799.         ; words.
  2800.  
  2801. @36dSave pointer to current node.
  2802. @36dInitialize the node's server chain
  2803. @36dto empty.
  2804. @d
  2805. @d
  2806.  
  2807. @36dPoint to the node's data area.
  2808. @36dGet interrupt number from table.
  2809. @36dMake the control word needed to disable
  2810. @36dthis interrupt.
  2811. @36dWrite it in the node's data area.
  2812. @36dMake the control word needed to enable
  2813. @36dthis interrupt and store it also.
  2814. @36dGet the cancel interrupt control word.
  2815. @36dMove a word of pad data.
  2816. @36dPoint to the generic interrupt handler.
  2817.  
  2818.         ; Set up this interrupt in the exec table.  The interrupt vector
  2819.         ; is at ExecBase + $54 + 12 * interrupt number.  We write the code
  2820.         ; and data addresses only; we don't bother with the node address.
  2821.  
  2822. @d
  2823. @d
  2824.  
  2825. @36dLoop until all interrupts done.
  2826.  
  2827.         ; Install the address of the software interrupt handler.  The
  2828.         ; software interrupt lists have already been cleared earlier in
  2829.         ; the system startup code.
  2830.  
  2831. @d
  2832.  
  2833.         ; Now enable interrupts and exit.  Note that only the software
  2834.         ; interrupts are enabled.  The interrupts handled by the handler
  2835.         ; below will be enabled if and when servers are put on their
  2836.         ; chains.  Interrupts handled external to the exec must be enabled
  2837.         ; by whoever provides the handler.
  2838.  
  2839. @d
  2840. @d
  2841. @d
  2842.  
  2843.  
  2844.         ; Interrupt initialization table.  Each line consists of an
  2845.         ; interrupt number, and a control word which is used to cancel
  2846.         ; the interrupt if pending.  The last column appears to be padding.
  2847.  
  2848.  
  2849. @8p@5w@5w@w
  2850. @8p@5w@5w@w
  2851. @8p@5w@5w@w
  2852. @8p@5w@5w@w
  2853. @8p@5w@5w@w
  2854.  
  2855.  
  2856.         ; Generic Interrupt Handler
  2857.         ; -------------------------
  2858.  
  2859.         ; Each logical interrupt (0-15) has a handler.  Some logical
  2860.         ; interrupts are accessible to the user not as handlers, but rather,
  2861.         ; as chains of servers.  Most of these (all but the Blitter one)
  2862.         ; use this code, which acts as a handler and dispatches the servers.
  2863.  
  2864.         ; A data structure set up by the previous routine exists for each
  2865.         ; interrupt to store the list header for the server chain, and some
  2866.         ; control words.
  2867.  
  2868. @d
  2869. @d
  2870. @35dCheck the head of the server chain.
  2871.  
  2872.         ; Main loop:  Here we dispatch a server from the queue.
  2873.  
  2874. @35dIs this the end of the chain?
  2875. @35dIf so, exit.
  2876. @35dGet the server's code and data addresses.
  2877. @35dCall it.
  2878.  
  2879.         ; Servers return with the zero flag indicating whether they have
  2880.         ; taken care of the interrupt.  We keep calling servers until
  2881.         ; we either run out or until one returns the zero flag clear.
  2882.  
  2883. @35dIf the zero flag is clear, exit.
  2884. @35dGo to next node in the queue.
  2885. @35dGo back to top of loop.
  2886.  
  2887.         ; Either we ran out of servers, or one of them accepted the
  2888.         ; interrupt.  Either way, clear the interrupt and exit.
  2889.  
  2890. @d
  2891. @35dClear the interrupt.
  2892. @d
  2893.  
  2894.  
  2895. ---------------------------------------------------------------------------
  2896.   Cause( interrupt )
  2897.          A1
  2898. ---------------------------------------------------------------------------
  2899.  
  2900. @36dDisable()
  2901. @d
  2902.  
  2903. @36dCheck if node type is already NT_SOFTINT.
  2904. @36dIf so, do nothing.
  2905.  
  2906. @36dMake node type NT_SOFTINT.
  2907. @d
  2908. @36dGet node priority.
  2909. @36dTruncate to a multiple of 16.
  2910. @36dSign extend to a word quantity.
  2911. @36dPoint at middle of ExecBase->SoftInts
  2912. @36dGet address of SoftInts entry correspon-
  2913.                                     ding to this priority (-32,-16,0,16,32).
  2914.  
  2915.         ; Now enqueue the node on the SoftIntList for this priority.
  2916.  
  2917. @d
  2918. @36dGet old TailPred pointer.
  2919. @36dSet TailPred pointer to new node.
  2920. @36dSet forward pointer of new node.
  2921. @36dSet back pointer of new node.
  2922. @d
  2923. @36dSet forward pointer of old tail node.
  2924.  
  2925. @36dSet the software interrupt pending flag.
  2926. @36dGenerate a level 1 "software" interrupt.
  2927. @36dEnable()
  2928. @d
  2929. @d
  2930. @d
  2931.  
  2932.         ; Software Interrupt Handler
  2933.         ; --------------------------
  2934.  
  2935.         ; This is the interrupt handler for logical interrupt #2, which
  2936.         ; is used for software interrupts.  It will be called as soon after
  2937.         ; the above routine as its interrupt priority will allow.
  2938.  
  2939. @36dClear the interrupt.
  2940. @36dClear the software int. pending flag.
  2941. @36dIf it wasn't set, ignore the interrupt.
  2942. @d
  2943.  
  2944. @36dDisable further software interrupts.
  2945. @36dGo and scan the SoftInts table.
  2946.  
  2947.         ; This code is called (from below) when a non-empty SoftIntList
  2948.         ; has been found.  The pointer of the list will be in A0.
  2949.  
  2950. @a?fc139c
  2951. FC139C  move.w    #$2700,SR         Mask all maskable interrupts.
  2952. @a=fc13a0
  2953. @36dGet the pointer to the first list node.
  2954. @d
  2955. @d
  2956. @36dUnlink the node from the list.
  2957. @d
  2958. @d
  2959. @d
  2960. @36dMake the node type NT_INTERRUPT.
  2961. @a?fc13b6
  2962. FC13B6  move.w    #$2000,SR         Enable all interrupts.
  2963. @a=fc13ba
  2964. @36dGet the interrupt code and data.
  2965. @36dCall the node's interrupt handler.
  2966.  
  2967.         ; The following scans the SoftInts[] table for non-empty
  2968.         ; SoftIntLists.  If it finds one, it executes the code above.
  2969.  
  2970. @36dLoop 5 times (1 less for dbra).
  2971. @36dStart at SoftInts[4] (priority 32).
  2972. @36dClear the software interrupt.
  2973. @36dSee if there are any nodes on this list.
  2974. @36dIf so, process the list.
  2975. @36dOtherwise, go to next lower priority,
  2976. @36dand loop back.
  2977.  
  2978.         ; No (more) nodes found.
  2979.  
  2980. @a?fc13de
  2981. FC13DE  move      #$2100,SR
  2982. @a=fc13e2
  2983. @36dReenable software interrupts and exit.
  2984. @d
  2985.  
  2986.  
  2987. ---------------------------------------------------------------------------
  2988.   Disable()
  2989. ---------------------------------------------------------------------------
  2990.  
  2991.         ; Hardware disable all interrupts, and log the fact that this
  2992.         ; was done in the interrupt disable nesting level counter.
  2993.  
  2994. @d
  2995. @d
  2996. @d
  2997.  
  2998.  
  2999. ---------------------------------------------------------------------------
  3000.   Enable()
  3001. ---------------------------------------------------------------------------
  3002.  
  3003.         ; Decrement the interrupt level nesting counter, and if it goes
  3004.         ; negative, enable interrupts again.
  3005.  
  3006. @d
  3007. @d
  3008. @d
  3009. @d
  3010.  
  3011. @8p@28wPadding.
  3012.  
  3013.  
  3014. ---------------------------------------------------------------------------
  3015.   AddLibrary( library )
  3016.               A1
  3017. ---------------------------------------------------------------------------
  3018.  
  3019. @36dPoint to system library list.
  3020. @36dAdd the library to the list.
  3021. @36dUpdate the library vector checksum.
  3022. @d
  3023.  
  3024.  
  3025. ---------------------------------------------------------------------------
  3026.   error = RemLibrary( library )
  3027.   D0                  A1
  3028. ---------------------------------------------------------------------------
  3029.  
  3030.         ; NOTE: Some other part of the system, presumably DOS, will patch
  3031.         ; itself in ahead of this.
  3032.  
  3033. @d
  3034. @36dForbid()
  3035. @36dSave ExecBase.
  3036. @d
  3037. @36dCall the library's Expunge() function.
  3038. @36dRestore ExecBase.
  3039. @36dPermit()
  3040. @d
  3041.  
  3042.  
  3043. ---------------------------------------------------------------------------
  3044.   library = OldOpenLibrary( libName )
  3045.   D0                        A1
  3046. ---------------------------------------------------------------------------
  3047.  
  3048.         ; This is just OpenLibrary() without the "version" parameter.
  3049.  
  3050. @36dAny version of the library will do.
  3051. @36dOpenLibrary()
  3052. @d
  3053.  
  3054.  
  3055. ---------------------------------------------------------------------------
  3056.   library = OpenLibrary( libName, version )
  3057.   D0                     A1       D0
  3058. ---------------------------------------------------------------------------
  3059.  
  3060.         ; NOTE: Some other part of the system, presumably DOS, will patch
  3061.         ; itself in ahead of this, presumably so it can pull libraries off
  3062.         ; disk if they aren't already in the library list.
  3063.  
  3064.         ; Note how several versions of a library can be in the system
  3065.         ; library list (although the initial RomTag system of putting them
  3066.         ; there will only take the newest one), and this routine will keep
  3067.         ; looking for one new enough to satisfy the request if it finds
  3068.         ; one which is too old.
  3069.  
  3070. @d
  3071. @d
  3072. @36dForbid()
  3073. @36dPoint to the system library list.
  3074. @36dFindName()
  3075. @36dDid we find the library?
  3076. @36dReturn zero and exit if not.
  3077. @d
  3078. @36dCheck the version number.
  3079. @36dTry to find another one if too old.
  3080.  
  3081.         ; We have an acceptable library.
  3082.  
  3083. @36dSave ExecBase.
  3084. @36dPoint A6 at the library base address.
  3085. @36dCall the library's Open() function.
  3086. @36dRestore ExecBase.
  3087. @36dPermit()
  3088. @d
  3089. @d
  3090.  
  3091.  
  3092. ---------------------------------------------------------------------------
  3093.   CloseLibrary( library )
  3094.                 A1
  3095. ---------------------------------------------------------------------------
  3096.  
  3097.         ; NOTE: Some other part of the system, presumably DOS, will patch
  3098.         ; itself in ahead of this.
  3099.  
  3100. @36dForbid()
  3101. @36dSave ExecBase.
  3102. @d
  3103. @36dCall the library's Close() function.
  3104. @36dRestore ExecBase.
  3105. @36dPermit()
  3106. @d
  3107.  
  3108.  
  3109. ---------------------------------------------------------------------------
  3110.   oldFunc = SetFunction( library, funcOffset, funcEntry )
  3111.   D0                     A1       A0.W        D0
  3112. ---------------------------------------------------------------------------
  3113.  
  3114. @36dIndicate that library is modified.
  3115. @36dCompute address of jump instruction.
  3116. @36dGet the old jump destination address.
  3117. @36dInstall a "JMP" instruction.
  3118. @36dInstall the new destination address.
  3119. @36dRe-checksum the library.
  3120. @36dReturn the previous jump destination.
  3121. @d
  3122.  
  3123.  
  3124. ---------------------------------------------------------------------------
  3125.   SumLibrary( library )
  3126.               A1
  3127. ---------------------------------------------------------------------------
  3128.  
  3129. @36dCheck the "sum used" flag.
  3130. @36dIf sum not used, then don't bother.
  3131.  
  3132. @d
  3133. @36dClear the "changed" flag.
  3134. @d
  3135. @36dIf the flag was set, clear the checksum.
  3136. @d
  3137. @36dGet the negative size.
  3138. @36dDivide by 2 (gives size in words).
  3139. @36dStart the sum at zero.
  3140. @d
  3141.  
  3142.         ; Loop:  Add up all the 16-bit words in the library's jump vector.
  3143.  
  3144. @d
  3145. @d
  3146.  
  3147. @36dGet the old checksum.
  3148. @d
  3149. @36dOld checksum wasn't zero, so compare
  3150. @36dit to the new checksum.
  3151.  
  3152.         ; Checksums didn't match, so put up an alert.
  3153.  
  3154. @d
  3155. @36dLibrary checksum alert number.
  3156. @d
  3157. @36dCall the alert function.
  3158. @d
  3159.  
  3160. @36dStore the new checksum in the library.
  3161.  
  3162. @36dEnable multitasking.
  3163. @d
  3164.  
  3165.  
  3166. ---------------------------------------------------------------------------
  3167.   library = MakeLibrary( vectors, structure, init, dataSize, segList )
  3168.   D0                     A0       A1         A2    D0        D1
  3169. ---------------------------------------------------------------------------
  3170.  
  3171. @d
  3172.  
  3173. @36dSize of library data area.
  3174. @36dPointer to library vector table.
  3175. @36dPointer to initialization structure.
  3176. @36dFunction to call after creating library.
  3177. @36dSegList (for DOS use).
  3178. @36dGet pointer to vector table.
  3179. @36dSkip the following if no vectors.
  3180.  
  3181. @d
  3182. @d
  3183. @36dCheck if vector data is absolute or
  3184. @36drelative (first word = -1).
  3185. @d
  3186. @36dRelative vectors.  Skip over the flag.
  3187. @36dCount the vectors up to the terminating
  3188. @36dflag.  D3 holds -(number of vectors + 1)
  3189. @d
  3190. @36dAbsolute vectors.  Count as above.
  3191. @d
  3192. @36dMake number of vectors positive.
  3193. @36dMultiply by 6.
  3194.  
  3195. @d
  3196. @36dAdd size of data area.
  3197.  
  3198. @36dMEMF_PUBLIC | MEMF_CLEAR
  3199. @36dRequest memory for library node.
  3200.  
  3201. @36dSee if the memory was allocated.
  3202. @d
  3203. @36dDidn't get any memory.  Fail by returning
  3204. @36da nil pointer to the caller.
  3205.  
  3206. @36dPoint to start of allocated memory.
  3207. @36dSkip over jump vector area.
  3208. @36dInstall negative size in library node.
  3209. @36dInstall positive size.
  3210. @d
  3211. @36dClear A2.
  3212. @36dPoint at vector table again.
  3213. @36dCheck if vectors are relative.
  3214. @d
  3215. @36dIf vectors are relative, skip over flag,
  3216. @36dand set A2 to vector table address.
  3217.  
  3218. @36dInstall the jump vector.
  3219.  
  3220. @36dCheck if there is an initialization
  3221. @36dstructure.  Skip the following if not.
  3222.  
  3223. @d
  3224. @d
  3225. @36dDo not clear memory before initializing.
  3226. @36dProcess the initialization structure.
  3227.  
  3228. @36dGet pointer to library node.
  3229. @36dCheck if there is initialization code.
  3230. @36dSkip the following if not.
  3231.  
  3232. @36dGet the address of the code.
  3233. @36dGet the address of the segList
  3234. @36dCall the initialization code.
  3235.  
  3236. @d
  3237. @d
  3238.  
  3239.  
  3240. ---------------------------------------------------------------------------
  3241.   size = MakeFunctions( vectors, offset )
  3242.   D0                    A1       A2
  3243. ---------------------------------------------------------------------------
  3244.  
  3245. @d
  3246. @36dClear size counter.
  3247. @36dCheck if vector table is relative.
  3248. @d
  3249.  
  3250.         ; Process a relative vector initialization table.
  3251.  
  3252. @36dGet a relative table entry.
  3253. @36dCheck if end of table marker.
  3254. @d
  3255. @36dCompute absolute vector address.
  3256. @36dInstall in jump vector.
  3257. @36dInstall "JMP" instruction.
  3258. @36dIncrement size counter.
  3259. @d
  3260.  
  3261.         ; Process an absolute vector initialization table.
  3262.  
  3263. @36dGet an absolute table entry.
  3264. @36dCheck if end of table marker.
  3265. @d
  3266. @36dInstall it in the jump table.
  3267. @36dInstall "JMP" instruction.
  3268. @36dIncrement size counter.
  3269. @d
  3270.  
  3271. @36dDone, return to caller.
  3272. @d
  3273.  
  3274.  
  3275. ---------------------------------------------------------------------------
  3276.   Insert( list, node, listNode )
  3277.           A0    A1    A2
  3278. ---------------------------------------------------------------------------
  3279.  
  3280. @32dCheck if node to insert after is zero.
  3281. @32dIf so, do an AddHead instead.
  3282.  
  3283. @32dSee if list node indicates end of list.
  3284. @32dBranch if so.
  3285.  
  3286.         ; If we get this far, A2 must point to a list node.
  3287.  
  3288. @d
  3289. @32dSet forward and back pointers of new node.
  3290. @32dSet back pointer of next node.
  3291. @32dSet forward pointer of previous node.
  3292. @d
  3293.  
  3294.         ; The "Successor" field of the listNode was zero, i.e. listNode
  3295.         ; is really the end of list marker.  In this case, insert just
  3296.         ; before listNode, i.e. at the end of the list (undocumented).
  3297.  
  3298. @32dSet forward pointer of new node to end.
  3299. @32dGet old TailPred pointer
  3300. @32dLink previous end node to new node.
  3301. @32dSet the TailPred pointer to the new node.
  3302. @32dLink this node to the previous end node.
  3303. @d
  3304.  
  3305.  
  3306. ---------------------------------------------------------------------------
  3307.   AddHead( list, node )
  3308.            A0    A1
  3309. ---------------------------------------------------------------------------
  3310.  
  3311. @32dGet old pointer to first node.
  3312. @32dMake the first node the new node.
  3313. @32dSet forward and back pointers in new node.
  3314. @d
  3315. @32dFix back pointer in previous first node.
  3316. @d
  3317.  
  3318.  
  3319. ---------------------------------------------------------------------------
  3320.   AddTail( list, node )
  3321.            A0    A1
  3322. ---------------------------------------------------------------------------
  3323.  
  3324. @32dPoint A0 to list's "Tail" field.
  3325. @32dSave old value of TailPred field.
  3326. @32dMake the new node the last node.
  3327. @32dSet new node's back pointer to list header.
  3328. @32dSet new node's back pointer.
  3329. @d
  3330. @32dLink new node to previous last node.
  3331. @d
  3332.  
  3333.  
  3334. ---------------------------------------------------------------------------
  3335.   Remove( node )
  3336.           A1
  3337. ---------------------------------------------------------------------------
  3338.  
  3339. @32dGet pointer to successor node.
  3340. @32dGet pointer to predecessor node.
  3341. @32dPoint predecessor to successor.
  3342. @32dPoint successor to predecessor.
  3343. @d
  3344.  
  3345.  
  3346. ---------------------------------------------------------------------------
  3347.   node = RemHead( list )
  3348.   D0              A0
  3349. ---------------------------------------------------------------------------
  3350.  
  3351. @32dGet list's head pointer.
  3352. @32dGet first node's successor.
  3353. @32dIf zero, list is empty, so return zero.
  3354.  
  3355. @32dPoint head pointer past removed node.
  3356. @d
  3357. @32dPoint new head node back at list header.
  3358. @d
  3359.  
  3360.  
  3361. ---------------------------------------------------------------------------
  3362.   node = RemTail( list )
  3363.   D0              A0
  3364. ---------------------------------------------------------------------------
  3365.  
  3366. @a?fc161e
  3367. @32dGet list's TailPred pointer.
  3368. @32dCheck if the last node has a predecessor.
  3369. @32dIf not, the list is empty, so return zero.
  3370. @32dPoint TailPred pointer at second-last node.
  3371. @d
  3372. @32dPoint second-last node at the list header.
  3373. @32dIncrement to point at "Tail" field.
  3374. @d
  3375.  
  3376.  
  3377. ---------------------------------------------------------------------------
  3378.   Enqueue( list, node )
  3379.            A0    A1
  3380. ---------------------------------------------------------------------------
  3381.  
  3382. @32dGet the priority field of the node.
  3383. @32dGet the head pointer of the queue.
  3384.  
  3385.         ; Loop:  Keep skipping nodes until the end of the list is
  3386.         ; reached or the next node has a lower priority.
  3387.  
  3388. @32dPoint at the current node.
  3389. @32dCheck if there is a successor.
  3390. @32dIf not, we are at the end of the list.
  3391. @32dCompare priorities.
  3392. @32dLoop until priority is lower than new node's.
  3393.  
  3394.         ; A0 now points at the node to insert before, or at the end
  3395.         ; of the list (i.e. the list header plus 4).
  3396.  
  3397. @32dGet old value of back pointer
  3398.                                 (or TailPred pointer of list header).
  3399. @32dChange it to point to the new node.
  3400. @32dSet new node's forward pointer.
  3401. @32dSet new node's back pointer to last node
  3402.                                 skipped, or list header.
  3403. @d
  3404. @32dSet list's head field, or forward pointer
  3405.                                 of previous node, to new node.
  3406. @d
  3407.  
  3408.  
  3409. ---------------------------------------------------------------------------
  3410.   node = FindName( start, name )
  3411.   D0               A0     A1
  3412. ---------------------------------------------------------------------------
  3413.  
  3414. @d
  3415. @36dPoint to list header or first node.
  3416. @36dSave address of match string in D1.
  3417. @d
  3418. @36dExit if list is empty.
  3419.  
  3420.         ; Main loop:  Check if node pointed to by D0 has the same name
  3421.         ; as the string pointed to by D1.
  3422.  
  3423. @36dGet the address of the node to check.
  3424. @d
  3425. @36dExit if this is the end of the list.
  3426.  
  3427. @36dPoint A0 at name of this node.
  3428. @36dPoint A1 at match string.
  3429.  
  3430.         ; Inner loop:  Compare the strings.
  3431.  
  3432. @36dCompare one character.
  3433. @36dSkip to next node if not equal.
  3434. @36dWas this the terminating zero?
  3435. @36dContinue comparing if not.
  3436.  
  3437. @36dGot a match - point D0 to the node.
  3438.  
  3439. @36dRestore registers and exit.
  3440. @d
  3441. @d
  3442.  
  3443.         ; Protected enqueue and dequeue routines
  3444.         ; --------------------------------------
  3445.  
  3446. @36dForbid()
  3447. @36dEnqueue()
  3448. @36dPermit()
  3449. @d
  3450.  
  3451. @36dForbid()
  3452. @36dRemove()
  3453. @36dPermit()
  3454. @d
  3455.  
  3456.  
  3457. ---------------------------------------------------------------------------
  3458.   memoryBlock = Allocate( freeList, byteSize )
  3459.   D0                      A0        D0
  3460. ---------------------------------------------------------------------------
  3461.  
  3462. @36dZero bytes requested?
  3463. @36dIf so, just return.
  3464. @d
  3465. @36dRound D0 up to nearest multiple of 8.
  3466. @d
  3467. @d
  3468. @36dCompare D0 to total number of bytes free.
  3469. @36dIf greater, return zero.
  3470. @36dPoint at the link to the first MemChunk.
  3471.  
  3472.         ; Loop:  Scan the free list for a MemChunk big enough to satisfy
  3473.         ; the request.
  3474.  
  3475. @36dGet the pointer to the next MemChunk.
  3476. @36dIf no more MemChunks, return zero.
  3477. @d
  3478. @36dCheck D0 against size of this chunk.
  3479. @36dIf smaller or equal, take it.
  3480. @36dOtherwise, go to next MemChunk.
  3481. @36dContinue searching.
  3482.  
  3483.         ; This is where memory fragmentation occurs.  If the block we've
  3484.         ; found is bigger than what we need, we take what we need and make
  3485.         ; a smaller block out of the rest.
  3486.  
  3487. @36dIf sizes are not the same, then
  3488. @36d  Compute address of leftover block.
  3489. @36d  Move the MemChunk pointer up.
  3490. @36d  Get the current size.
  3491. @36d  Subtract the allocated amount.
  3492. @36d  Put it into the new MemChunk.
  3493. @36d  Link to previous MemChunk (or header).
  3494. @36dElse
  3495. @36d  Unlink this MemChunk.
  3496.                                     Endif
  3497. @36dDecrease free memory value in header.
  3498. @36dGet address of allocated block.
  3499.  
  3500. @36dReturn zero or address of block.
  3501. @d
  3502. @d
  3503.  
  3504.         ; Routine to put up a "Corrupt Free List" dead-end alert.
  3505.  
  3506. @a?fc16ee
  3507. @d
  3508. @36dAlert number.
  3509. @36dGet ExecBase.
  3510. @36dPut up the alert.
  3511. @36dNever reached.
  3512.  
  3513.  
  3514. ---------------------------------------------------------------------------
  3515.   Deallocate( freeList, memoryBlock, byteSize )
  3516.               A0        A1           D0
  3517. ---------------------------------------------------------------------------
  3518.  
  3519. @36dSee if byte size is zero.
  3520. @36dDo nothing if so.
  3521. @d
  3522. @d
  3523. @36dTruncate block address to nearest
  3524. @36dmultiple of 8.
  3525. @36dFind out by how much that decreased
  3526. @36dthe address, then add this amount to
  3527. @36dthe number of bytes to free.
  3528. @36dNow round number of bytes to free up to
  3529. @36dnearest multiple of 8.
  3530. @36dExit if the result is zero bytes.
  3531.  
  3532.         ; Block address and size are now nice multiples of 8, so we can
  3533.         ; go ahead and put the block into the free list.
  3534.  
  3535. @36dPoint at the link to the first MemChunk.
  3536. @36dGet the address of the first MemChunk.
  3537. @36dBranch if there are no MemChunks.
  3538.  
  3539.         ; Main loop: Find the first MemChunk with an address greater than
  3540.         ; that of our memory block.
  3541.  
  3542. @36dCompare addresses.
  3543. @36dExit loop if right MemChunk found.
  3544. @36dIf addresses are equal, guru time!
  3545. @d
  3546. @36dGet address of next MemChunk.
  3547. @36dContinue searching.
  3548.  
  3549.         ; A2 now points at the link which comes directly before the position
  3550.         ; where our block must be inserted.  First, we check whether this
  3551.         ; is the start of the list.  If so, we just link it in.
  3552.  
  3553. @36dCompute address of MemHeader's link.
  3554. @d
  3555. @36dSee if A2 still points there.
  3556. @36dIf so, insert block at head of the list.
  3557.  
  3558.         ; We are somewhere other than at the start of the list.  It is
  3559.         ; possible that we can join the block to the previous MemChunk.
  3560.         ; Try this now.
  3561.  
  3562. @36dCompute first address after the
  3563. @36dprevious MemChunk.
  3564. @36dCompare to address of our new block.
  3565. @36dIf equal, join the two together.
  3566. @36dIf greater, free list is corrupt.
  3567.  
  3568.         ; Enter here to make a new MemChunk and link it into the free list.
  3569.  
  3570. @36dSet new MemChunk's link field.
  3571. @36dPoint previous link at the MemChunk.
  3572. @36dPut the block size into the MemChunk.
  3573. @d
  3574.  
  3575.         ; Enter here to attach the new block to the previous MemChunk.
  3576.  
  3577. @36dAdd to previous MemChunk's size.
  3578. @36dBack pointer up to that MemChunk.
  3579.  
  3580.         ; Now the block is taken care of.  Either we have built a MemChunk
  3581.         ; for it, or we have attached it to a MemChunk directly before the
  3582.         ; block.  Either way, the address of the MemChunk where the block
  3583.         ; now is is in A1.  It remains to check whether we can join this
  3584.         ; MemChunk with the next one down the line.
  3585.  
  3586. @36dSee if there is a next MemChunk.
  3587. @36dExit if not.
  3588. @36dGet our MemChunk's size.
  3589. @36dAdd to its base address.
  3590. @36dCompare to address of next MemChunk.
  3591. @36dIf higher, free list is corrupt.
  3592. @36dIf not equal, we can't join them.
  3593.  
  3594.         ; If we get this far, we can join this MemChunk to the next one down
  3595.         ; the line, so we delete the next one and add its size to this one.
  3596.  
  3597. @36dGet pointer to next MemChunk.
  3598. @36dFetch its link and put in our MemChunk.
  3599. @36dGet its size.
  3600. @36dAdd to size of our MemChunk.
  3601.  
  3602.         ; This is where all the paths meet again.
  3603.  
  3604. @36dAdd size of freed block to free counter.
  3605. @d
  3606. @d
  3607.  
  3608.         ; Error exit routine.  Generate a dead-end alert.
  3609.  
  3610. @d
  3611. @36dAlert number.
  3612. @36dGet ExecBase.
  3613. @36dGo put up the alert.
  3614. @36dNever reached.
  3615.  
  3616.  
  3617. ---------------------------------------------------------------------------
  3618.   memoryBlock = AllocMem( byteSize, requirements )
  3619.   D0                      D0        D1
  3620. ---------------------------------------------------------------------------
  3621.  
  3622.         ; NOTE: Some other part of the system, presumably DOS, will patch
  3623.         ; itself in ahead of this, presumably so it can throw out unused
  3624.         ; libraries, devices, fonts, etc. when memory runs low.
  3625.  
  3626. @36dForbid()
  3627. @d
  3628. @d
  3629. @d
  3630. @36dPoint to the system free memory list.
  3631.  
  3632.         ; Loop:  Step through the system free memory list looking for
  3633.         ; a MemHeader which can satisfy the memory request.
  3634.  
  3635. @36dGet pointer to a MemHeader.
  3636. @36dEnd of memory list reached?
  3637. @d
  3638. @36dIf so, return a null pointer and exit.
  3639. @d
  3640. @36dGet the MemHeader's attributes.
  3641. @36dCheck against needed attributes.
  3642. @d
  3643. @36dGo to next MemHeader if not present.
  3644.  
  3645.         ; The current MemHeader has the right attribute flags, now try
  3646.         ; to get a block of the required size out of its free list.
  3647.  
  3648. @36dPoint to the MemHeader.
  3649. @36dIndicate size of block required.
  3650. @36dAllocate()
  3651. @36dDid we get the memory?
  3652. @36dIf not, go to next MemHeader.
  3653.  
  3654.         ; We got a memory block.  Clear it if necessary.
  3655.  
  3656. @36dWas the MEMF_CLEAR flag set?
  3657. @36dJust return if not.
  3658. @d
  3659. @36dConvert number of bytes to nearest number
  3660. @36dof longwords.
  3661. @36dPoint to the memory block.
  3662. @36dEnter the loop at the bottom.
  3663.  
  3664.         ; Loop: Clear the memory block.
  3665.  
  3666. @36dClear one longword.
  3667. @36dLoop back until none remain.
  3668.  
  3669. @36dDBRA instruction only uses low 16 bits
  3670. @36das program counter, so if any remain
  3671. @36dset in the upper half of D3, decrement
  3672. @36dthem manually and loop back.
  3673. @d
  3674. @d
  3675.  
  3676. @36dPermit()
  3677. @d
  3678. @d
  3679.  
  3680.  
  3681. ---------------------------------------------------------------------------
  3682.   FreeMem( memoryBlock, byteSize )
  3683.            A1           D0
  3684. ---------------------------------------------------------------------------
  3685.  
  3686. @36dForbid()
  3687. @36dIs number of bytes to free zero?
  3688. @36dIf so, just exit.
  3689. @36dPoint to system free memory list.
  3690.  
  3691.         ; Loop: Look for the right MemHeader to put the block back into.
  3692.  
  3693. @36dPoint to the next MemHeader.
  3694. @36dEnd of list reached?
  3695.  
  3696.         ; If no MemHeader can be found to put this block on, something
  3697.         ; is wrong, so it's guru time.
  3698.  
  3699. @36dGuru time if end of list reached.
  3700.  
  3701.         ; See if the block falls into the address range covered by this
  3702.         ; MemHeader.
  3703.  
  3704. @36dDoes block start before mh_Lower?
  3705. @36dIf so, try next MemHeader.
  3706. @36dDoes block start after mh_Upper?
  3707. @36dIf so, try next MemHeader.
  3708.  
  3709.         ; The block belongs to this MemHeader, so go link it back into
  3710.         ; the free list.
  3711.  
  3712. @36dDeallocate()
  3713. @36dPermit()
  3714. @d
  3715.  
  3716.  
  3717. ---------------------------------------------------------------------------
  3718.   attributes = TypeOfMem( address )
  3719.   D0                      A1
  3720. ---------------------------------------------------------------------------
  3721.  
  3722. @36dForbid()
  3723. @36dPoint to system free memory list.
  3724. @d
  3725. @36dPoint to next MemHeader.
  3726. @36dEnd of list reached?
  3727. @36dIf so, return zero and exit.
  3728. @36dCheck if the block is in the address
  3729. @36drange covered by this MemHeader.
  3730. @d
  3731. @36dIf it is, return the contents of the
  3732. @36dMemHeader's attribute field.
  3733. @36dPermit()
  3734. @d
  3735.  
  3736.  
  3737. ---------------------------------------------------------------------------
  3738.   memoryBlock = AllocAbs( byteSize, location )
  3739.   D0                      D0        A1
  3740. ---------------------------------------------------------------------------
  3741.  
  3742. @36dForbid()
  3743. @d
  3744. @36dGet the start address.
  3745. @36dTruncate down to nearest multiple of 8.
  3746. @d
  3747. @36dAdd any difference to number of bytes
  3748. @36dwanted, then round number of bytes
  3749. @36dup to nearest multiple of 8.
  3750. @36dPoint to the system free memory list.
  3751.  
  3752.         ; Loop: Scan through all the MemHeaders in the free list.
  3753.  
  3754. @36dPoint to next MemHeader.
  3755. @36dEnd of list reached?
  3756. @36dIf so, allocation failed, return zero.
  3757.  
  3758.         ; Check whether the block we want is covered by this MemHeader.
  3759.  
  3760. @36dIf block starts before this MemHeader's
  3761. @36darea, go on to the next one.
  3762. @36dIf block starts after this MemHeader's
  3763. @36darea, go on to next one.
  3764.  
  3765.         ; The desired block starts in the address range covered by this
  3766.         ; MemHeader, so it's either this one or nothing.
  3767.  
  3768.         ; Quick check:  If the total number of bytes free in this MemHeader's
  3769.         ; free list is less than the size of the block wanted, then the
  3770.         ; allocation is going to fail anyway.
  3771.  
  3772. @37dCheck block size against mh_Free.
  3773. @37dAllocation failed if higher.
  3774. @37dGet start address of block wanted.
  3775. @d
  3776. @37dCompute end address of block wanted.
  3777. @37dPoint to link to first MemChunk.
  3778.  
  3779.         ; Loop:  Find the MemChunk in the free list which contains the
  3780.         ; wanted block.
  3781.  
  3782. @37dGet pointer to next MemChunk.
  3783. @37dAllocation failed if no more MemChunks.
  3784. @d
  3785. @37dGet the MemChunk's size.
  3786. @37dCompute its end address.
  3787. @37dCheck against needed end address.
  3788. @37dExit loop if equal or higher.
  3789. @d
  3790. @37dGo to the next MemChunk.
  3791.  
  3792.         ; We have a MemChunk whose end address is greater than or equal
  3793.         ; to the end address of the block we want.  It's either this
  3794.         ; MemChunk or none at all.
  3795.  
  3796. @37dCheck start addresses.
  3797. @37dAllocation failed if needed block
  3798.                                      starts before this MemChunk.
  3799.  
  3800.         ; The block we want is entirely within this MemChunk, so now we
  3801.         ; cut it out and make zero, one or two MemChunks out of what's left.
  3802.  
  3803. @37dRemove block size from free count.
  3804. @37dCompare end addresses.
  3805. @d
  3806.  
  3807.         ; The end addresses of the allocated block and the MemChunk it
  3808.         ; was in were exactly equal.
  3809.  
  3810. @d
  3811. @d
  3812.  
  3813.         ; Memory was left over between the allocated block and the end of
  3814.         ; the MemChunk.  Make a new MemChunk out of this and link it into
  3815.         ; the free list.
  3816.  
  3817. @37dCompute base address of new MemChunk.
  3818. @37dStore pointer to next MemChunk.
  3819. @37dLink to previous MemChunk.
  3820. @37dStore number of bytes in MemChunk.
  3821.  
  3822.         ; At this point, whatever was left after the block was taken
  3823.         ; care of, and a pointer to the next MemChunk after the block is
  3824.         ; in A0.
  3825.  
  3826. @37dCompare start addresses.
  3827. @d
  3828.  
  3829.         ; The block started after the beginning of this MemChunk, so we
  3830.         ; just truncate the MemChunk to contain the leftover memory before
  3831.         ; the allocated block.
  3832.  
  3833. @d
  3834. @37dCompute remaining size.
  3835. @37dStore in the MemChunk.
  3836. @37dAll done.
  3837.  
  3838.         ; The block started exactly at the beginning of the MemChunk, so
  3839.         ; the MemChunk must be deleted.
  3840.  
  3841. @37dUnlink this MemChunk from the chain.
  3842. @37dReturn address of allocated block.
  3843. @d
  3844. @37dPermit()
  3845. @d
  3846.  
  3847. @37dReturn zero if allocation failed.
  3848. @d
  3849.  
  3850.  
  3851. ---------------------------------------------------------------------------
  3852.   size = AvailMem( requirements )
  3853.   D0               D1
  3854. ---------------------------------------------------------------------------
  3855.  
  3856. @d
  3857. @36dInitialize free memory counter.
  3858. @36dPoint at the ExecBase->MemList.
  3859. @36dForbid()
  3860. @d
  3861. @36dGet address of first MemHeader.
  3862. @36dExit if list is empty.
  3863. @36dGet this MemHeader's attributes.
  3864. @36dMask with required attributes.
  3865. @36dCheck if all attributes are satisfied.
  3866. @36dGo to next MemHeader if not.
  3867. @36dAre we looking for the largest
  3868.                                     contiguous block of memory?
  3869. @d
  3870. @36dIf not, just add the size,
  3871. @36dand loop back.
  3872.  
  3873.         ; We are looking for the largest contiguous block of memory.
  3874.  
  3875. @36dGet address of first MemChunk.
  3876. @36dLoop back if there is no MemChunk.
  3877. @d
  3878. @36dSee if this MemChunk is the biggest yet.
  3879. @d
  3880. @36dIf it is, keep its base address (why?),
  3881. @36dand its size.
  3882. @d
  3883. @36dGo to next MemChunk.
  3884. @36dPermit()
  3885. @36dReturn the accumulated or largest size.
  3886. @d
  3887. @d
  3888.  
  3889.  
  3890. ---------------------------------------------------------------------------
  3891.   memList = AllocEntry( memList )
  3892.   D0                    A0
  3893. ---------------------------------------------------------------------------
  3894.  
  3895. @d
  3896. @36dSave pointer to request MemList.
  3897. @36dClear loop counter.
  3898. @d
  3899. @36dGet the number of MemEntries.
  3900. @d
  3901. @36dCompute the size of the MemList needed
  3902. @36dto keep track of the MemEntries.
  3903. @36dSet MEMF_CLEAR.
  3904. @36dAllocate that amount of memory.
  3905. @36dIf we didn't get it, go exit.
  3906. @d
  3907. @36dPoint to base of new MemList structure.
  3908. @36dPut in the number of MemEntries.
  3909. @36dPoint to MemEntries in request MemList.
  3910. @36dPoint to MemEntries in result MemList.
  3911.                                     For each MemEntry do
  3912. @36d  Get its required attributes.
  3913. @36d  Get its required size.
  3914. @36d  Store the size in the result list.
  3915. @36d  If size is not zero then
  3916. @36d    Allocate the memory.
  3917. @36d    Go exit if unsuccessful.
  3918. @36d  Endif
  3919. @36d  Store memory address in result list.
  3920. @36d  Go to next request MemEntry.
  3921. @36d  Go to next result MemEntry.
  3922. @36d  Increment loop counter.
  3923. @36d  Compare to number of MemEntries.
  3924. @36dEndfor.
  3925. @d
  3926. @36dCompute -(size of MemEntry list).
  3927. @36dPoint A2 back at the request MemList.
  3928. @36dPoint A3 back at the result MemList.
  3929. @36dReturn the address of the result MemList.
  3930. @d
  3931. @d
  3932.  
  3933.         ; Enter here if one of the MemEntries could not be allocated.
  3934.  
  3935. @36dSave size of the allocate which failed.
  3936. @36dTest number of allocated MemEntries.
  3937. @36dExit if none remaining.
  3938. @36dDecrement number of MemEntries.
  3939. @36dPoint to the allocated MemEntry.
  3940. @36dGet the address and size of the block
  3941. @36dcorresponding to it.
  3942. @36dDeallocate the block.
  3943. @36dGo back and check for more MemEntries.
  3944.  
  3945.         ; Enter here if the AllocEntry failed, after deallocating anything
  3946.         ; which was allocated before the failure.
  3947.  
  3948. @36dGet size of the allocate which failed.
  3949. @d
  3950. @36dSet the high bit.
  3951. @36dReturn it to the user.
  3952.  
  3953.  
  3954. ---------------------------------------------------------------------------
  3955.   FreeEntry( memList )
  3956.              A0
  3957. ---------------------------------------------------------------------------
  3958.  
  3959. @d
  3960. @36dPoint to the MemList.
  3961. @36dPoint to the first MemEntry.
  3962. @36dGet number of MemEntries.
  3963. @36dFor each MemEntry in the MemList do
  3964. @36d  Get the address of the memory block.
  3965. @36d  Get the sizde of the memory block.
  3966. @36d  If size is not zero then
  3967. @36d    Deallocate the block.
  3968. @36d  Endif
  3969. @36dEndfor
  3970. @d
  3971. @36dGet the number of MemEntries again.
  3972. @d
  3973. @36dCompute the size of the MemList.
  3974. @36dPoint to the base of the MemList.
  3975. @36dDeallocate it.
  3976. @d
  3977. @d
  3978.  
  3979.  
  3980. ---------------------------------------------------------------------------
  3981.   error = AddMemList( size, attributes, pri, base, name )
  3982.   D0                  D0    D1          D2   A0    A1
  3983. ---------------------------------------------------------------------------
  3984.  
  3985.         ; This routine takes a block of memory, builds a MemHeader at the
  3986.         ; start of it, and puts the rest of the block into the MemHeader's
  3987.         ; free list.  Then it adds the MemHeader to the system free memory
  3988.         ; list.
  3989.  
  3990. @36dStore the name in the MemHeader.
  3991. @36dCompute first address after MemHeader.
  3992. @36dMemHeader's node type is NT_MEMORY.
  3993. @36dSet the MemHeader's priority.
  3994. @36dSet the memory attributes.
  3995. @d
  3996. @36dRound the base address of the block up
  3997. @36dto the nearest multiple of 8.
  3998. @d
  3999. @36dCompute by how much it changed,
  4000. @36dand add this amount to the length.
  4001. @36dTruncate the length to a multiple of 8.
  4002. @36dSubtract the size of the MemHeader.
  4003. @36dStore base address as lower bound of
  4004. @36dmemory and link to first MemChunk.
  4005. @d
  4006. @36dCompute upper bound address.
  4007. @36dStore it in the MemHeader.
  4008. @36dStore the amount of free memory.
  4009. @36dBuild a MemChunk at the start of free
  4010. @36dmemory (clear link, store size).
  4011. @36dGet base address of MemHeader
  4012. @36dPoint to the system free memory list.
  4013. @36dPut the MemHeader on the list.
  4014. @d
  4015.  
  4016. @8p@28wPadding.
  4017.  
  4018.  
  4019.         ; Data table used to build the exec jump vector table.
  4020.  
  4021.         ; There are 105 entries, corresponding to the 105 exec functions,
  4022.         ; followed by a -1 table end marker.  Each entry is a 16-bit
  4023.         ; relative offset from the start of the table.
  4024.  
  4025. @7p@9l@9l@9l@l
  4026. @7p@9l@9l@9l@l
  4027. @7p@9l@9l@9l@l
  4028. @7p@9l@9l@9l@l
  4029. @7p@9l@9l@9l@l
  4030. @7p@9l@9l@9l@l
  4031. @7p@9l@9l@9l@l
  4032. @7p@9l@9l@9l@l
  4033. @7p@9l@9l@9l@l
  4034. @7p@9l@9l@9l@l
  4035. @7p@9l@9l@9l@l
  4036. @7p@9l@9l@9l@l
  4037. @7p@9l@9l@9l@l
  4038. @7p@w
  4039.  
  4040. @7p@29wEnd of table marker.
  4041.  
  4042. @7p@29wLooks like garbage.
  4043. @7p@w
  4044.  
  4045.  
  4046. ---------------------------------------------------------------------------
  4047.   AddPort( port )
  4048.            A1
  4049. ---------------------------------------------------------------------------
  4050.  
  4051. @36dAddress of port's message list.
  4052. @36dInitialize the list's head pointer.
  4053. @d
  4054. @36dInitialize the list's Tail field.
  4055. @36dInitialize the list's TailPred pointer.
  4056. @36dAddress of the public message port list.
  4057. @36dSafely add port to the list.
  4058.  
  4059.  
  4060. ---------------------------------------------------------------------------
  4061.   RemPort( port )
  4062.            A1
  4063. ---------------------------------------------------------------------------
  4064. @a?fc1b30
  4065.  
  4066.         ; Call a general purpose subroutine which unlinks something from
  4067.         ; its queue while disabling multitasking.
  4068.  
  4069. @d
  4070.  
  4071.  
  4072. ---------------------------------------------------------------------------
  4073.   PutMsg( port, message )
  4074.           A0    A1
  4075. ---------------------------------------------------------------------------
  4076.  
  4077. @36dMake sure message node type is NT_MESSAGE
  4078. @d
  4079. @36dCompute address of port's message list
  4080.  
  4081. @36dDisable()
  4082. @d
  4083.  
  4084.         ; Enqueue the message at the end of the port's message list
  4085.  
  4086. @36dPoint A0 at port's Tail field.
  4087. @36dSave pointer to last node in list
  4088. @36dMake new node the last node
  4089. @36dNew node has no next node
  4090. @36dLink new node back to old last node
  4091. @d
  4092. @36dLink old last node to new node
  4093.  
  4094.         ; Do whatever needs to be done on message arrival.
  4095.  
  4096. @d
  4097. @36dGet address of message port's task.
  4098. @36dExit if port has no task.
  4099.  
  4100. @36dGet port's flag bits.
  4101. @d
  4102. @36dDecode the flag bits.
  4103. @d
  4104. @d
  4105.  
  4106.         ; Processing for PA_SOFTINT
  4107.  
  4108. @d
  4109. @36dCause the software interrupt.
  4110. @d
  4111.  
  4112.         ; If PA_IGNORE, do nothing.
  4113.  
  4114. @d
  4115. @d
  4116.  
  4117.         ; (Undocumented?) processing for mp_Flags = 3.  Apparently,
  4118.         ; calls a subroutine at mp_SigTask.
  4119.  
  4120. @d
  4121. @d
  4122. @d
  4123.  
  4124.         ; Processing for PA_SIGNAL
  4125.  
  4126. @36dGet SigBit.
  4127. @d
  4128. @36dCompute corresponding signal mask.
  4129. @d
  4130. @d
  4131. @36dSignal the task.
  4132.  
  4133. @36dEnable()
  4134. @d
  4135. @d
  4136. @d
  4137.  
  4138.  
  4139. ---------------------------------------------------------------------------
  4140.   message = GetMsg( port )
  4141.   D0                A0
  4142. ---------------------------------------------------------------------------
  4143.  
  4144. @36dPoint A0 at head of port's message list.
  4145.  
  4146. @36dDisable()
  4147. @d
  4148.  
  4149.         ; Try to dequeue a message from the message list.
  4150.  
  4151. @36dGet head pointer into A1.
  4152. @d
  4153. @36dIf list is empty, just return zero.
  4154. @d
  4155. @36dUnlink the message from the list.
  4156. @d
  4157.  
  4158.         ; Reenable interrupts if necessary and exit.
  4159.  
  4160. @36dEnable()
  4161. @d
  4162. @d
  4163. @d
  4164.  
  4165.  
  4166. ---------------------------------------------------------------------------
  4167.   ReplyMsg( message )
  4168.             A1
  4169. ---------------------------------------------------------------------------
  4170.  
  4171. @36dGet address of reply port.
  4172. @d
  4173. @36dNo reply port.  Set node type to
  4174. @36dNT_FREEMSG and exit.
  4175.  
  4176. @36dSet node type to NT_REPLYMSG.
  4177. @d
  4178. @36dSend the message via the reply port.
  4179.  
  4180.  
  4181. ---------------------------------------------------------------------------
  4182.   message = WaitPort( port )
  4183.   D0                  A0
  4184. ---------------------------------------------------------------------------
  4185.  
  4186. @36dGet head pointer of port's message list.
  4187. @36dCheck if list is empty.
  4188. @36dIf not empty, return right away.
  4189.  
  4190. @36dList was empty.  Get signal bit.
  4191. @36dPoint A0 at message list.
  4192. @d
  4193. @36dCompute signal mask.
  4194. @d
  4195. @d
  4196. @36dWait()
  4197. @d
  4198. @36dCheck message list.
  4199. @36dIf still empty, go back and wait again.
  4200. @d
  4201. @36dReturn first message in the list.
  4202. @d
  4203.  
  4204.  
  4205. ---------------------------------------------------------------------------
  4206.   port = FindPort( name )
  4207.   D0               A1
  4208. ---------------------------------------------------------------------------
  4209.  
  4210. @36dPoint to the public port list.
  4211. @36dSearch it for a port of the given name.
  4212. @d
  4213.  
  4214.  
  4215. ---------------------------------------------------------------------------
  4216.   AddResource( resource )
  4217.                A1
  4218. ---------------------------------------------------------------------------
  4219.  
  4220. @36dPoint to the resource list.
  4221. @36dAdd the resource to the list.
  4222.  
  4223.  
  4224. ---------------------------------------------------------------------------
  4225.   RemResource( resource )
  4226.                A1
  4227. ---------------------------------------------------------------------------
  4228.  
  4229. @36dUnlink the resource from the list.
  4230.  
  4231.  
  4232. ---------------------------------------------------------------------------
  4233.   resource = OpenResource( resName )
  4234.   D0                       A1
  4235. ---------------------------------------------------------------------------
  4236.  
  4237. @36dPoint to the resource list.
  4238. @36dForbid()
  4239. @36dFindName()
  4240. @36dPermit()
  4241. @d
  4242.  
  4243.  
  4244. @8p@28wPadding.
  4245.  
  4246. ---------------------------------------------------------------------------
  4247.   AddTask( task, initialPC, finalPC )
  4248.            A1    A2         A3
  4249. ---------------------------------------------------------------------------
  4250.  
  4251. @d
  4252. @36dMake the task state TS_ADDED.
  4253. @36dClear the task's flags.
  4254. @36dSet IDNestCnt and TDNestCnt to -1.
  4255. @d
  4256. @36dTask is not waiting for any signals.
  4257. @36dTask has not received any signals.
  4258. @36dTask does not have any exception signals.
  4259. @36dSet allocated traps.
  4260. @36dNo traps are enabled.
  4261.  
  4262. @36dInstall default system exception handler
  4263. @36dif the user has not provided one.
  4264. @d
  4265. @d
  4266. @d
  4267. @d
  4268.  
  4269. @36dGet the initial stack pointer.
  4270. @36dPut the exit code address on the stack.
  4271. @d
  4272. @36dUse system default if no exit code.
  4273.  
  4274. @36dClear 15 longwords below the process's
  4275. @36dinitial stack pointer, so all registers
  4276. @36dwill be zero when initially loaded.
  4277.  
  4278. @36dClear the initial status register.
  4279. @36dPut the initial PC on the stack.
  4280.  
  4281. @36dIf we have a 68881, then put another
  4282. @36dlongword on the stack.
  4283. @d
  4284. @d
  4285. @36dPut the initial stack pointer back.
  4286.  
  4287. @d
  4288. @36dDisable()
  4289. @d
  4290. @36dMake the task state TS_READY.
  4291. @36dPut the task on the TaskReady queue.
  4292. @d
  4293. @36dEnable()
  4294. @d
  4295. @d
  4296. @36dIf the task ended up at the front of the
  4297. @36dTaskReady queue, then
  4298. @36dReschedule()
  4299. @d
  4300.  
  4301.         ; System default task exit function
  4302.         ; ---------------------------------
  4303.  
  4304. @36dGet ExecBase.
  4305. @d
  4306. @36dAsk for current task to be removed.
  4307.  
  4308.         ; fall through into RemTask.
  4309.  
  4310.  
  4311. ---------------------------------------------------------------------------
  4312.   RemTask( task )
  4313.            A1
  4314. ---------------------------------------------------------------------------
  4315.  
  4316. @d
  4317. @36dCheck address of task to be removed.
  4318. @36dBranch if not zero.
  4319. @36dIf zero, use the current task.
  4320. @d
  4321. @36dIf not zero, check if it was the current
  4322. @36dtask anyway.
  4323.  
  4324.         ; The following is executed only if the task to be removed is not
  4325.         ; the current one.  This is because the currently running task isn't
  4326.         ; on a queue anywhere.
  4327.  
  4328. @36dDisable()
  4329. @d
  4330. @36dUnlink the task from its queue.
  4331. @d
  4332. @36dEnable()
  4333. @d
  4334.  
  4335. @36dGet the address of the task back.
  4336. @36dMake the task TS_REMOVED.
  4337. @36dCheck if it is the current task.
  4338. @d
  4339. @36dIf so, disable task switching now.
  4340.  
  4341. @36dPoint to allocated memory list.
  4342. @d
  4343. @36dExit if the head pointer is zero,
  4344. @36dor if the tail pointer points back at
  4345. @36dthe list header.
  4346. @36dZero the list head pointer.
  4347.  
  4348.         ; Loop:  Release all the memory blocks which the task had allocated.
  4349.  
  4350. @36dGet pointer to current list node.
  4351. @36dGet pointer to next list node.
  4352. @36dExit if the end of the list was reached.
  4353. @36dFreeEntry() this list node.
  4354. @36dBack to the head of the loop.
  4355.  
  4356. @36dCheck if the current task was removed.
  4357. @36dIf not, indicate success and exit.
  4358. @d
  4359. @36dGo to supervisor mode.
  4360. @36dPop exception data from the stack.
  4361. @36dDispatch() a new task.
  4362.  
  4363. @36dIf the current task was not removed,
  4364. @36dindicate success and return.
  4365. @d
  4366.  
  4367.  
  4368. ---------------------------------------------------------------------------
  4369.   task = FindTask( name )
  4370.   D0               A1
  4371. ---------------------------------------------------------------------------
  4372.  
  4373. @36dSee if a name was given.
  4374. @d
  4375. @36dIf not, use this task.
  4376. @d
  4377. @36dPoint at the TaskReady queue.
  4378. @36dDisable()
  4379. @d
  4380. @36dCall FindName() to look for the task.
  4381. @36dCheck if found, return address if so.
  4382. @d
  4383. @36dTask not found, try TaskWait queue.
  4384. @36dCall FindName() to look for the task.
  4385. @36dCheck if found, return address if so.
  4386. @d
  4387. @36dStill not found, compare name with that
  4388. @36dof the current task.
  4389. @d
  4390. @36dIf names differ, return zero (not found).
  4391. @d
  4392. @d
  4393. @36dTask was the current task.
  4394. @36dEnable()
  4395. @d
  4396. @d
  4397. @d
  4398.  
  4399.  
  4400. ---------------------------------------------------------------------------
  4401.   oldPriority = SetTaskPri( task, priority )
  4402.   D0                        A1    D0
  4403. ---------------------------------------------------------------------------
  4404.  
  4405. @36dDisable()
  4406. @d
  4407. @36dSave the task's current priority.
  4408. @36dSet the task's new priority.
  4409. @36dCheck if it was the current task.
  4410. @36dIf so, go reschedule it.
  4411. @36dCheck if the task was TS_READY.
  4412. @36dIf not, we're done.
  4413. @d
  4414. @36dTake the task out of the TaskReady queue.
  4415. @d
  4416. @36dAnd put it back in the right place
  4417. @36dcorresponding to its new priority.
  4418. @36dSee if it ended up at the front.
  4419. @36dIf not, we're done.
  4420.  
  4421.         ; If we get here, either we've changed the priority of the current
  4422.         ; task, or we've moved another task to the front of the TaskReady
  4423.         ; queue.  Either way, we have to check if the current task should
  4424.         ; be preempted.
  4425.  
  4426. @36dReschedule()
  4427. @d
  4428. @36dEnable()
  4429. @d
  4430. @d
  4431. @36dReturn the previous priority.
  4432. @d
  4433.  
  4434.  
  4435. ---------------------------------------------------------------------------
  4436.   oldSignals = SetExcept( newSignals, signalMask )
  4437.   D0                      D0          D1
  4438. ---------------------------------------------------------------------------
  4439.  
  4440. @36dGet pointer to current task.
  4441. @36dPoint to its SigExcept longword.
  4442. @36dDrop into SetSignal.
  4443.  
  4444.  
  4445. ---------------------------------------------------------------------------
  4446.   oldSignals = SetSignal( newSignals, signalMask )
  4447.   D0                      D0          D1
  4448. ---------------------------------------------------------------------------
  4449.  
  4450. @36dGet pointer to current task.
  4451. @36dPoint to its SigRecvd longword.
  4452.  
  4453.         ; This code is common to SetExcept and SetSignal.
  4454.  
  4455. @36dMask out signals to be left alone.
  4456. @36dDisable()
  4457. @d
  4458. @36dSave current value of signal word.
  4459. @36dMake mask of singnals to leave alone.
  4460. @36dGet those signals only.
  4461. @36dOr in the changed signals.
  4462. @36dPut the result back in the task.
  4463.  
  4464.         ; Now we drop into Signal(), which will process any new signals
  4465.         ; we may have set in the SigRecvd longword.
  4466.  
  4467. @36dGet the SigRecvd data.
  4468. @36dDrop into Signal.
  4469.  
  4470.  
  4471. ---------------------------------------------------------------------------
  4472.   Signal( task, signals )
  4473.           A1    D0
  4474. ---------------------------------------------------------------------------
  4475.  
  4476. @36dGet the set of received signals.
  4477. @36dDisable()
  4478. @d
  4479. @36dStore the signals.
  4480. @36dOr the new signals into the old ones.
  4481.  
  4482.         ; The code from here down is common to SetExcept, SetSignal, and
  4483.         ; Signal.  It checks if the task whose signals are being modified
  4484.         ; should be awakened.
  4485.  
  4486. @36dCheck the exception signals,
  4487. @36dand see if any of them have become set.
  4488. @36dIf so, go process them.
  4489. @36dSee if the task is in the TS_WAIT state.
  4490. @36dIf not, we're done.
  4491. @36dSee if a signal being waited for has been
  4492. @36dset.  If not, we are done.
  4493.  
  4494.         ; We have set a signal which the task was currently waiting for,
  4495.         ; so we must awaken it.  First, we take it out of the TaskWait
  4496.         ; list then we make it TS_READY, then we put it on the TaskReady
  4497.         ; queue and check if it should preempt the current task.
  4498.  
  4499. @d
  4500. @36dSave pointer to the task.
  4501. @36dGet pointer to the next task in the list.
  4502. @36dGet pointer to the previous task.
  4503. @36dUnlink from the previous task.
  4504. @36dUnlink from the next task.
  4505. @36dRestore pointer to the task.
  4506. @36dMake the task TS_READY.
  4507. @36dPoint to the TaskReady queue.
  4508. @36dEnqueue the task in the right place.
  4509. @36dCheck if it was put at the head of the
  4510. @36dTaskReady queue, and exit if not.
  4511. @d
  4512. @36dEnable()
  4513. @d
  4514. @36dReturn old signals to caller eventually.
  4515. @36dReschedule() so the task can run.
  4516.  
  4517.         ; Enter here if we have set an exception signal, or if a previously
  4518.         ; set signal has become an exception signal.
  4519.  
  4520. @36dSet the task's TB_EXCEPT flag.
  4521. @36dSee if it is in the TS_WAIT state.
  4522.  
  4523.         ; If the task for which the exception occurred was in the TS_WAIT
  4524.         ; state, make it TS_READY and move it from the TaskWait list to
  4525.         ; the TaskReady queue.  Otherwise, just dispatch it.
  4526.  
  4527. @d
  4528. @d
  4529.  
  4530.         ; Exit here if the current task was allowed to keep running (i.e.
  4531.         ; the other task did not preempt it).
  4532.  
  4533. @36dEnable()
  4534. @d
  4535. @d
  4536. @36dReturn old signals.
  4537. @d
  4538.  
  4539.  
  4540. ---------------------------------------------------------------------------
  4541.   signals = Wait( signalSet )
  4542.   D0              D0
  4543. ---------------------------------------------------------------------------
  4544.  
  4545. @36dGet the pointer to the current task.
  4546. @36dRecord which signals we are waiting for.
  4547. @36dDisable()
  4548. @d
  4549. @36dEnter the loop at the bottom.
  4550.  
  4551.         ; Main loop:  We stay here until we have a signal we want.
  4552.  
  4553. @36dMake the task state TS_WAIT.
  4554. @36dPoint to the TaskWait list.
  4555. @d
  4556. @36dUnlink the task from the TaskReady
  4557. @36dqueue, and put it in the TaskWait
  4558. @36dlist.
  4559. @d
  4560. @d
  4561. @d
  4562.  
  4563.         ; Here we block.  Calling Switch() gives control to any other
  4564.         ; process.  Eventually, someone else doing a Signal() will put us
  4565.         ; back on the TaskReady list, and then we will return from the
  4566.         ; Switch() when our priority comes up again.
  4567.  
  4568. @36dSave A5.
  4569. @36dGet ready to call Switch(), but first...
  4570. @36dEnter Supervisor mode.
  4571.  
  4572.         ; We're back.  See if we now have a signal we want.
  4573.  
  4574. @36dRestore A5.
  4575. @36dGet pointer to current process.
  4576. @36dGet the signals we are waiting for.
  4577.  
  4578.         ; We initially enter here to see if we have to block at all, and
  4579.         ; again each time we have been unblocked to see if we can now
  4580.         ; continue running.
  4581.  
  4582. @36dGet the signals which are currently set.
  4583. @36dCheck against signals to wait for.
  4584. @36dIf not, go back and block again.
  4585.  
  4586.         ; Eventually, we end up here.  We now have one or more signals
  4587.         ; that were being waited for.  We take these out of the set of
  4588.         ; received signals, since we will return them to the caller.
  4589.  
  4590. @36dUpdate the set of received signals.
  4591. @d
  4592. @36dEnable()
  4593. @d
  4594. @36dReturn the signals.
  4595. @d
  4596.  
  4597.  
  4598. ---------------------------------------------------------------------------
  4599.   Reschedule()
  4600. ---------------------------------------------------------------------------
  4601.  
  4602.         ; This function is used when it is possible that a task should
  4603.         ; be preempted and another task run in its place.  It sets the
  4604.         ; scheduling attention flag to force the scheduler to do its thing
  4605.         ; as soon as possible.  If multitasking is disabled, that's all
  4606.         ; it does, since Permit() will do the rest when multitasking is
  4607.         ; turned on again.  If interrupts are disabled, it sets the software
  4608.         ; generated interrupt.  Since this is not accompanied by setting
  4609.         ; the software interrupt pending flag, it will do nothing but
  4610.         ; run ExitIntr() as soon as the interrupt level allows it.
  4611.         ; ExitIntr() will then cause the outstanding scheduling operation
  4612.         ; to be done.
  4613.  
  4614.         ; Note that part of Permit() is used to switch into supervisor
  4615.         ; mode and call the scheduler.
  4616.  
  4617. @36dSet the scheduling attention flag.
  4618. @36dSave its previous state.
  4619. @36dCheck if multitasking enabled.
  4620. @36dIf not, exit.
  4621. @36dCheck if interrupts enabled.
  4622. @36dIf so, go and do the scheduling.
  4623. @36dCheck the (old) scheduling attn flag.
  4624. @36dExit if it was already set.
  4625. @36dAssert the software generated interrupt.
  4626. @d
  4627.  
  4628.  
  4629. ---------------------------------------------------------------------------
  4630.   Forbid()
  4631. ---------------------------------------------------------------------------
  4632.  
  4633. @36dIncrement the TDNestCnt.
  4634. @d
  4635.  
  4636.  
  4637. ---------------------------------------------------------------------------
  4638.   Permit()
  4639. ---------------------------------------------------------------------------
  4640.  
  4641. @36dDecrement the TDNestCnt.
  4642. @36dExit if still positive.
  4643. @36dCheck if interrupts disabled.
  4644. @36dExit if yes.
  4645.  
  4646.         ; The current task has just reenabled multitasking.  If the system
  4647.         ; is waiting to switch tasks, now is the time to do it.
  4648.  
  4649. @36dCheck the scheduling attention flag.
  4650. @36dExit if not pending.
  4651. @36dSave A5.
  4652. @36dSet address to go to in supervisor mode.
  4653. @36dEnter supervisor mode.
  4654. @36dRestore A5 and return.
  4655. @d
  4656.  
  4657.         ; This is executed in supervisor mode.
  4658.  
  4659. @36dCheck caller's supervisor mode flag.
  4660. @36dIf the caller was in supervisor mode,
  4661. @36dthen don't switch tasks.
  4662.  
  4663.         ; Eventually, this task will be dispatched again, using the program
  4664.         ; counter and status register left on the stack by the supervisor
  4665.         ; mode call.  Then it continues running above, pops A5 from the
  4666.         ; stack, and returns to the caller.
  4667.  
  4668. @36dGo and do the scheduling.
  4669.  
  4670.  
  4671. ---------------------------------------------------------------------------
  4672.   trapNum = AllocTrap( trapNum )
  4673.   D0                   D0
  4674. ---------------------------------------------------------------------------
  4675.  
  4676. @36dGet pointer to the current task.
  4677. @36dGet the task's TrapAlloc flags.
  4678. @36dSee if we want a particular trap number.
  4679. @d
  4680. @36dIf so, set this trap number's flag bit.
  4681. @36dIf it wasn't set, indicate success.
  4682. @36dIt was already set, indicate failure.
  4683.  
  4684.         ; Look for a free trap number.
  4685.  
  4686. @36d16 traps to check.  Start at #15.
  4687. @36dTry to set this trap's flag bit.
  4688. @36dIf not set before, indicate success.
  4689. @36dLoop until all flags checked.
  4690. @36dIndicate failure.
  4691. @36dPut updated trap flags back.
  4692. @d
  4693.  
  4694.  
  4695. ---------------------------------------------------------------------------
  4696.   FreeTrap( trapNum )
  4697.             D0
  4698. ---------------------------------------------------------------------------
  4699.  
  4700. @36dGet pointer to the current task.
  4701. @36dGet the task's TrapAlloc flags.
  4702. @36dClear the specified flag.
  4703. @36dPut the flags back.
  4704. @d
  4705.  
  4706.  
  4707. ---------------------------------------------------------------------------
  4708.   signalNum = AllocSignal( signalNum )
  4709.   D0                       D0
  4710. ---------------------------------------------------------------------------
  4711.  
  4712. @36dGet pointer to the current task.
  4713. @36dGet the task's SigAlloc flags.
  4714. @36dSee if we want a particular signal.
  4715. @d
  4716. @36dIf so, try to set its flag.
  4717. @36dIndicate success if it was clear.
  4718. @36dIndicate failure if already set.
  4719.  
  4720.         ; Look for a free signal.
  4721.  
  4722. @36d32 Signals to check.  Start at 31.
  4723. @36dTry to set the signal's flag.
  4724. @36dIf it wasn't already set, success.
  4725. @36dOtherwise, keep looking.
  4726. @36dIndicate failure.
  4727. @d
  4728.  
  4729. @36dSuccess.  Update allocated signal flags.
  4730. @d
  4731. @36dSet all but this signal bit in D1.
  4732. @36dMake sure this signal isn't set.
  4733. @36dMake sure it's not an exception signal.
  4734. @36dIndicate that we are not waiting for it.
  4735. @d
  4736.  
  4737.  
  4738. ---------------------------------------------------------------------------
  4739.   FreeSignal( signalNum )
  4740.               D0
  4741. ---------------------------------------------------------------------------
  4742.  
  4743. @36dGet pointer to the current task.
  4744. @36dGet the SigAlloc flags.
  4745. @36dClear the indicated signal bit.
  4746. @36dPut the flags back.
  4747. @d
  4748.  
  4749.  
  4750.         ; Subroutines for RawDoFmt()
  4751.         ; --------------------------
  4752.  
  4753.         ; Find the length of a null-terminated string pointed to by A0.
  4754.         ; For efficiency, the length is counted up as a negative number.
  4755.  
  4756. @a?fc200c
  4757. @40dStart the length at -1.
  4758. @40dGet string character, test for end.
  4759. @40dCount, and loop until end of string.
  4760. @d
  4761. @40dConvert length to correct +ve value.
  4762. @d
  4763.  
  4764.  
  4765.         ; Evaluate a decimal numeric constant pointed to by A4.
  4766.  
  4767. @40dStart the result at 0.
  4768. @d
  4769. @40dGet a character from the input.
  4770. @a?fc2020
  4771. FC2020  cmp.b     #'0',D2
  4772. @a=fc2024
  4773. @d
  4774. FC2026  cmp.b     #'9',D2               If not a numeric digit, exit.
  4775. @a=fc202a
  4776. @d
  4777. @40dMultiply previous result by 10.
  4778. @d
  4779. @d
  4780. @d
  4781. @d
  4782. @a?fc2036
  4783. FC2036  sub.b     #'0',D2               Convert digit to number 0 - 9.
  4784. @a=fc203a
  4785. @40dAdd to result.
  4786. @40dGo evaluate next character.
  4787.  
  4788.         ; Finish up by pointing back at the non-digit character.
  4789.  
  4790. @40dBackspace the input pointer.
  4791. @d
  4792.  
  4793.  
  4794.         ; Convert the number in D4 to its decimal ASCII representation.
  4795.  
  4796. @40dIs the number zero?
  4797. @40dIf so, just output "0" and return.
  4798. @40dIs it negative?
  4799. @40dIf not, make it negative.
  4800. @d
  4801. @a?fc204c
  4802. FC204C  move.b    #'-',(A5)+            If so, output a "-".
  4803. @a=fc2050
  4804.  
  4805.         ; The minus sign is taken care of, and negative the number to
  4806.         ; be output is in D4.
  4807.  
  4808. @40dPoint at table of divisors.
  4809. @40dClear the "non-zero digit" flag.
  4810.  
  4811. @40dGet a divisor from the table.
  4812. @40dIf zero, output last digit and exit.
  4813.  
  4814.         ; Subtract the current divisor from the number as many times as
  4815.         ; possible (actually, add to its negative).
  4816.  
  4817. @40dStart the counter at -1.
  4818. @40dTry to add the divisor to D4.
  4819. @40dLoop until D4 is greater than zero.
  4820. @40dMake the number less than zero again.
  4821. @40dIncrement the counter by 1.
  4822.  
  4823.         ; D0 now contains negative the current digit to output.  Discard
  4824.         ; it if it is a leading zero.
  4825.  
  4826. @40dIf the current digit is zero then
  4827. @40dif no non zero digits have been
  4828. @40doutput, then discard it.
  4829.  
  4830.         ; Output the digit.
  4831.  
  4832. @40dSet "non-zero digit" flag.
  4833. @40dMake D0 positive.
  4834. @a?fc2072
  4835. FC2076  add.b     #'0',D0               Convert to an ASCII digit.
  4836. @a=fc2076
  4837. @40dPut it into the buffer.
  4838. @40dGo do the next digit.
  4839.  
  4840.         ; Enter here to output the last digit, or the single "0" if the
  4841.         ; number is zero.
  4842.  
  4843. @40dMake D0 positive.
  4844. @a?fc207c
  4845. FC207C  add.b     #'0',D4               Convert to an ASCII digit.
  4846. @a=fc2080
  4847. @40dPut it into the buffer.
  4848. @d
  4849.  
  4850.  
  4851.         ; Table of divisors.
  4852.  
  4853. @8p@32l1000000000 decimal.
  4854. @8p@33l100000000 decimal.
  4855. @8p@34l10000000 decimal.
  4856. @8p@35l1000000 decimal.
  4857. @8p@36l100000 decimal.
  4858. @8p@37l10000 decimal.
  4859. @8p@38l1000 decimal.
  4860. @8p@39l100 decimal.
  4861. @8p@40l10 decimal.
  4862. @8p@41l0 decimal.
  4863.  
  4864.  
  4865.         ; Convert the number in D4 to its hexadecimal ASCII representation.
  4866.  
  4867. @a?fc20ac
  4868. @40dIs the number zero?
  4869. @40dIf so, just output "0" and exit.
  4870. @40dClear "non-zero digit" flag.
  4871. @40dIs the data 32 bits long?
  4872. @d
  4873. @40dIf not, output 4 digits,
  4874. @40dfrom the high word of D4.
  4875. @d
  4876. @40dIf so, output 8 digits.
  4877.  
  4878.         ; Digit output loop.
  4879.  
  4880. @40dRotate leftmost digit into bits 0-3.
  4881. @d
  4882. @40dMask out all but bits 0-3.
  4883.  
  4884.         ; Skip leading zeros.
  4885.  
  4886. @40dIf no non-zero digit has been
  4887. @40dencountered yet, and this is a zero,
  4888. @40dskip it.
  4889.  
  4890. @40dSet "non-zero digit" flag.
  4891. @40dIs the digit greater than 9?
  4892. @d
  4893. @a?fc20d6
  4894. FC20D6  add.b     #'0',D0               If not, convert to ASCII numeral.
  4895. @a=fc20DA
  4896. @d
  4897. FC20DC  add.b     #$37,D0               If so, convert to upper case letter.
  4898. @a=fc20e0
  4899. @40dPut digit in buffer.
  4900. @40dLoop until all digits done.
  4901. @d
  4902.  
  4903.  
  4904. ---------------------------------------------------------------------------
  4905.   RawDoFmt( FormatString, DataStream, PutChProc, PutChData )
  4906.             A0            A1          A2         A3
  4907. ---------------------------------------------------------------------------
  4908.  
  4909. @d
  4910. @40dReserve stack space for buffer.
  4911. @40dStore data stream pointer.
  4912. @40dPoint to the format string.
  4913. @40dGet a byte from the format string.
  4914. @40dCheck for end and exit if found.
  4915. @a?fc20f8
  4916. FC20F8  cmp.b     #'%',D0               Check for format specifier.
  4917. @a=fc20fc
  4918. @40dProcess it if found.
  4919. @40dOtherwise, output the character,
  4920. @40dand go on to the next one.
  4921. @40dOutput the terminating zero.
  4922. @40dDeallocate the output buffer.
  4923. @d
  4924. @d
  4925.  
  4926.         ; Enter here if the "%" format specifier was found.  Next we check
  4927.         ; for the characters "-", signaling that the printed item should
  4928.         ; be left-aligned in its field, and "0", signaling that leading
  4929.         ; zeros should be attached.
  4930.  
  4931. @40dPoint to the output buffer.
  4932. @40dClear the option flags.
  4933. @a?fc2112
  4934. FC2112  cmp.b     #'-',(A4)             Left alignment desired?
  4935. @a=fc2116
  4936. @d
  4937. @40dIf so, set the corresponding flag,
  4938. @40dand go on to the next character.
  4939. FC211E  cmp.b     #'0',(A4)             Zero fill desired?
  4940. @a=fc2122
  4941. @d
  4942. @40dIf so, set the corresponding flag.
  4943. @40dGet the field width.
  4944. @40dStore it in D6.
  4945. @40dAssume no maximum length.
  4946. @a?fc2130
  4947. FC2130  cmp.b     #'.',(A4)             Maximum length specifier?
  4948. @a=fc2134
  4949. @d
  4950. @40dIf so, go on to the next character,
  4951. @40dand get the maximum length.
  4952. @40dStore maximum length.
  4953. FC213E  cmp.b     #'l',(A4)             32 bit data?
  4954. @a=fc2142
  4955. @d
  4956. @40dIf so, set the corresponding flag,
  4957. @40dand go on to the next character.
  4958.  
  4959.         ; At this point, we have interpreted a format string of the format
  4960.         ; "%-0xxx.yyyl".  In D3, bit 0 is set if the "-" was present, bit 1
  4961.         ; is set if the "0" was present, and bit 2 is set if the "l"
  4962.         ; was present.  D6 contains the value of "xxx" (numeric constant),
  4963.         ; and D5 contains the value of "yyy" if present, or 0 if not.
  4964.  
  4965.         ; Now we process the actual format characters: "s" for string, "c"
  4966.         ; for character, "d" for decimal, "x" for hex.  In all cases, the
  4967.         ; goal is to build a null-terminated string, pointed to by A0,
  4968.         ; containing the formatted output.
  4969.  
  4970. @40dGet the next character.
  4971. @a?fc214c
  4972. FC214C  cmp.b     #'d',D0               Decimal output?
  4973. @a=fc2150
  4974. @40dSkip to next option if not.
  4975. @40dGet data item.
  4976. @40dFormat as decimal number.
  4977. @40dOutput the buffer.
  4978. FC215A  cmp.b     #'x',D0               Hexadecimal output?
  4979. @a=fc215e
  4980. @40dSkip to next option if not.
  4981. @40dGet data item.
  4982. @40dFormat as hexadecimal number.
  4983. @40dOutput the buffer.
  4984.  
  4985.         ; Subroutine to get a number from the data stream.  We get either
  4986.         ; a word or a longword, depending on whether an "l" was in the
  4987.         ; format specification.
  4988.  
  4989. @40dIf data size is 16 bits then
  4990. @d
  4991. @40d  Get data stream pointer.
  4992. @40d  Get a word from the data stream.
  4993. @40d  Put data stream pointer back.
  4994. @40d  Extend to longword.
  4995. @40dElse
  4996. @40d  Get data stream pointer.
  4997. @40d  Get a longword from data stream.
  4998. @40d  Put data stream pointer back.
  4999. @40dEndif
  5000.  
  5001.         ; Continue here if not formatting a number.
  5002.  
  5003. @a?fc2188
  5004. FC2188  cmp.b     #'s',D0               String output?
  5005. @a=fc218c
  5006. @40dIf not, skip to next.
  5007. @40dGet data stream pointer.
  5008. @40dPoint directly at the string.
  5009. @40dPut data stream pointer back.
  5010. @40dOutput the string.
  5011. FC2196  cmp.b     #'c',D0               Single character output?
  5012. @a=fc219a
  5013. @40dIf not, discard format specifier.
  5014. @40dGet character from input stream.
  5015. @40dPut it into the buffer.
  5016.  
  5017.         ; Numeric and character output, having put their formatted argument
  5018.         ; into the buffer, meet here.
  5019.  
  5020. @40dZero-terminate the buffer.
  5021. @40dPoint back to its start.
  5022.  
  5023.         ; All output options continue here.  A5 now points to a
  5024.         ; null-terminated string to output.
  5025.  
  5026. @d
  5027. @40dFind the length of the string.
  5028. @40dWas a maximum length specified?
  5029. @d
  5030. @40dIf so, and if the output string is
  5031. @40dlonger, set the length to the
  5032. @40dmaximum length.
  5033. @40dCompute amount of padding needed.
  5034. @d
  5035. @40dSet to zero if negative.
  5036. @40dWas left alignment desired?
  5037. @d
  5038. @40dIf not, output padding first.
  5039. @d
  5040. @40dLoop to copy the string to the output
  5041. @40duntil its end or the given maximum
  5042. @40dnumber of characters.
  5043. @40dWas left alignment desired?
  5044. @d
  5045. @40dIf so, output padding now.
  5046. @40dContinue with format string.
  5047.  
  5048.  
  5049.         ; Subroutine to output the right amount of padding.
  5050.  
  5051. @a?fc21de
  5052. FC21DE  move.b    #' ',D2               Assume padding with spaces.
  5053. @a=fc21e2
  5054. @40dWas zero-fill desired?
  5055. @d
  5056. FC21E8  move.b    #'0',D2               If so, pad with zeros.
  5057. @a=fc21ec
  5058. @d
  5059. @40dLoop to output the required number
  5060. @40dof padding characters.
  5061. @d
  5062. @d
  5063.  
  5064.  
  5065. ---------------------------------------------------------------------------
  5066.   RawIOInit()
  5067. ---------------------------------------------------------------------------
  5068.  
  5069.         ; Set the serial port for receiving 8 bit data at 9600 bps.
  5070.  
  5071. @40dSet up the SERPER register.
  5072. @d
  5073.  
  5074.  
  5075. ---------------------------------------------------------------------------
  5076.   RawMayGetChar()
  5077. ---------------------------------------------------------------------------
  5078.  
  5079. @d
  5080. @40dRead SERDATR.
  5081. @40dIs a byte in the receive buffer?
  5082. @40dIf not, return -1 and exit.
  5083. @40dClear the serial receive interrupt.
  5084. @40dGet the received character.
  5085. @40dReturn it to the caller.
  5086. @d
  5087.  
  5088.  
  5089.         ; Subroutine to wait for a character on the serial port.
  5090.  
  5091. @40dRawMayGetChar()
  5092. @40dDid we get a character?
  5093. @40dContinue waiting if not.
  5094. @40dReturn the character.
  5095.  
  5096.  
  5097.         ; This looks like a C entry point for RawPutChar.
  5098.  
  5099. @40dGet the first C parameter.
  5100.  
  5101. ---------------------------------------------------------------------------
  5102.   RawPutChar()
  5103. ---------------------------------------------------------------------------
  5104.  
  5105.         ; Don't output code 0, and expand newlines to CRLF.
  5106.  
  5107. @40dIs the character to send zero?
  5108. @40dIf so, don't send it.
  5109. @40dSave the character.
  5110. @40dIs it a newline?
  5111. @d
  5112. @40dIf so, send a carriage return first.
  5113. @d
  5114. @40dGet the character back.
  5115.  
  5116.         ; Enter here to send the character in D0 on the serial port.
  5117.  
  5118. @40dRead SERDATR.
  5119. @40dTransmitter ready?
  5120. @40dWait until true.
  5121.  
  5122. @40dMask out all but bits 0-7.
  5123. @40dSet the stop bit.
  5124. @40dWrite to SERDAT.
  5125.  
  5126.         ; Handle XON/XOFF and/or escape into the debugger if DEL pressed.
  5127.  
  5128. @40dRawMayGetChar()
  5129. @40dDid we get an XOFF?
  5130. @d
  5131. @40dIf yes, wait for any other character.
  5132. @d
  5133. @40dDid we get a DEL?
  5134. @40dReturn if not.
  5135. @40dIf so, Debug()
  5136. @40dOn return, check for XOFF again.
  5137. @d
  5138.  
  5139.  
  5140.         ; C compatible routine to print a string.
  5141.  
  5142. @40dGet first C parameter (string addr.)
  5143.  
  5144.         ; Assembly language entry point (address in A0).
  5145.  
  5146. @40dGet a string character.
  5147. @40dExit if is the terminating zero.
  5148. @40dIs it a newline?
  5149. @d
  5150. @40dIf so, output a CR first.
  5151. @d
  5152. @d
  5153. @40dOutput the character.
  5154. @40dGo on to next character.
  5155. @d
  5156.  
  5157.  
  5158.         ; C compatible function to output a hex number.  First argument
  5159.         ; is the number, second one is the number of digits.  The number
  5160.         ; will be output with one space following.
  5161.  
  5162. @40dGet C parameters.
  5163.  
  5164.         ; Assembly language entry point.
  5165.  
  5166. @d
  5167. @d
  5168. @d
  5169. @40dCompute 8 - number of digits.
  5170. @40dLoop that many times, rotating the
  5171. @40dnumber left by a digit each time,
  5172. @40dto left-align the number in D2.
  5173.  
  5174. @40dGet number of digits.
  5175. @d
  5176. @40dShift current digit into bits 0-3.
  5177. @d
  5178. @40dExtract bits 0-3 from the number.
  5179. @40dNumeric or alphabetic digit?
  5180. @d
  5181. @40dIf alphabetic, add ('A'-'9').
  5182. @a?fc22ba
  5183. FC22BA  add.b     #'0',D0               Convert to ASCII digit.
  5184. @a=fc22be
  5185. @40dOutput the digit.
  5186. @40dLoop until all digits done.
  5187. @d
  5188. @40dOutput a space.
  5189. @d
  5190. @d
  5191.  
  5192.  
  5193.         ; Entry point to do a RawDoFmt() to the serial port.
  5194.  
  5195. @40dSave A2.
  5196. @40dPoint A2 to RawPutChar() function.
  5197. @40dRawDoFmt()
  5198. @40dRestore A2.
  5199. @d
  5200.  
  5201.  
  5202. ---------------------------------------------------------------------------
  5203.   Open()
  5204. ---------------------------------------------------------------------------
  5205.  
  5206.         ; This gets executed if someone actually opens "exec.library".
  5207.  
  5208. @40dReturn ExecBase.
  5209. @40dIncrement exec.library open count.
  5210. @d
  5211.  
  5212.  
  5213. ---------------------------------------------------------------------------
  5214.   Close()
  5215. ---------------------------------------------------------------------------
  5216.  
  5217.         ; This gets executed if someone tries to close "exec.library".
  5218.  
  5219. @40dDecrement exec.library open count.
  5220.  
  5221.  
  5222. ---------------------------------------------------------------------------
  5223.   Expunge()
  5224. ---------------------------------------------------------------------------
  5225.  
  5226.         ; This gets executed if someone tries to Expunge() the exec.
  5227.         ; Needless to say, we won't do anything of the sort, but we'll make
  5228.         ; the caller happy by returning zero.
  5229.  
  5230.         ; The reserved jump vector (at ExecBase - 24) also points here.
  5231.  
  5232. @d
  5233. @d
  5234.  
  5235.  
  5236. @a?fc22f0
  5237.         ; ROM-Wack
  5238.         ; --------
  5239.  
  5240.         ; This is the Amiga's ROM resident mini-debugger.  The following
  5241.         ; string is sent out the serial port when it starts up.
  5242.  
  5243. @8p@,10s
  5244.  
  5245.         ; ROM-Wack has a private, 236 byte data area at $000200.  The
  5246.         ; following is a memory map of this area.  Addresses are given as
  5247.         ; hex offsets from $000200.
  5248.  
  5249.         ;-------------------------------------------------------------------
  5250.         ; 00  (32 bit)  Pointer to current key bindings.
  5251.         ; 04  (32 bit)  Saved key binding pointer if not using main ones.
  5252.         ; 08  (32 bit)  Value of last number entered by the user.
  5253.         ; 0C  (32 bit)  The "current address" for all operations.
  5254.         ; 10 - 13       (not used).
  5255.         ; 14  (32 bit)  The current "frame size".
  5256.         ; 18  (32 bit)  The upper limit address for searches and fills.
  5257.         ; 1C  (16 bit)  Number of characters in the input buffer.
  5258.         ; 1E  (8 bit)   Flag indicating whether the "frame" should be
  5259.         ;               redisplayed after a command has executed.
  5260.         ; 1F  (8 bit)   Flag indicating whether we are in "alter" mode.
  5261.         ; 20  (16 bit)  Flag indicating whether there is unprocessed data
  5262.         ;               in the buffer (0 if yes, 1 if no).
  5263.         ; 22  (16 bit)  Number of digits in the number most recently entered.
  5264.         ; 24  (16 bit)  Flag indicating whether a number is being gathered as
  5265.         ;               a parameter to a command, or being entered unprompted
  5266.         ;               (in which case it becomes the current address).
  5267.         ; 26  (32 bit)  Indirection stack pointer (for following pointers).
  5268.         ; 2A - 4F       (not used).
  5269.         ; 50 - 81       Input buffer for user commands.
  5270.         ; 82  (16 bit)  Last character typed by the user.
  5271.         ; 84  (32 bit)  Pointer to data area on the stack, holding CPU and
  5272.         ;               process related information (map farther down)
  5273.         ; 88  (16 bit)  Instruction to use for breakpoints (TRAP #15).
  5274.         ; 8A - E9       Breakpoint table.  Each entry consists of an address
  5275.         ;               where an instruction was replaced with TRAP #15, and
  5276.         ;               the word which had been there before.
  5277.         ; EA  (16 bit)  Value to be written to INTENA to restore serial
  5278.         ;               port interrupts to their original state.
  5279.         ;-------------------------------------------------------------------
  5280.  
  5281.  
  5282.         ; This gets called from the exec initialization code.
  5283.  
  5284. @40dSave ExecBase.
  5285. @40dPoint to ROM-Wack's data area.
  5286. @40dInitialize it.
  5287. @40dRestore ExecBase.
  5288. @40dInstall default ExecBase->DebugEntry.
  5289. @40dInstall default Debug() vector.
  5290. @40dRawIOInit()
  5291. @d
  5292.  
  5293.  
  5294.         ; Special exception handlers for ROM-Wack
  5295.         ; ---------------------------------------
  5296.  
  5297.         ; ROM-Wack trace exception handler.
  5298.  
  5299. @40dPush "Trace" exception number.
  5300. @40dEnter the debugger.
  5301.  
  5302.         ; ROM-Wack breakpoint exception handler.  A "TRAP #15" instruction
  5303.         ; is used for the breakpoint.
  5304.  
  5305. @40dPush "TRAP #15" exception number.
  5306. @40dEnter the debugger.
  5307.  
  5308. ---------------------------------------------------------------------------
  5309.   Debug()
  5310. ---------------------------------------------------------------------------
  5311.  
  5312.         ; This entry point is used when an actual function call to Debug()
  5313.         ; is made.  We set up the supervisor stack to look like it would
  5314.         ; after an exception handled by the exec exception entry points.
  5315.  
  5316. @40dSave A5.
  5317. @40dWhere to go in supervisor mode.
  5318. @40dSupervisor()
  5319.  
  5320.         ; We now have an exception stack frame from the Supervisor() call.
  5321.  
  5322. @40dPop the return address from the
  5323. @40dDebug() call from the user stack.
  5324. @d
  5325. @40dGet the return address back.
  5326. @40dFake exception number zero.
  5327.  
  5328.         ; Now the supervisor and user stacks look as if an exception had
  5329.         ; occurred and was handled by the exec, with the difference that
  5330.         ; the original value of A5 is on the supervisor stack, and A5 now
  5331.         ; contains the return address from the Debug() call.
  5332.  
  5333.  
  5334.         ; Exception entry point.
  5335.         ; ----------------------
  5336.  
  5337.         ; The debugger is entered here with the stacks already set up as
  5338.         ; above (by the system exception handler).  First, we verify if
  5339.         ; the stack is even working (pointing at RAM).
  5340.  
  5341. @40dPut a signature on the stack.
  5342. @40dCheck if it can be read back.
  5343. @d
  5344.  
  5345.         ; A signature pushed on the supervisor stack could not be read
  5346.         ; back, so we are in serious trouble.  Initialize the stack at
  5347.         ; the top of the first 256K of chip memory.  Put a fake exception
  5348.         ; stack frame on the new stack.
  5349.  
  5350. @40dStart stack at 256K.
  5351. @40dFake program counter.
  5352. @40dFake status register.
  5353. @40dPush exception number -1.
  5354. @d
  5355.  
  5356.         ; We now have a working supervisor stack with the exception
  5357.         ; number and stack frame on it.
  5358.  
  5359. @40dSave most of the CPU registers.
  5360. @40dPoint A5 at the exception number.
  5361. @40dReserve 22 bytes of stack space,
  5362. @40dand point A4 to the bottom of this.
  5363. @d
  5364. @40dGet the exception number.
  5365. @40dStore it.
  5366. @40dStore supervisor stack pointer.
  5367. @d
  5368. @40dStore user stack pointer.
  5369.  
  5370.         ; When a 680x0 hits an exception, it pushes the program counter, then
  5371.         ; the status register, onto the supervisor stack.  For bus and
  5372.         ; address errors, however, more information is saved.  On 68010 and
  5373.         ; 68020 processors, this comes before the program counter and status
  5374.         ; register, i.e. the stack pointer after an exception always points
  5375.         ; at these.  On the 68000, however, 8 bytes of other information
  5376.         ; are pushed on the stack AFTER the PC and SP.  The following code
  5377.         ; compensates for this.
  5378.  
  5379. @40dCheck CPU/FPP configuration.
  5380. @40dIs it a plain vanilla 68000?
  5381. @d
  5382. @40dWas it an address error?
  5383. @d
  5384. @40dWas it a bus error?
  5385. @d
  5386. @40dIf either, skip past bus error info.
  5387.  
  5388.         ; For all CPUs, A5 now points to where the status register and
  5389.         ; program counter are stored on the supervisor stack.
  5390.  
  5391. @40dCheck the supervisor mode bit.
  5392. @40dIf it was set,
  5393. @40dget ExecBase,
  5394. @40dand get the current task pointer.
  5395. @40dGet and store the status register.
  5396. @40dGet and store the program counter.
  5397.  
  5398.         ; Time for a summary (so I don't get confused).  A4 currently
  5399.         ; points at a data structure, on the supervisor stack, containing
  5400.         ; the following:
  5401.  
  5402.         ; (60 bytes) Register dump (D0-D7, A0-A6).
  5403.  
  5404.         ; (32 bit)   Current task pointer or zero.
  5405.         ; (32 bit)   Number of the exception that got us here (see below).
  5406.         ; (32 bit)   Saved supervisor stack pointer.
  5407.         ; (32 bit)   Saved user stack pointer.
  5408.         ; (16 bit)   Saved status register (from exception stack frame).
  5409.         ; (32 bit)   Saved program counter (from exception stack frame).
  5410.  
  5411.         ; If the exception number is zero, Debug() was used to get here.
  5412.  
  5413.         ; If the exception number is -1, we somehow got here, but the
  5414.         ; supervisor stack pointer was clobbered and not pointing to RAM.
  5415.         ; In this case, we have just set it to 256K, and the saved
  5416.         ; program counter and status register are invalid.
  5417.  
  5418. @40dPoint to ROM-Wack's data area.
  5419.  
  5420.         ; Disable serial port interrupts, and make a control word which,
  5421.         ; when written to INTENA, will return them to their original status.
  5422.  
  5423. @40dStore interrupt enable status.
  5424. @40dDisable serial port interrupts.
  5425. @d
  5426. @40dMake the control word to be used
  5427. @40dto restore those two interrupts.
  5428.  
  5429. @40dRawIOInit()
  5430. @d
  5431. @40dPrint a newline and "rom-wack".
  5432.  
  5433. @40dSave pointer to stack-resident data.
  5434. @40dMake the saved exception program
  5435. @40dcounter even (if not already so),
  5436. @40dand put it back.
  5437. @40dSet the "current address" there.
  5438. @40dDid a TRAP #15 get us here?
  5439. @40dSkip the following if not.
  5440.  
  5441.         ; Special handling for breakpoints.  Back the PC up by 2 (over
  5442.         ; the TRAP #15 instruction used for the breakpoint), and clear
  5443.         ; the breakpoint (restore the original instruction).
  5444.  
  5445. @40dBack up to breakpoint address.
  5446. @40d"clear" the breakpoint.
  5447.  
  5448. @40dUpdate the saved program counter.
  5449. @40dPoint to the stack-resident data.
  5450.  
  5451.         ; Install the exception vectors needed for breakpoints and
  5452.         ; single-stepping.
  5453.  
  5454. @40dInstall TRAP #15 exception vector.
  5455. @40dInstall "Trace" exception vector.
  5456. @40dSet the search limit to 16 megabytes.
  5457. @40dDisplay the ROM-Wack register frame.
  5458. @40dEnter the ROM-Wack main loop.
  5459.  
  5460.  
  5461.         ; Entry point for <Tab> command.
  5462.  
  5463.         ; Entry point to run a single instruction in trace mode.  This does
  5464.         ; everything required to resume running as below, but with the trace
  5465.         ; mode bit set in the saved status register, so only a single
  5466.         ; instruction will be executed after the RTE (and then we come back
  5467.         ; in at the top).
  5468.  
  5469. @40dPoint to data on system stack.
  5470. @40dGet the saved status register, set
  5471. @40dthe trace mode bit, and store it.
  5472. @d
  5473.  
  5474.         ; Set up to continue running after exit from ROM-Wack.  Note that
  5475.         ; to compensate for the different exception stack frame formats of
  5476.         ; bus error and regular exceptions, we don't even try to compensate
  5477.         ; for the format of the exception stack frame, just build one
  5478.         ; containing a simple status register and program counter right
  5479.         ; above the register dump.  This allows the RTE instruction to
  5480.         ; conveniently resume running whatever called ROM-Wack, but
  5481.         ; some garbage may be left on the stack.
  5482.  
  5483.         ; Entry point for "go" command.
  5484.  
  5485.         ; This starts running wherever the current address is pointing.
  5486.  
  5487. @40dPoint to data on system stack.
  5488. @40dMake PC the current address.
  5489.  
  5490.         ; Entry point for "^D" and "resume" commands.
  5491.  
  5492.         ; This continues running where it left off.
  5493.  
  5494. @d
  5495. @40dGet the saved status register.
  5496. @40dClear the trace mode flag and put
  5497.                                         it on the stack.
  5498. @40dRestore serial port interrupt status.
  5499. @40dPut the program counter on the stack.
  5500. @40dGet the saved user stack pointer,
  5501. @40dand restore it.
  5502. @40dPoint to the register dump.
  5503. @40dRestore all the other registers.
  5504. @40dPop the exception number.
  5505. @40dReturn from the exception.
  5506.  
  5507.  
  5508.         ; Subroutine to initialize ROM-Wack's data area.
  5509.  
  5510. @40dPoint to data area.
  5511. @d
  5512. @40dClear 236 bytes.
  5513. @d
  5514. @40dUse primary key bindings.
  5515. @40dFrame size = 16 bytes.
  5516. @40dUse "TRAP #15" for breakpoints.
  5517. @d
  5518.  
  5519. @8p@32wPadding.
  5520.  
  5521.         ; A lot of the functions in ROM-Wack have C compatible entry points
  5522.         ; (which get the parameters from the stack), and most of them have
  5523.         ; C compatible return values (in D0).  I guess this is to interface
  5524.         ; them to other functions, written in C, in the bigger versions of
  5525.         ; Wack.  Likewise, the following are probably C interface functions,
  5526.         ; but they (and most of the C entry points) aren't used anywhere.
  5527.  
  5528.  
  5529.         ; "Peek" function for C.  Takes address, returns 16-bit contents.
  5530.  
  5531. @a?fc2498
  5532. @d
  5533. @d
  5534. @d
  5535.  
  5536.         ; I have no idea why this is here twice.
  5537.  
  5538. @d
  5539. @d
  5540. @d
  5541.  
  5542.         ; "Poke" function for C.  Takes address and a word, and stores the
  5543.         ; word at the address given.
  5544.  
  5545. @d
  5546. @d
  5547. @d
  5548.  
  5549.  
  5550.         ; Entry point for "user" command.
  5551.  
  5552.         ; Takes all the data currently resident on the supervisor
  5553.         ; stack (exception stack frame, exception number, register dump,
  5554.         ; ROM-Wack data area, and any other stuff), and moves it onto the
  5555.         ; user stack.  Then puts the CPU into user mode.
  5556.  
  5557.         ; In effect, this switches ROM-Wack from running as part of the
  5558.         ; exec kernel (in supervisor mode) to running as a plain, ordinary
  5559.         ; task, along with other tasks.  The good side is that the system
  5560.         ; can now go and clean up (flush disk buffers, etc), while the
  5561.         ; user can go on playing with ROM-Wack.  The bad side is that the
  5562.         ; task which did Debug() or trapped into ROM-Wack is stuck there
  5563.         ; forever.  "go", and "resume" commands will no longer work.
  5564.  
  5565. @40dPoint to data area on stack.
  5566. @40dWas CPU in supervisor mode?
  5567. @40dIf not, exit.
  5568. @40dGet the user stack pointer.
  5569. @40dReserve 92 bytes on user stack.
  5570. @40dMake this the new data area.
  5571. @40dPoint to top of new data area.
  5572. @40dPoint to top of old data area.
  5573. @40dSave the supervisor stack pointer.
  5574. @d
  5575. @d
  5576. @40dCopy exception stack frame, register
  5577. @40ddump, data area, and any other stuff
  5578. @40dto the user stack.
  5579. @40dBump supervisor stack pointer up.
  5580. @40dBump user stack pointer down.
  5581. @d
  5582. @40dGet the saved status register.
  5583. @40dPrint a newline.
  5584. @d
  5585.  
  5586.  
  5587.         ; String compare function.  This checks if a command entered by
  5588.         ; the user, pointed to by A1, matches a command, pointed to by A0,
  5589.         ; from the command table.  It returns zero if so, else it returns
  5590.         ; the character number at which the mismatch occurred.
  5591.  
  5592.         ; C style entry point.
  5593.  
  5594. @d
  5595.  
  5596.         ; Assembler entry point.
  5597.  
  5598. @d
  5599. @40dGet a byte from reference string.
  5600. @40dEnd of string?
  5601. @40dCompare to byte from second string.
  5602. @40dLoop while strings are equal.
  5603. @40dCompute number of equal characters.
  5604. @40dExit.
  5605.  
  5606. @40dCheck if other string ends also.
  5607. @d
  5608. @40dReturn zero (strings match).
  5609. @d
  5610.  
  5611.  
  5612.         ; Entry point for <Return> command (Redisplay frame).
  5613.  
  5614. @40dRequest redisplay of current frame.
  5615. @d
  5616.  
  5617.  
  5618.         ; I don't know what this is for.  It's not referenced anywhere.
  5619.  
  5620. @d
  5621. @d
  5622. @d
  5623. @d
  5624.  
  5625.  
  5626.         ; Entry point for ">", <Space> commands (Move forward a word).
  5627.  
  5628. @40dIncrement current address by 1 word.
  5629. @40dRequest frame display.
  5630. @d
  5631. @d
  5632. @40dPrint a newline.
  5633. @d
  5634. @d
  5635. @d
  5636.  
  5637.  
  5638.         ; Entry point for "<", <Backspace> commands (Move back a word).
  5639.  
  5640. @40dDecrement current address by 1 word.
  5641. @40dRequest frame display.
  5642. @d
  5643. @d
  5644. @40dPrint a newline.
  5645. @d
  5646. @d
  5647. @d
  5648.  
  5649.  
  5650.         ; Entry point for "." command (move forward a frame).
  5651.  
  5652. @40dGet frame size.
  5653. @40dAdd to current address.
  5654. @40dRequest frame display.
  5655. @d
  5656.  
  5657.  
  5658.         ; Entry point for "," command (move back a frame).
  5659.  
  5660. @40dGet frame size.
  5661. @40dSubtract from current address.
  5662. @40dRequest frame display.
  5663. @d
  5664.  
  5665.  
  5666.         ; Entry point for "[" command.
  5667.  
  5668.         ; This follows a pointer at the current address.
  5669.  
  5670. @40dGet indirection stack pointer.
  5671. @40dGet current location.
  5672. @40dStore in indirection stack.
  5673. @40dPut indirection stack pointer back.
  5674. @40dMake the current location even.
  5675. @40dGet the pointer.
  5676. @40dPut it in the current location.
  5677. @40dRequest display of frame.
  5678. @d
  5679.  
  5680.  
  5681.         ; Entry point for "]" command.
  5682.  
  5683.         ; This walks undoes a "[" command, good for walking back along
  5684.         ; singly linked lists or backing out of nested structure pointers.
  5685.  
  5686. @40dGet indirection stack pointer.
  5687. @40dGet address from indirection stack.
  5688. @40dRequest frame display.
  5689. @40dUpdate the indirection stack pointer.
  5690. @d
  5691.  
  5692.  
  5693.         ; Entry point for "+" command.
  5694.  
  5695. @40dEcho "+" on the user's terminal.
  5696. @d
  5697. @40dRead a number from the keyboard.
  5698. @d
  5699. @40dIf none, print newline and exit.
  5700. @40dGet the number which was entered.
  5701. @40dAdd to current address.
  5702. @40dRequest frame redisplay.
  5703. @d
  5704.  
  5705.  
  5706.         ; Entry point for "-" command.
  5707.  
  5708. @40dEcho "-" on the user's terminal.
  5709. @d
  5710. @40dRead a number from the keyboard.
  5711. @d
  5712. @40dIf none, print newline and exit.
  5713. @40dGet the number which was entered.
  5714. @40dSubtract from the current address.
  5715. @40dRequest frame redisplay.
  5716. @d
  5717.  
  5718.  
  5719.         ; The following isn't referenced anywhere.  Perhaps an outdated
  5720.         ; bit of code to set the current address to the last number entered.
  5721.         ; This is now unnecessary.
  5722.  
  5723. @d
  5724. @d
  5725. @d
  5726.  
  5727.  
  5728.         ; Entry point for ":" command (set frame size).
  5729.  
  5730. @40dEcho ":" on the terminal.
  5731. @d
  5732. @40dGet a number from the terminal.
  5733. @40dSet the frame size.
  5734. @40dRequest frame redisplay.
  5735. @d
  5736.  
  5737.  
  5738.         ; Routine to print a prompt for memory-modify commands.
  5739.  
  5740. @40dGet the current address.
  5741. @40dPrint it (6 digits).
  5742. @40dIs the frame size zero?
  5743. @40dIf frame size is not zero, then
  5744. @d
  5745. @40d  Get word at current address.
  5746. @40d  Print it (4 digits).
  5747. @40d  Print "=".
  5748. @d
  5749. @40dElse
  5750. @40d  Print "xxxx ="
  5751. @40dEndif
  5752. @d
  5753.  
  5754.  
  5755.         ; Entry point for "=" command (modify one word of memory).
  5756.  
  5757.         ; This is also used by the "alter" routine below.  It returns 1
  5758.         ; if a value was entered, and 0 if not.
  5759.  
  5760. @40dPrint a prompt.
  5761. @40dGet a number from the terminal.
  5762. @40dDid we get one?
  5763. @d
  5764. @40dIf so, update the word pointed
  5765. @40dto by the current address with the
  5766. @40ddata which was entered, and return
  5767. @40da non-zero value.
  5768. @40dAre we in "alter" mode?
  5769. @d
  5770. @40dIf not, request frame redisplay.
  5771. @d
  5772.  
  5773. @8p@,8s
  5774.  
  5775.  
  5776.         ; Entry point for "alter" command.
  5777.  
  5778. @40dSet "alter mode" flag.
  5779. @40dPrint a newline.
  5780. @40dDo an "=" command.
  5781. @d
  5782. @40dIf a value was entered, increase the
  5783. @40dcurrent location by 2, and loop back.
  5784. @d
  5785.  
  5786. @40dClear "alter mode" flag.
  5787. @40dPrint a newline.
  5788. @d
  5789.  
  5790.  
  5791.         ; I don't know what this is for.  Perhaps a remnant from an old
  5792.         ; version of ROM-Wack, or something from a bigger version of Wack.
  5793.         ; It's not called from anywhere.
  5794.  
  5795. @a?fc2692
  5796. @40dPoint to the string below.
  5797. @40dPrint it.
  5798. @d
  5799.  
  5800. @8p@,22s
  5801.  
  5802.  
  5803.         ; Entry point for "list" command.
  5804.  
  5805.         ; This will traverse a standard exec list, displaying information
  5806.         ; about each node.  It should be called when the current address is
  5807.         ; either that of the list header, or of any node.
  5808.  
  5809. @d
  5810. @40dGet the current address.
  5811. @40dList header ("Tail" field zero)?
  5812. @d
  5813. @40dIf yes, go to first node.
  5814. @40dSee if now at end of list (or empty).
  5815. @40dIf no more nodes, exit.
  5816. @40dGet the node's name.
  5817. @40dIf name pointer is null, replace
  5818. @40dit with a pointer to a zero.
  5819. @40dSave name pointer on stack.
  5820. @d
  5821. @40dGet priority field.
  5822. @40dPut it on the stack.
  5823. @40dGet type field.
  5824. @40dPut it on the stack.
  5825. @40dPut node address to stack.
  5826. @40dPoint to data on stack.
  5827. @40dPoint to format string below.
  5828. @40dRawDoFmt() to serial port.
  5829. @40dPop data back off the stack.
  5830. @40dMove to next node.
  5831. @40dLoop until no more nodes.
  5832. @40dPrint a newline.
  5833. @d
  5834. @d
  5835.  
  5836. @a?fc26fc
  5837. @8p@,36s
  5838.  
  5839.  
  5840.         ; Subroutine to display a "frame" of data from memory.  On entry,
  5841.         ; the address of the frame is given in D0, and its size in D1.
  5842.  
  5843.         ; Data is displayed in lines of up to 8 words, and as an address,
  5844.         ; followed by hex words, followed by their ASCII character
  5845.         ; equivalents.
  5846.  
  5847. @d
  5848. @40dReserve 40 bytes of stack space.
  5849. @40dPrint a newline.
  5850. @d
  5851. @40dSet number of bytes remaining.
  5852. @40dJust exit if frame size is zero.
  5853.  
  5854.         ; Outer loop:  Display one line of the frame.
  5855.  
  5856. @a?fc2732
  5857. @d
  5858. @40dPrint the address.
  5859. @40dMaximum 8 words per line.
  5860. @40dPoint to reserved stack space.
  5861.  
  5862.         ; Inner loop:  Display one word of data.
  5863.  
  5864. @40dGet a word from memory.
  5865. @40dPrint it.
  5866. @d
  5867. @40dGet high 8 bits of current word.
  5868. @40dConvert to printable data.
  5869. @40dAdd to character string.
  5870. @d
  5871. @40dDo likewise for low 8 bits.
  5872. @d
  5873. @40dDecrement number of bytes remaining.
  5874. @40dExit if zero,
  5875. @40dotherwise continue until line full.
  5876.  
  5877.         ; End of line reached.
  5878.  
  5879. @40dMark end of character string.
  5880. @40dPoint to beginning.
  5881. @40dPrint the string and a newline.
  5882. @40dGo and do next line.
  5883.  
  5884.         ; End of frame reached.
  5885.  
  5886. @40dMark end of character string.
  5887. @40dPoint to beginning.
  5888. @40dPrint the string and a newline.
  5889. @d
  5890. @d
  5891. @d
  5892.  
  5893.  
  5894.         ; Subroutine to display an 8-digit hex number.
  5895.  
  5896. @d
  5897. @40d8 digits.
  5898. @d
  5899.  
  5900.  
  5901.         ; Subroutine to display a 6-digit hex number (address).
  5902.  
  5903. @d
  5904. @40d6 digits.
  5905. @d
  5906.  
  5907.  
  5908.         ; Subroutine to display a 4-digit hex number.
  5909.  
  5910. @d
  5911. @40d4 digits.
  5912. @40dGo print the number.
  5913. @d
  5914. @d
  5915.  
  5916.  
  5917.         ; Subroutine to print the "DR:", "AR:", and "SF:" portions of
  5918.         ; the ROM-Wack register frame.
  5919.  
  5920. @d
  5921. @d
  5922. @40d7 Data registers.
  5923. @40dPoint to "\nDR: " string.
  5924. @40dDisplay data registers.
  5925. @40d6 Address registers.
  5926. @40dPoint to "\nAR: " string.
  5927. @40dDisplay address registers.
  5928. @40dSkip exception number on stack.
  5929. @40dSupervisor mode?
  5930. @d
  5931. @40dIf not, get saved USP.
  5932. @d
  5933. @40dPoint to "\nSF: " string.
  5934. @40dPrint it.
  5935. @d
  5936. @40dDisplay 14 words of stack data.
  5937. @d
  5938. @d
  5939. @40dPrint a newline.
  5940. @d
  5941. @d
  5942.  
  5943.  
  5944.         ; Subroutine to print a string pointed to by A0, followed by (D2)
  5945.         ; longwords from memory pointed to by A2.
  5946.  
  5947. @40dPrint the string.
  5948. @d
  5949. @40dLoop and print all the data.
  5950. @d
  5951. @d
  5952.  
  5953.  
  5954.         ; Subroutine to print the first ("PC: ...") line of the register
  5955.         ; frame, followed by the rest of the register frame via the routine
  5956.         ; above.  Note, we just give RawDoFmt() a format string describing
  5957.         ; the data structure on the supervisor stack
  5958.  
  5959.         ; Also entry point for "regs" command.
  5960.  
  5961. @40dGet pointer to stack-resident data.
  5962. @d
  5963. @40dPoint to format string.
  5964. @40dFormat the data.
  5965. @d
  5966. @40dPoint to the register dump area.
  5967. @40dPrint it.
  5968.  
  5969.  
  5970.         ; Text strings used to display register frames.  The second one
  5971.         ; isn't used anywhere.
  5972.  
  5973. @a?fc27fc
  5974. @8p@,52s
  5975. @8p@,19s
  5976.  
  5977. @8p@,33s
  5978.  
  5979. @8p@,6s
  5980. @8p@,6s
  5981. @8p@,6s
  5982.  
  5983.  
  5984.         ; Memory fill routine.  Fills (D1) words, starting at (D0), with
  5985.         ; the value in D2.  Not used anywhere.
  5986.  
  5987. @d
  5988. @d
  5989. @d
  5990. @d
  5991. @d
  5992. @d
  5993. @d
  5994.  
  5995.  
  5996.         ; Subroutine to find a breakpoint in the breakpoint table, given
  5997.         ; its address.  If successful, returns address of breakpoint table
  5998.         ; entry, if not, returns zero.
  5999.  
  6000. @a?fc2886
  6001. @40dPrint a newline.
  6002. @40dPoint to breakpoint table.
  6003. @d
  6004. @40dScan breakpoint table for a
  6005. @40dbreakpoint address matching A1.
  6006. @d
  6007. @d
  6008. @40dNot found, so return zero.
  6009. @d
  6010. @40dReturn address of table entry.
  6011. @d
  6012.  
  6013.         ; Entry point for "clear" command.
  6014.  
  6015.         ; Deactivate the breakpoint at the current program address,
  6016.         ; if there is one.
  6017.  
  6018. @40dGet current address.
  6019. @40dSee if it is a breakpoint address.
  6020. @d
  6021. @40dIf so, deactivate it and write the
  6022. @40doriginal instruction back.
  6023. @d
  6024.  
  6025.  
  6026.         ; Entry point for "reset" command.
  6027.  
  6028.         ; Deactivates all breakpoints.
  6029.  
  6030. @40dPoint to ROM-Wack's breakpoint table.
  6031. @40dSize of breakpoint table - 1.
  6032. @40dGet breakpoint address.
  6033. @40dIf breakpoint in use then
  6034. @d
  6035. @40d  Clear breakpoint address.
  6036. @40d  Fix instruction at breakpoint.
  6037.                                         Endif
  6038. @40dGo to next table entry.
  6039. @40dLoop until whole table done.
  6040. @40dPrint a newline.
  6041. @d
  6042.  
  6043.  
  6044.         ; Entry point for "set" command.
  6045.  
  6046.         ; Activates a breakpoint at the current address.
  6047.  
  6048. @40dGet current address.
  6049. @40dSee if it is a breakpoint.
  6050. @40dIf so, do nothing.
  6051. @d
  6052. @40dScan the breakpoint table for an
  6053. @40dunused entry.
  6054. @d
  6055. @d
  6056. @d
  6057.  
  6058.         ; No unused breakpoint table entry found.
  6059.  
  6060. @40dPoint at "too many" string.
  6061. @40dPrint it.
  6062. @40dReturn.
  6063.  
  6064.         ; Unused entry in the breakpoint table found.  Activate a breakpoint.
  6065.  
  6066. @40dSave instruction at breakpoint.
  6067. @40dReplace with TRAP #15.
  6068. @40dSave the breakpoint address.
  6069. @d
  6070.  
  6071. @8p@,12s
  6072.  
  6073.  
  6074.         ; Entry point for "show" command.
  6075.  
  6076.         ; Lists all active breakpoints.
  6077.  
  6078. @40dPoint to breakpoint table.
  6079. @40dLoop for 16 entries.
  6080. @40dGet current breakpoint address.
  6081. @40dSkip if zero.
  6082. @40dPrint a newline.
  6083. @40dPrint the breakpoint address.
  6084. @40dGo to next table entry.
  6085. @40dLoop until done.
  6086. @40dPrint a newline.
  6087. @d
  6088.  
  6089. @40dGarbage.
  6090.  
  6091.  
  6092.         ; Subroutine to get a character and echo it to the user.
  6093.  
  6094. @40dGet a character.
  6095. @d
  6096. @40dEcho it back.
  6097. @d
  6098. @d
  6099.  
  6100.         ; Entry point for "!" command (Modify a register).
  6101.  
  6102. @d
  6103. @40dPrint "!".
  6104. @d
  6105. @40dGet a character.
  6106. @40dConvert to upper case.
  6107. @40dGet pointer to stack-resident data.
  6108. @40dPoint to data register dump area.
  6109. @40dMaximum data register # = 7.
  6110. @a?fc2952
  6111. FC2952  cmp.b     #'D',D0               [D]ata register?
  6112. @a=fc2956
  6113. @d
  6114. @40dPoint to address register dump.
  6115. @40dMaximum address register # = 6.
  6116. FC295E  cmp.b     #'A',D0               [A]ddress register?
  6117. @a=fc2962
  6118. @d
  6119. @40dPoint to user stack pointer.
  6120. FC2968  cmp.b     #'U',D0               [U]SP?
  6121. @a=fc296c
  6122. @40dIf so, go change it.
  6123. @40dOtherwise, exit.
  6124.  
  6125.         ; Enter here with A0 pointing to a dump area containing sequential
  6126.         ; images of the address or data registers, and D2 containing the
  6127.         ; maximum register number.
  6128.  
  6129. @40dGet a character.
  6130. @40dBackspace?
  6131. @40dIf so, exit.
  6132. @40dIs it a digit?
  6133. @40dIf not, exit.
  6134. @40dConvert to number.
  6135. @40dGreater than maximum?
  6136. @40dIf so, exit.
  6137. @40dCompute offset to given register.
  6138. @40dCompute address of register.
  6139.  
  6140.         ; Enter here with A2 pointing to a longword containing the image
  6141.         ; of the register to modify.
  6142.  
  6143. @40dGet the current value.
  6144. @40dPrint a space.
  6145. @40dDisplay value as 8 hex digits.
  6146. @40dPrint "="
  6147. @d
  6148. @40dGet the new value from the user.
  6149. @40dWas a value entered?
  6150. @40dIf not, exit.
  6151. @40dUpdate the register.
  6152. @40dPrint a newline.
  6153. @d
  6154. @d
  6155.  
  6156.  
  6157.         ; Entry point for "^" and "limit" commands.
  6158.  
  6159.         ; This copies the current address to the "limit" address, i.e. the
  6160.         ; address to stop searching or filling memory at.
  6161.  
  6162. @40dCopy current address to limit.
  6163. @40dRequest frame redisplay.
  6164. @d
  6165.  
  6166.  
  6167.         ; Entry point for "find" command.
  6168.  
  6169. @d
  6170. @40dGet the search pattern.
  6171. @40dExit if none entered.
  6172. @40dDo the searching.
  6173. @40dExit if not found.
  6174. @40dRound result address down to even.
  6175. @40dStore it in current address.
  6176. @40dRequest frame redisplay.
  6177. @d
  6178. @d
  6179.  
  6180.         ; Search routine for the "find" command.
  6181.  
  6182. @d
  6183. @40dStart searching at start address - 2.
  6184.  
  6185. @40dSet the number of bytes to match.
  6186. @40dSet the search pattern address.
  6187. @40dGo to next address.
  6188. @d
  6189. @40dSee if limit address reached.
  6190. @40dIf so, return false.
  6191. @40dCompare one byte.
  6192. @40dGo to next address if mismatch.
  6193. @40dDecrement byte counter.
  6194. @40dLoop until all matched.
  6195. @40dFound: return the address where.
  6196. @d
  6197. @40dReturn false.
  6198. @d
  6199. @d
  6200.  
  6201.         ; Search/fill pattern input routine.  Prompts for a pattern,
  6202.         ; accepts it, and returns the following:
  6203.  
  6204.         ;   D0: Number of bytes in search pattern.
  6205.         ;   D1: True if pattern entered, false if aborted.
  6206.         ;   A0: Lower bound for search.
  6207.         ;   A2: Upper bound for search.
  6208.         ;   A3: Address of search pattern.
  6209.  
  6210. @40dPoint to "pattern? " string.
  6211. @40dPrint it.
  6212. @40dGet a number from the terminal.
  6213. @40dDid we get one?
  6214. @40dIf not, return false.
  6215. @d
  6216. @40dCompute 4-(d+1)/2, where d is the
  6217. @40dnumber of digits entered.
  6218. @d
  6219. @40dGet the number entered.
  6220. @40dGet the current address,
  6221. @40dand the limit address.
  6222. @40dReturn true.
  6223. @d
  6224.  
  6225. @a?fc2a2c
  6226. @8p@,12s
  6227.  
  6228.  
  6229.         ; Entry point for "fill" command.
  6230.  
  6231. @d
  6232. @40dGet the fill pattern.
  6233. @d
  6234. @40dIf one entered, go do the fill.
  6235. @40dRequest frame redisplay.
  6236. @d
  6237. @d
  6238.  
  6239.         ; Fill routine for the "fill" command.
  6240.  
  6241. @40dAdjust number of bytes for "dbra".
  6242. @40dInitialize loop counter.
  6243. @40dInitialize pattern address.
  6244. @40dUpper limit reached?
  6245. @40dExit if so.
  6246. @40dCopy one byte from the fill pattern.
  6247. @40dLoop until pattern done.
  6248. @40dLoop back and do pattern again.
  6249. @d
  6250.  
  6251.  
  6252.         ; Subroutine to print a single space.
  6253.  
  6254. @d
  6255. @40dCharacter code for a space.
  6256. @40dRawPutChar()
  6257. @d
  6258. @d
  6259.  
  6260.  
  6261.         ; Subroutine to print a single newline.
  6262.  
  6263. @d
  6264. @40dPoint to string below.
  6265. @40dPrint it.
  6266. @d
  6267. @d
  6268.  
  6269. @8p@,2s
  6270.  
  6271.  
  6272.         ; Subroutine to print string at address pointed to by A0, followed
  6273.         ; by a newline.
  6274.  
  6275. @d
  6276. @40dPrint the string.
  6277. @40dPrint a newline.
  6278. @d
  6279. @d
  6280.  
  6281.  
  6282.         ; I don't know what this is for.  It's not referenced anywhere.
  6283.  
  6284. @d
  6285. @d
  6286.  
  6287.  
  6288.         ; Subroutine to get a character.  Returns with the zero flag clear
  6289.         ; if a character was received, set otherwise.
  6290.  
  6291. @d
  6292. @d
  6293. @d
  6294. @d
  6295. @d
  6296.  
  6297.  
  6298.         ; Isdigit() type of function.  Enter with a character in D0, returns
  6299.         ; with the zero flag set if the character is a numeric digit.
  6300.  
  6301. @a?fc2aac
  6302. FC2AAC  cmp.b     #'0',D0
  6303. @a=fc2ab0
  6304. @d
  6305. FC2AB2  cmp.b     #'9',D0
  6306. @a=fc2ab6
  6307. @d
  6308. @d
  6309. @d
  6310.  
  6311.  
  6312.         ; Subroutine to convert an 8-bit code in D0 to a 2 character
  6313.         ; printable ASCII version.
  6314.  
  6315.         ; Codes 0 and 128-255 return "..", control codes are shown as "^A"
  6316.         ; to "^\", other characters are shown as a space, then the actual
  6317.         ; character.
  6318.  
  6319. @d
  6320. @40dMove ".." into D2.
  6321. @40dIs the code zero?
  6322. @40dIf so, return ".." and exit.
  6323. @40dIs the high bit set?
  6324. @40dIf so, return ".." and exit.
  6325. @40dMove space and null into D2.
  6326. @d
  6327. @40dIf the character is a control code,
  6328. @d
  6329. @40d  Move "^" and null into D2.
  6330. @a?fc2adc
  6331. FC2ADC  or.b      #$40,D0                 Convert to printable character.
  6332. @a=fc2ae0
  6333. @40d  Put it into D2.
  6334.                                         Endif
  6335. @40dReturn D2.
  6336. @d
  6337. @d
  6338.  
  6339.  
  6340.         ; ROM-Wack command execution function.  Calls the command function
  6341.         ; given in A0, and on return, displays the current "frame" if
  6342.         ; requested by the command function.
  6343.  
  6344. @d
  6345. @40dGet the command function address.
  6346. @40dExecute the function.
  6347. @40dNeed to display frame?
  6348. @40dExit if not.
  6349. @40dGet current address.
  6350. @40dGet frame size.
  6351. @40dDisplay the frame.
  6352. @d
  6353.  
  6354.  
  6355.         ; Entry point for "?" command (Display multi-character commands).
  6356.  
  6357. @d
  6358. @40dPoint to ROM-Wack command table.
  6359. @40dGet a character.
  6360. @d
  6361. @40dIf not zero, print it, and loop
  6362. @40dback to do the next one.
  6363. @40dPrint a space.
  6364. @40dAnother zero?
  6365. @40dIf not, loop back & print next cmd.
  6366. @40dPrint a newline.
  6367. @d
  6368. @d
  6369.  
  6370.  
  6371.         ; ROM-Wack command dispatch table scanner.
  6372.  
  6373.         ; Enter with a character code in D0.  This routine runs through the
  6374.         ; command table, and returns either the address of the command table
  6375.         ; entry matching the character, or zero.
  6376.  
  6377.         ; Each command table entry either corresponds to exactly one
  6378.         ; character, or to a range of characters.  This may sound confusing,
  6379.         ; but I've commented the command table itself, so you can just look
  6380.         ; there and it will be perfectly obvious.
  6381.  
  6382. @d
  6383. @40dPoint to command table.
  6384. @d
  6385. @40dGet link to next table entry.
  6386. @40dStrip off high 8 bits.
  6387. @40dExit if no next entry.
  6388. @40dPoint ot next entry.
  6389. @40dSee if command matches table entry.
  6390. @40dExit if it does.
  6391. @40dGo to next entry if smaller.
  6392. @40dCheck if in range.
  6393. @40dGo to next entry if not.
  6394. @40dReturn table entry address.
  6395. @d
  6396.  
  6397.  
  6398.         ; ROM-Wack command dispatcher.  Given a command character, looks it
  6399.         ; up in the command dispatch table and executes the command if found.
  6400.  
  6401.         ; C style entry point.
  6402.  
  6403. @d
  6404.  
  6405.         ; Assembler entry point.
  6406.  
  6407. @40dLook command up in command table.
  6408. @40dFound it?
  6409. @40dExit if not.
  6410. @d
  6411. @40dGet execution address from table
  6412.                                         and store it on the stack.
  6413. @40dExecute the function.
  6414. @40dPop address back off the table.
  6415. @d
  6416.  
  6417.  
  6418.         ; Multi-character command lookup function.
  6419.  
  6420.         ; This takes a pointer to a command string in A0, and looks it up
  6421.         ; in the table of multi-character commands.  It returns the address
  6422.         ; of the table entry corresponding to the command, or zero if the
  6423.         ; command was not found.
  6424.  
  6425.         ; C style entry point.
  6426.  
  6427. @d
  6428.  
  6429.         ; Assembler entry point.
  6430.  
  6431. @d
  6432. @d
  6433. @40dPoint at command dispatch table.
  6434. @d
  6435. @40dGet pointer to next table entry.
  6436. @40dExit if null (end of table).
  6437. @d
  6438. @40dGet pointer to string.
  6439. @40dPoint to string to match.
  6440. @40dCompare them.
  6441. @40dGot a match?
  6442. @40dKeep looking if not.
  6443. @40dReturn table address.
  6444. @d
  6445. @d
  6446.  
  6447.  
  6448.         ; ROM-Wack main loop:  Gets a character from the user, then
  6449.         ; interprets it, then gets next characer, etc.
  6450.  
  6451. @40dGet a character from the user.
  6452. @40dStore it.
  6453. @40dProcess it.
  6454. @40dGo get next character.
  6455.  
  6456.  
  6457.         ; Entry point for letters, numbers and underline characters typed
  6458.         ; at the ROM-Wack command level.  This function collects them in
  6459.         ; a buffer.
  6460.  
  6461. @40dAddress of secondary key bindings.
  6462. @40dAlready using them?
  6463. @d
  6464.  
  6465.         ; This is the first character of a multi character command, so
  6466.         ; clear the buffer and point to the other set of key bindings.
  6467.  
  6468. @40dZero characters in buffer so far.
  6469. @40dSave address of primary key bindings.
  6470. @40dPoint at secondary key bindings.
  6471.  
  6472. @a?fc2bbe
  6473. FC2BBE  cmp.b     #' ',$82(A6)          Was the key a space?
  6474. @a=fc2bc4
  6475. @40dIf so, ignore it (kludge, see below).
  6476. @40dGet number of chars in buffer
  6477. @40d50 characters already?
  6478. @40dIf equal or more, ignore this one.
  6479. @40dGet command character.
  6480. @40dEcho it to the user.
  6481. @40dPoint to buffer.
  6482. @40dGet offset into buffer.
  6483. @40dStore character in buffer.
  6484. @40dIncrement buffer count.
  6485. @40dThere is unprocessed data in the
  6486. @40dbuffer, so set the flag.
  6487.  
  6488.  
  6489.         ; Entry point to get a number from the user.
  6490.  
  6491. @a?fc2bf0
  6492. FC2BF0  move.b    #' ',$82(A6)           Start using secondary key bindings.
  6493. @a=fc2bf6
  6494. @d
  6495. @40d Indicate that input is being
  6496.                                          gathered for a specific function.
  6497.  
  6498.         ; Loop to read the digits.  We stay in this loop, using the
  6499.         ; secondary (input gathering) key bindings until some command
  6500.         ; function switches us back to the primary ones.  That means
  6501.         ; the user either canceled the line, or pressed RETURN.
  6502.  
  6503. @40d Using secondary key bindings now?
  6504. @40d Exit loop if not.
  6505. @40d Get a key from the user.
  6506. @40d Store it in "last key typed".
  6507. @40d Dispatch it as a command character.
  6508. @40d Loop.
  6509.  
  6510.         ; The input line has been processed.  Either it was a command
  6511.         ; (and was executed), or it was a number, or it was an error.
  6512.  
  6513. @40d Clear "parameter input" flag.
  6514. @d
  6515. @40d Get number of digits.
  6516. @40d If no useful data in buffer (line
  6517. @40d canceled, command already executed,
  6518. @40d bad symbol...), return zero digits.
  6519. @d
  6520.  
  6521.  
  6522.         ; Entry point for <Space> while using the secondary key bindings.
  6523.  
  6524. @d
  6525.  
  6526.  
  6527.         ; Entry point for CTRL-U and CTRL-X.  Point back to the original
  6528.         ; set of key bindings, and set the buffer to empty.
  6529.  
  6530. @40d-1 characters in buffer.
  6531. @40dRestore top-level key bindings.
  6532. @40dPrint a linefeed.
  6533. @40dBuffer contains no useful data.
  6534. @d
  6535.  
  6536.  
  6537.         ; Entry point for <Backspace>.  This deletes one charaacter from
  6538.         ; the input buffer.
  6539.  
  6540. @40dAny characters in the buffer?
  6541. @40dIf none, cancel input.
  6542. @40dPoint to buffer.
  6543. @40dGet buffer offset.
  6544. @40dClear last character in buffer.
  6545. @40dDecrement buffer count.
  6546. @40dPoint to string below.
  6547. @40dPrint it.
  6548. @40dIs buffer now empty?
  6549. @40dIf so, cancel input.
  6550. @d
  6551.  
  6552.         ; String used to erase one character from the user's terminal.
  6553.  
  6554. @8p@,4s
  6555.  
  6556.  
  6557.         ; Entry point for <Return>.
  6558.  
  6559. @40dRestore previous key bindings.
  6560. @40dPoint to input buffer.
  6561. @40dGet number of characters in it.
  6562. @d
  6563. @40dIndicate that no data is in the
  6564.                                         buffer waiting for processing.
  6565. @d
  6566. @d
  6567.  
  6568.         ; There was data in the buffer, now interpret it.
  6569.  
  6570. @40dZero-terminate the buffer.
  6571. @40dPoint to it.
  6572. @40dLook command up in table.
  6573. @40dBranch if not found.
  6574. @d
  6575. @40dIndicate that buffer was processed.
  6576. @40dGet the command table offset.
  6577. @40dGet execution address from table.
  6578. @40dExecute the command.
  6579. @40dClear frame redisplay flag.
  6580. @40dPop execution address of stack.
  6581. @d
  6582.  
  6583.         ; Continue here if the buffer contained a string not found
  6584.         ; in the command table.  For a full Wack, this means it would
  6585.         ; either be a number, or a symbol.  For ROM-Wack, it's either
  6586.         ; a number or an error.
  6587.  
  6588. @40dPoint to the string in the buffer.
  6589. @40dPoint to input number location.
  6590. @40dInterpret input buffer as a number.
  6591. @40dStore number of digits.
  6592. @d
  6593. @40dIf 0 digits (bad hex number), print
  6594. @40d"unknown symbol", indicate that no
  6595. @40ddata is waiting in the buffer, and
  6596. @40dexit.
  6597.  
  6598.         ; Continue here if number of digits was non-zero.  If the number
  6599.         ; wasn't being gathered as a parameter to another command, make it
  6600.         ; the current location.
  6601.  
  6602. @40dParameter being gathered?
  6603. @40dExit if so.
  6604. @40dRound number down to even.
  6605. @d
  6606. @40dSet the current location to it.
  6607. @40dRequest (re)display of frame.
  6608. @d
  6609.  
  6610. @8p@,18s
  6611.  
  6612.  
  6613.         ; Hex number interpreting routine.
  6614.  
  6615. @d
  6616. @40dStart result at zero.
  6617. @40dStart with "-1 digits".
  6618. @d
  6619. @40dJump into the loop.
  6620. @40dEntry point for hex digits:  Add 10.
  6621. @d
  6622. @40dShift previous number left by 4 bits.
  6623. @40dAdd in new digit.
  6624. @40dIncrement digit counter.
  6625. @40dGet a digit from the input string.
  6626. @40dExit if end of string reached.
  6627. @a?fc2d14
  6628. FC2D14  sub.b     #'0',D0               Subtract '0'.
  6629. @a=fc2d18
  6630. @40dExit if result less than zero.
  6631. @40dGreater than 9?
  6632. @40dBranch if not.
  6633. @40dSubtract 17.
  6634. @40dExit if result less than zero.
  6635. @40dBranch if less than 7.
  6636. @d
  6637. @a?fc2d2c
  6638. FC2D2C  sub.b     #$20,D0               Subtract ('a' - 'A').
  6639. @a=fc2d30
  6640. @40dBranch if less than zero.
  6641. @d
  6642. @40dBranch if less than 7.
  6643.  
  6644.         ; If we branch here, the number entered contained an invalid
  6645.         ; hexadecimal digit.
  6646.  
  6647. @40dReturn "0 digits".
  6648.  
  6649.         ; Branch here if end of string reached with no invalid digits.
  6650.  
  6651. @40dStore result where indicated.
  6652. @40dReturn number of digits.
  6653. @d
  6654. @d
  6655.  
  6656.  
  6657.         ; Some sort of format string.  Not used anywhere.
  6658.  
  6659. @a?fc2d42
  6660. @8p@,6s
  6661.  
  6662.  
  6663.         ; Toupper() type of function.  Converts character in D0 to upper
  6664.         ; case if necessary.
  6665.  
  6666. @a?fc2d48
  6667. FC2D48  cmp.b     #'a',D0               Less than 'a'?
  6668. @a=fc2d4c
  6669. @d
  6670. @a?fc2d4e
  6671. FC2D4E  cmp.b     #'z',D0               Greater than 'z'?
  6672. @a=fc2d52
  6673. @d
  6674. FC2D54  sub.b     #$20,D0               If neither, convert to upper case.
  6675. @a=fc2d58
  6676. @d
  6677.  
  6678. @8p@32wPadding.
  6679.  
  6680. ---------------------------------------------------------------------------
  6681.   result = Procure( semaphore, bidMessage )
  6682.   D0                A0         A1
  6683. ---------------------------------------------------------------------------
  6684.  
  6685.         ; A Procure/Vacate semaphore is a message port structure plus a
  6686.         ; counter.  A task can "lock" the semaphore, by calling Procure().
  6687.         ; Further attempts to lock the semaphore won't succeed until the
  6688.         ; original locker unlocks the semaphore by Vacate().
  6689.  
  6690.         ; A sm_Bids value of -1 indicates that the semaphore is free, zero
  6691.         ; indicates it's locked and no one is waiting, 1 means one task is
  6692.         ; waiting, etc.
  6693.  
  6694.         ; Whenever Procure() is called, a pointer to a message must be
  6695.         ; given.  This message is enqueued on the semaphore's port if the
  6696.         ; semaphore is not currently available, and returned when the
  6697.         ; caller's turn comes up to get the lock.  If the semaphore was
  6698.         ; available (sm_Bids = -1), the message is not used.
  6699.  
  6700. @40dIncrement the sm_Bids field.
  6701. @40dCheck if the semaphore was free.
  6702. @40dIf it was, store pointer to the
  6703.                                         current locker's message
  6704. @40dand return TRUE.
  6705. @d
  6706. @40dIf it wasn't, enqueue the message
  6707. @40don the semaphore's port and return
  6708. @40dFALSE.
  6709.  
  6710.  
  6711. ---------------------------------------------------------------------------
  6712.   Vacate( semaphore )
  6713.           A0
  6714. ---------------------------------------------------------------------------
  6715.  
  6716.         ; A task which has successfully obtained a semaphore via Procure()
  6717.         ; calls this to release it again.  The sm_Bids field is decremented.
  6718.         ; If it was zero and ends up at -1, nobody else was waiting to use
  6719.         ; the semaphore.  If it ends up positive, someone else is waiting
  6720.         ; and we must send his bid message back to let him know he has it
  6721.         ; now.  The first message enqueued on the semaphore's port is the
  6722.         ; task which has waited longest and gets it.
  6723.  
  6724. @40dClear pointer to locker's message.
  6725. @40dDecrement sm_Bids field.
  6726. @40dReturn if it is now -1.
  6727. @d
  6728. @40dSave semaphore pointer.
  6729. @40dDequeue the oldest bid message.
  6730. @40dRestore semaphore pointer.
  6731. @40dStore pointer to the message.
  6732. @40dExit if no message (error).
  6733. @d
  6734. @40dReplyMsg() to inform the waiting
  6735. @40dtask, then exit.
  6736.  
  6737.  
  6738. ---------------------------------------------------------------------------
  6739.   InitSemaphore( signalSemaphore )
  6740.                  A0
  6741. ---------------------------------------------------------------------------
  6742.  
  6743. @40dPoint to the waiting task list.
  6744. @40dInitialize it to empty.
  6745. @d
  6746. @d
  6747. @d
  6748. @40dClear the ss_Owner field to null.
  6749. @40dClear the ss_NestCount to zero.
  6750. @40dSet the ss_QueueCount to -1.
  6751. @d
  6752.  
  6753.  
  6754. ---------------------------------------------------------------------------
  6755.   ObtainSemaphore( signalSemaphore )
  6756.                    A0
  6757. ---------------------------------------------------------------------------
  6758.  
  6759. @40dForbid()
  6760. @40dIncrement the ss_QueueCount.
  6761. @d
  6762.  
  6763.         ; If the ss_Queuecount is now 0, then the semaphore was free and
  6764.         ; we got it.  Set the pointer to the owning task, set the nesting
  6765.         ; level to 1, and exit.
  6766.  
  6767. @40dStore pointer to owning task.
  6768. @d
  6769.  
  6770.         ; The ss_Queuecount was not -1, so the semaphore was already owned
  6771.         ; by someone.  Check if it is the calling task.
  6772.  
  6773. @d
  6774. @40dGet current task pointer.
  6775. @40dDo we own the semaphore already?
  6776. @40dIf so, increment nest count and exit.
  6777.  
  6778.         ; Another task owns the semaphore at the moment, so we must block.
  6779.         ; Since all non-running tasks must be on the TaskWait queue, we
  6780.         ; can't just enqueue the task on the semaphore.  Instead, we build
  6781.         ; a temporary node on the stack, and enqueue that.  Then we clear
  6782.         ; signal #2, and wait for someone to set it, which will occur when
  6783.         ; the current owner of the semaphore releases it.  When we wake up,
  6784.         ; we deallocate the temporary node, and return to the user.
  6785.  
  6786. @40dReserve 12 bytes of stack space.
  6787. @40dStore pointer to this task.
  6788. @40dClear signal #2.
  6789. @40dPoint to waiting task list.
  6790. @d
  6791. @40dEnqueue the temporary list node.
  6792. @d
  6793. @40dWait for signal #2.
  6794. @40dRelease the reserved stack space.
  6795. @d
  6796.  
  6797. @40dIncrement the nesting count.
  6798. @40dPermit()
  6799. @d
  6800.  
  6801.  
  6802. ---------------------------------------------------------------------------
  6803.   ReleaseSemaphore( signalSemaphore )
  6804.                     A0
  6805. ---------------------------------------------------------------------------
  6806.  
  6807. @40dDecrement the nesting count.
  6808. @40dIf zero, release the semaphore.
  6809. @40dIf it went negative, guru city!
  6810. @40dOtherwise, just decrement the
  6811. @40dss_QueueCount and exit.
  6812.  
  6813.         ; Continue here when the nesting count went to zero, and we
  6814.         ; therefore don't want the semaphore any more.
  6815.  
  6816. @40dForbid()
  6817. @40dDecrement the ss_QueueCount.
  6818. @40dIf now -1, nobody was waiting.
  6819.  
  6820.         ; The ss_Queuecount is still positive, so someone is blocked on
  6821.         ; the semaphore and waiting to be awakened.  The first (oldest)
  6822.         ; entry on the semaphore's queue gets it.
  6823.  
  6824. @d
  6825. @40dSave semaphore pointer.
  6826. @40dPoint to semaphore's queue.
  6827. @40dRemHead()
  6828. @40dIf the queue was empty, guru city!
  6829. @d
  6830.  
  6831.         ; We have a pointer (in D0) to a node which identifies the
  6832.         ; waiting process (the temporary one allocated on that process's
  6833.         ; stack).
  6834.  
  6835. @d
  6836. @d
  6837. @40dGet pointer to waiting task.
  6838. @40dMake this task the ss_Owner.
  6839. @d
  6840. @40dSet waiting task's signal #2.
  6841. @d
  6842. @40dExit.
  6843.  
  6844.         ; Continue here if nobody was waiting for the semaphore.  In this
  6845.         ; case just clear the semaphore's owner field.
  6846.  
  6847. @40dClear ss_Owner to null.
  6848. @40dPermit()
  6849. @d
  6850.  
  6851.         ; Put up an alert if the semaphore's nest count went negative
  6852.         ; (should never happen, we give away the semaphore when it reaches
  6853.         ; zero), or if the semaphore's queue was empty even though the
  6854.         ; ss_QueueCount said it isn't.
  6855.  
  6856. @d
  6857. @40dAlert number (fatal).
  6858. @40dGet ExecBase.
  6859. @40dPut up the alert.
  6860. @40dNever executed.
  6861. @d
  6862.  
  6863.  
  6864. ---------------------------------------------------------------------------
  6865.   success = AttemptSemaphore( signalSemaphore )
  6866.   D0                          A0
  6867. ---------------------------------------------------------------------------
  6868.  
  6869. @40dGet pointer to current task.
  6870. @40dForbid()
  6871. @40dIncrement the ss_QueueCount.
  6872. @40dBranch if now zero.
  6873. @40dDo we own the semaphore already?
  6874. @40dBranch if true.
  6875. @40dDecrement the ss_QueueCount again.
  6876. @40dPermit()
  6877. @40dReturn FALSE.
  6878. @d
  6879.  
  6880.         ; Continue here if we were able to get the semaphore.
  6881.  
  6882. @40dInstall pointer to owning task.
  6883. @40dIncrement nest count.
  6884. @40dPermit()
  6885. @40dReturn TRUE.
  6886. @d
  6887.  
  6888.  
  6889. ---------------------------------------------------------------------------
  6890.   ObtainSemaphoreList( list )
  6891.                        A0
  6892. ---------------------------------------------------------------------------
  6893.  
  6894.         ; This function is given a linked list of semaphore structures, and
  6895.         ; obtains them all.  This is done in two passes.  On the first pass,
  6896.         ; a SemaphoreRequest is enqueued on all semaphores which aren't free,
  6897.         ; and all the free ones are grabbed.
  6898.  
  6899.         ; On the second pass, the list is traversed again.  This time, if
  6900.         ; we already have a semaphore, we just pass it, otherwise, we wait
  6901.         ; for it.
  6902.  
  6903.         ; Note:  Whereas ObtainSemaphore() builds its SemaphoreRequest node
  6904.         ; on the task's stack, this one uses the single copy inside the
  6905.         ; semaphore structure.  This means that a crash is sure to result
  6906.         ; if more than one task tries to ObtainSemaphoreList and several
  6907.         ; end up waiting for the same semaphore.  The documentation has
  6908.         ; a bit more to say about this.
  6909.  
  6910. @d
  6911. @40dClear the "need to wait" flag.
  6912. @40dGet pointer to current task.
  6913. @40dForbid()
  6914. @d
  6915. @40dPoint to first semaphore in list.
  6916. @d
  6917. @40dEnd of list reached?
  6918. @40dExit loop if so.
  6919. @40dIncrement current semaphore's count.
  6920. @40dBranch if now zero.
  6921. @40dCheck if the semaphore is ours.
  6922. @40dBranch if true.
  6923. @40dUse the ss_MultipleLink structure
  6924. @40dto enqueue our semaphore request on
  6925. @40dthe semaphore's wait queue.
  6926. @d
  6927. @40dIndicate that we need to wait.
  6928. @40dGo to next semaphore in list.
  6929.  
  6930.         ; We got a semaphore.
  6931.  
  6932. @40dMake us the owner of this semaphore.
  6933. @40dIncrement its nest count.
  6934. @40dTry next semaphore in the list.
  6935.  
  6936.         ; The end of the list was reached.
  6937.  
  6938. @40dDid we get all the semaphores?
  6939. @40dIf so, exit.
  6940.  
  6941.         ; We have to wait for at least one semaphore in the list.
  6942.  
  6943. @40dGo to the start of the list.
  6944. @d
  6945. @40dEnd of list reached?
  6946. @40dIf so, exit.
  6947. @40dDo we own this semaphore?
  6948. @d
  6949. @40dIf we do, and its nest count is not
  6950. @40dzero, go on to the next one.
  6951. @40dIncrement the nest count.
  6952. @40dGo on to the next one.
  6953.  
  6954.         ; Wait for a semaphore.
  6955.  
  6956. @d
  6957. @40dWait for signal #2.
  6958. @40dGo back and check if we have it now.
  6959. @40dPermit()
  6960. @d
  6961. @d
  6962.  
  6963.  
  6964. ---------------------------------------------------------------------------
  6965.   ReleaseSemaphoreList( list )
  6966.                         A0
  6967. ---------------------------------------------------------------------------
  6968.  
  6969. @d
  6970. @40dGo to the start of the list.
  6971. @40dGo to first/next node.
  6972. @40dEnd of list reached?
  6973. @40dIf so, exit.
  6974. @40dReleaseSemaphore()
  6975. @40dLoop until all done.
  6976. @d
  6977. @d
  6978.  
  6979.  
  6980. ---------------------------------------------------------------------------
  6981.   AddSemaphore( signalSemaphore )
  6982.                 A1
  6983. ---------------------------------------------------------------------------
  6984.  
  6985. @40dInitSemaphore()
  6986. @40dPoint to global semaphore list.
  6987. @40dAdd the semaphore to the list.
  6988.  
  6989.  
  6990. ---------------------------------------------------------------------------
  6991.   RemSemaphore( signalSemaphore )
  6992.                 A1
  6993. ---------------------------------------------------------------------------
  6994.  
  6995. @40dUnlink semaphore from whatever
  6996.                                         list it's in.
  6997.  
  6998. ---------------------------------------------------------------------------
  6999.   signalSemaphore = FindSemaphore( name )
  7000.   D0                               A1
  7001. ---------------------------------------------------------------------------
  7002.  
  7003. @40dPoint to global semaphore list.
  7004. @40dFindName()
  7005. @d
  7006.  
  7007.  
  7008. @8p@32wPadding.
  7009.  
  7010.  
  7011. ---------------------------------------------------------------------------
  7012.   CopyMemQuick( source, dest, size )
  7013.                 A0      A1    D0
  7014. ---------------------------------------------------------------------------
  7015.  
  7016.         ; The caller guarantees that the source and destination are even,
  7017.         ; and that the transfer count is a multiple of 4.  This allows us
  7018.         ; to skip some of the strategy below.
  7019.  
  7020. @40d0 bytes left over after longword copy.
  7021. @40dGo copy (at least) as longwords.
  7022.  
  7023.  
  7024. ---------------------------------------------------------------------------
  7025.   CopyMem( source, dest, size )
  7026.            A0      A1    D0
  7027. ---------------------------------------------------------------------------
  7028.  
  7029.         ; This is an interesting tutorial on efficient 68000 memory moving.
  7030.  
  7031.         ; Note that this is not necessarily the best way to move memory on
  7032.         ; a 68010 or 68020, since both of these processors have expanded
  7033.         ; features designed to make memory moving more efficient, and all
  7034.         ; the computational overhead of choosing the right copying method
  7035.         ; might not be worth it.
  7036.  
  7037. @40dLess than 12 bytes to copy?
  7038. @d
  7039. @40dIf so, just copy byte by byte.
  7040.  
  7041.         ; The following bit of code handles odd/even source and destination
  7042.         ; addresses.  The following is done:
  7043.  
  7044.         ; Source and destination even:  Just continue.
  7045.         ; Source and destination odd:   Copy 1 byte.  Both addresses are now
  7046.         ;                               even, so we can continue.
  7047.         ; Source even, dest. odd:       Copy byte by byte.
  7048.         ; Source odd, destination even: Copy one byte, then copy the rest
  7049.         ;                               byte by byte.
  7050.  
  7051.         ; Note that there is nothing we can do if the source and destination
  7052.         ; differ by an odd number, i.e. are "out of phase".  In such a case,
  7053.         ; we must copy byte by byte.
  7054.  
  7055. @d
  7056. @40dIs the source address odd?
  7057. @40dBranch past the following if not.
  7058. @40dCopy one byte.
  7059. @40dDecrement transfer count.
  7060. @d
  7061. @40dIs the destination address odd?
  7062. @40dIf so, transfer byte by byte.
  7063.  
  7064.         ; Both the source and destination addresses are (now) even.
  7065.         ; The worst that can happen now is that we have to move the data
  7066.         ; as individual longwords.  First, compute how many bytes will
  7067.         ; be left over after we move the data as longwords, and save this
  7068.         ; value.
  7069.  
  7070. @40dFind how many bytes will be left
  7071. @40dif data is copied as longwords.
  7072. @40dSave this number.
  7073.  
  7074.         ; The "move multiple" approach below copies 48 bytes of data with
  7075.         ; only two instructions.  But to use it, 48 bytes of registers need
  7076.         ; to be saved and restored, and so it's not worth it unless we have
  7077.         ; at least two 48 byte "batches" to copy.
  7078.  
  7079. @d
  7080. @40d96 or more bytes to move?
  7081. @40dIf not, copy as longwords.
  7082. @40dSave 12 registers on the stack.
  7083. @40dGet 48 bytes with one instruction.
  7084. @40dMove them to the destination.
  7085. @d
  7086. @40dAdd 48 to destination address.
  7087. @40dSubtract 48 from transfer count.
  7088. @40dCopy another batch if 48 or more
  7089. @40dbytes remain to be copied.
  7090. @40dRestore the 12 registers.
  7091.  
  7092.         ; Whatever the case, D0 now contains the number of bytes left over.
  7093.         ; Copy as many of these as possible as longwords.
  7094.  
  7095. @40dSee how many longwords to copy.
  7096. @40dBranch if none.
  7097. @40dAdjust for dbra.
  7098. @40dSplit up into two 16-bit values.
  7099. @d
  7100. @40dCopy the longwords.
  7101. @d
  7102. @d
  7103.  
  7104.         ; Done copying longwords.  Get the number of bytes left over (0-3)
  7105.         ; from the stack and fall into the byte copy routine.
  7106.  
  7107. @40dRestore number of bytes left over.
  7108. @40dExit if none.
  7109. @40dHigh 16 bits of byte count = 0.
  7110. @40dEnter the byte copy loop.
  7111.  
  7112.         ; Copy as individual bytes, either to clean up odds and ends after
  7113.         ; copying in larger chunks, or because copying in larger chunks
  7114.         ; wasn't worth it.
  7115.  
  7116. @40dSplit transfer count up into two
  7117. @40d16-bit sections.
  7118. @40dEnter loop at bottom (for dbra).
  7119. @40dCopy the bytes.
  7120. @d
  7121. @d
  7122. @d
  7123.  
  7124.  
  7125.         ; System exception alert entry point
  7126.         ; ----------------------------------
  7127.  
  7128.         ; If an exception occurs or a TRAP instruction is executed while the
  7129.         ; CPU is in supervisor mode, we jump here, since we have no task to
  7130.         ; blame it on.  If a task was running, we use its tc_TrapCode vector
  7131.         ; instead, but at powerup, the exec default for this vector is also
  7132.         ; initialized to point here.  Later, it is stolen by some other
  7133.         ; part of the system so the "Software error - task held" window can
  7134.         ; be put up before the guru.
  7135.  
  7136.  
  7137. @40dDump the registers.
  7138. @40dPoint at exception data on the stack.
  7139. @40dGet ExecBase.
  7140. @40dIs it even?
  7141. @d
  7142. @40dIf so, point where the current task
  7143. @40dpointer probably is.
  7144. @40dGet the exception number.
  7145. @40dMask out any garbage.
  7146.  
  7147.         ; Fall into Alert().  alertNum is the exception number from the
  7148.         ; stack, and A5 points either to the current task pointer, or to
  7149.         ; the exception data on the stack.
  7150.  
  7151.  
  7152. ---------------------------------------------------------------------------
  7153.   Alert( alertNum, parameters )
  7154.          D7        A5
  7155. ---------------------------------------------------------------------------
  7156.  
  7157.         ; This routine has a relatively failsafe mechanism for getting an
  7158.         ; alert message up on the screen.  I call this the "deferred guru".
  7159.  
  7160.         ; Right away, a signature ("HELP") is installed at location 0, and
  7161.         ; the guru data is stored at location $000100.  If the system hangs
  7162.         ; now, the user will get the guru after he/she reboots manually
  7163.         ; via CTRL-Amiga-Amiga.  If for any reason it decides it's in
  7164.         ; serious trouble, it will reset itself, with the same effect.
  7165.  
  7166. @40dDisable all interrupts.
  7167. @d
  7168.  
  7169.         ; If location 0 ALREADY contains "HELP", something is wrong, and
  7170.         ; no matter what the requested alert was, we reset the computer.
  7171.  
  7172. @40dSee if "HELP" is at location zero.
  7173. @40dIf so, unrecoverable crash.
  7174.  
  7175.         ; Store our own "deferred guru" data at 0 and $000100.  Then see
  7176.         ; if we should use it.  If ExecBase has been clobbered, or the
  7177.         ; stack is not working, or the unrecoverable alert bit is set,
  7178.         ; we blink the power light, and reset the computer.  The guru will
  7179.         ; come up during the reboot.
  7180.  
  7181. @40dMove "HELP" at location 0 now.
  7182. @40dPoint at location $000100.
  7183. @40dStore alert number there.
  7184. @40dStore the parameter.
  7185.  
  7186. @40dGet ExecBase.
  7187. @d
  7188.  
  7189.         ; Without checking, I would assume that this is where the famous
  7190.         ; "Recoverable alert doesn't work with expansion memory" bug is.
  7191.  
  7192.         ; Namely, if the ExecBase structure isn't in the first 64K of
  7193.         ; memory, we assume that it isn't OK.  With $C00000 memory, it
  7194.         ; will be at $C00276, and KABOOM, this fails, and the system
  7195.         ; resets, doing the unrecoverable alert thing via the "deferred
  7196.         ; alert" mechanism discussed earlier.
  7197.  
  7198. @40dIs ExecBase in the first 64K?
  7199. @40dIf not, unrecoverable crash.
  7200. @d
  7201. @40dCheck ExecBase complement pointer.
  7202. @d
  7203. @40dUnrecoverable crash if not valid.
  7204. @40dCheck if the stack is working by
  7205. @40dpushing a signature and trying to
  7206. @40dpop it off again.
  7207. @40dUnrecoverable crash if not working.
  7208. @40dTest high bit of alert number.
  7209. @40dBranch if unrecoverable.
  7210.  
  7211.         ; Processing for recoverable alerts.  If we get this far, we have
  7212.         ; verified that the "dead end alert" flag was not set, that the
  7213.         ; ExecBase pointer and structure are probably OK, and that the
  7214.         ; stack is working (stack pointer pointing to RAM).
  7215.  
  7216. @40dPoint to ExecBase->LastAlert.
  7217. @40dStore alert number.
  7218. @40dStore parameter.
  7219. @40dCall the guru alert routine.
  7220.  
  7221. @40dWas the subsystem ID field zero?
  7222. @40dIf not, return to the caller.
  7223.  
  7224.         ; The alert number was of the form 0000xxxx.  This means that it
  7225.         ; must have been a system exception.  Presumably, the user has had
  7226.         ; the option of pressing the left or right mouse button, reflected
  7227.         ; in D0 as returned from the guru routine.  Accordingly, we
  7228.         ; reset or go to the debugger.
  7229.  
  7230. @40dTest the guru routine's return code.
  7231. @40dRestore the registers.
  7232. @40dReset if zero flag not set.
  7233. @40dElse go to ROM-Wack.
  7234.  
  7235. @40dEnable interrupts if they are
  7236. @40dsupposed to be enabled.
  7237. @d
  7238. @d
  7239.  
  7240.  
  7241.         ; Unrecoverable system crash entry point
  7242.         ; --------------------------------------
  7243.  
  7244.         ; This routine blinks the power light slowly 6 times, and checks
  7245.         ; whether the user presses DEL on a terminal attached to the
  7246.         ; serial port.  If DEL is received, it jumps to ROM-Wack.  If
  7247.         ; DEL is not received, it resets the computer.  This may or may
  7248.         ; not lead to a guru, depending on how locations 0 and $000100 were
  7249.         ; set up before this was called.
  7250.  
  7251.         ; Entry point for when the stack is not working (stack pointer
  7252.         ; clobbered).  Set the stack pointer to 256K, and build a fake
  7253.         ; exception stack frame below it.
  7254.  
  7255. @40dSet stack pointer to 256K
  7256. @40dBuild fake exception stack frame.
  7257. @d
  7258.  
  7259.         ; Entry point for when the stack was working.
  7260.  
  7261. @40dSet CIA data direction register.
  7262. @40dSet power light to bright.
  7263.  
  7264.         ; Force the CPU into supervisor mode.  If the MOVE.W #$2700,SR
  7265.         ; instruction bombs the first time, it will work the second time.
  7266.  
  7267. @40dSet privilege violation vector.
  7268. @a?fc3076
  7269. FC3076  move.w    #$2700,SR             Mask all maskable interrupts.
  7270. @a=fc307a
  7271.  
  7272.         ; Blink the power light slowly 6 times and look for a DEL character
  7273.         ; coming in through the serial port at 9600 bps.  If such a character
  7274.         ; is received, go to the debugger.
  7275.  
  7276. @40dSet loop counter to 5.
  7277. @40dSet serial port for 8 bits, 9600 bps.
  7278. @d
  7279. @40dSet power light to dim.
  7280. @40dDelay.
  7281. @40dSet power light to bright.
  7282. @40dDelay.
  7283. @40dRead the serial port.
  7284. @40dClear serial port interrupt bit.
  7285. @d
  7286. @40dDid we receive a DEL character?
  7287. @40dIf not, keep blinking the light.
  7288. @40dIf DEL not pressed, reset.
  7289.  
  7290.         ; The user pressed DEL.  Push the exception number on the stack
  7291.         ; and enter the debugger.
  7292.  
  7293. @d
  7294. @40dGo to ROM-Wack.
  7295.  
  7296.  
  7297.         ; "Deferred Guru" support routines
  7298.         ; --------------------------------
  7299.  
  7300.         ; The following routine is called early in the startup code.  Since
  7301.         ; there is no stack at that point, it returns via a jump, rather
  7302.         ; than an RTS.  It removes the "HELP" at zero, if present, and
  7303.         ; loads D6 and D7 with the data for ExecBase->LastAlert.
  7304.  
  7305. @40dLoad -1 into D6
  7306. @40dSee if location 0 contains "HELP".
  7307. @40dIf not, go back to init. code.
  7308. @40dClear location 0.
  7309. @40dLoad D6 and D7 from location $0100.
  7310. @40dGo back to init. code.
  7311.  
  7312.         ; The following subroutine is called later, after the ExecBase
  7313.         ; structure has been built.  It writes the data determined above
  7314.         ; (still in D6 and D7) into ExecBase->LastAlert.
  7315.  
  7316. @d
  7317. @d
  7318.  
  7319.  
  7320.         ; Guru Alert Routine
  7321.         ; ------------------
  7322.  
  7323.         ; This routine puts the big red "Guru" message up on the screen,
  7324.         ; waits for the user to click the mouse button, then returns.
  7325.  
  7326.         ; The routine is called with the alert number and parameters stored
  7327.         ; at LastAlert in the ExecBase structure.  This routine reads the
  7328.         ; alert number from there and decides what to do with it.
  7329.  
  7330.         ; An alert number of -1 means that no alert was outstanding, and
  7331.         ; therefore, the routine returns right away.  This means that if
  7332.         ; it is called via the "alert.hook" mechanism, and no alert was
  7333.         ; pending from before the reboot, nothing will happen.
  7334.  
  7335.         ; If the alert number is not -1, an alert will be generated.  The
  7336.         ; following algorithm is used to decide what the first string in
  7337.         ; the alert should say.
  7338.  
  7339.         ; IF the alert number is of the form xxxx01xxxxxxxx THEN
  7340.         ;   Make the alert message "Not enough memory".
  7341.         ; ELSEIF the high bit in the alert number is clear, and the
  7342.         ;        "general error" field is not zero THEN
  7343.         ;   Make the alert message "Recoverable Alert".
  7344.         ; ELSE
  7345.         ;   Make the alert message "Software Failure".
  7346.         ; ENDIF
  7347.  
  7348.         ; When the alert is finished (the user pressed the mouse button),
  7349.         ; the LastAlert field in ExecBase is cleared to -1, and the longword
  7350.         ; at location 0 is cleared to zero.
  7351.  
  7352.  
  7353. @d
  7354.  
  7355. @40dDelay for a while.
  7356. @d
  7357. @d
  7358. @d
  7359.  
  7360. @40dGet the alert number.
  7361. @40dCompare to -1 (indicates no alert).
  7362. @d
  7363. @40dExit if equal.
  7364. @40dReserve 200 bytes of stack space.
  7365. @40dPoint to base of reserved area.
  7366.  
  7367.         ; Decide which alert message to use.
  7368.  
  7369. @40dPoint to "Software Failure" string.
  7370. @40dGet the alert number.
  7371. @40dGet the general error number.
  7372. @40dIs it an AG_NoMemory type of alert?
  7373. @40dIf so, point to "Not enough Memory"
  7374. @40dstring.
  7375. @d
  7376. @40dIf otherwise, check the dead-end
  7377. @40dalert flag.  If it is clear, but
  7378. @40dthe Subsystem/General error fields
  7379. @40dare not zero, then point to the
  7380. @40d"Recoverable Alert" string.
  7381.  
  7382. @40dCopy the string into the buffer.
  7383. @40dPoint to "Press left mouse button..."
  7384. @40dCopy the string into the buffer.
  7385. @40dPut a zero into the buffer.
  7386. @40dPoint to "Guru Meditation..." string.
  7387. @40dPoint to alert data.
  7388. @40dPoint to character output routine.
  7389. @40dRawDoFmt()
  7390.  
  7391. @40dPoint to "intuition.library".
  7392. @40dMinimum version is 0 (any).
  7393. @40dOpenLibrary()
  7394. @40dDid it open OK?
  7395. @40dIf not, skip the following.
  7396. @40dSave ExecBase.
  7397. @40dGet IntuitionBase.
  7398. @40dTell intuition that the alert # is 0.
  7399. @40dPoint to the alert string.
  7400. @40dAlert should be 40 video lines high.
  7401. @40dDisplayAlert()
  7402. @d
  7403. @40dGet IntuitionBase.
  7404. @40dRestore ExecBase.
  7405. @40dCloseLibrary()
  7406.  
  7407. @40dDeallocate string space on stack.
  7408. @40dRemove "HELP" at 0, if present.
  7409. @d
  7410. @40dSet LastAlert to -1.
  7411.  
  7412.         ; Set the return code.  If intuition.library didn't open, A2 contains
  7413.         ; a non-zero address, so a non-zero return value results.  If
  7414.         ; intuition could be called, this is the return code from the
  7415.         ; DisplayAlert() call.
  7416.  
  7417. @40dSet return code.
  7418. @d
  7419. @d
  7420.  
  7421.         ; Character output routine for RawDoFmt() while putting together
  7422.         ; the "Guru Meditation #..." message.
  7423.  
  7424. @40dPut character in buffer.
  7425. @40dZero-terminate the buffer.
  7426. @d
  7427.  
  7428.         ; Routine to copy a given string to the output buffer while
  7429.         ; building the guru message.
  7430.  
  7431. @40dPut a zero into the buffer.
  7432. @40dCopy the given string.
  7433. @d
  7434. @40dTerminate buffer with $FF.
  7435. @d
  7436.  
  7437.         ; Strings used for the guru message.
  7438.  
  7439. @8p@,22s
  7440. @8p@,21s
  7441. @8p@,22s
  7442. @8p@,39s
  7443. @8p@,31s
  7444.  
  7445.         ; Name used to open intuition to put up the alert.
  7446.  
  7447. @8p@,18s
  7448.  
  7449.  
  7450.         ; The "alert.hook" mechanism
  7451.         ; --------------------------
  7452.  
  7453.         ; This is a RomTag.  At system startup, this will be found and added
  7454.         ; to the resident module list.  Since it has the RTW_COLDSTART flag
  7455.         ; set, it will be initialized along with the other libraries,
  7456.         ; devices, etc.  The RTF_AUTOINIT flag is not set, therefore, the
  7457.         ; code at RT_INIT is called.
  7458.  
  7459.         ; The code at RT_INIT is the Guru routine.  This reads the LastAlert
  7460.         ; field in ExecBase.  If this is not -1, then an alert is still
  7461.         ; outstanding (from before the reboot), and this puts it up, lets
  7462.         ; the user click the mouse button, then returns.  The resident
  7463.         ; module initialization then continues, the DOS boots, and the
  7464.         ; system comes up.
  7465.  
  7466.         ; The purpose of all this is to allow the system to defer display
  7467.         ; of a guru message until after the system has been cold-started.
  7468.  
  7469.  
  7470. @8p@,13s
  7471.  
  7472. @a?fc323a
  7473. @8p@24wRTC_MATCHWORD   (start of ROMTAG marker)
  7474. @8p@24lRT_MATCHTAG     (pointer RTC_MATCHWORD)
  7475. @8p@24lRT_ENDSKIP      (pointer to end of code)
  7476. @8p@24bRT_FLAGS        (RTW_COLDSTART)
  7477. @8p@24bRT_VERSION      (33 decimal)
  7478. @8p@24bRT_TYPE         (NT_UNKNOWN)
  7479. @8p@24bRT_PRI          (priority = 5)
  7480. @8p@24lRT_NAME         (pointer to name)
  7481. @8p@24lRT_IDSTRING     (pointer to ID string)
  7482. @8p@24lRT_INIT         (execution address)
  7483.  
  7484.  
  7485.         ; ROM-Wack command dispatch tables ("Key bindings").
  7486.         ; --------------------------------------------------
  7487.  
  7488.         ; ROM-Wack can be in one of two modes when a key is pressed.  It can
  7489.         ; be waiting for a command, or it can be in the process of gathering
  7490.         ; a multi character command.  The two tables below decide what to do
  7491.         ; with the key in each case.
  7492.  
  7493.         ; Each table entry has 4 fields.  These are, address of next table
  7494.         ; entry to try if key doesn't match this one, lowest key value for
  7495.         ; this table entry, highest key value (if several) or zero, address
  7496.         ; to jump to.
  7497.  
  7498.         ; Primary command dispatch table.
  7499.  
  7500. @8p@9l@3b@3b@17l^D
  7501. @8p@9l@3b@3b@17l<Return>
  7502. @8p@9l@3b@3b@17l<Tab>
  7503. @8p@9l@3b@3b@17l?
  7504. @8p@9l@3b@3b@17l.
  7505. @8p@9l@3b@3b@17l,
  7506. @8p@9l@3b@3b@17l>
  7507. @8p@9l@3b@3b@17l<
  7508. @8p@9l@3b@3b@17l<Backspace>
  7509. @8p@9l@3b@3b@17l<Space>
  7510. @8p@9l@3b@3b@17l[
  7511. @8p@9l@3b@3b@17l]
  7512. @8p@9l@3b@3b@17l:
  7513. @8p@9l@3b@3b@17l+
  7514. @8p@9l@3b@3b@17l-
  7515. @8p@9l@3b@3b@17l=
  7516. @8p@9l@3b@3b@17l!
  7517. @8p@9l@3b@3b@17l^
  7518. @8p@9l@3b@3b@17l_
  7519. @8p@9l@3b@3b@17l0 - 9
  7520. @8p@9l@3b@3b@17la - z
  7521. @8p@9l@3b@3b@17lA - Z
  7522.  
  7523. @8p@32lEnd of table marker.
  7524.  
  7525.  
  7526.         ; Secondary command dispatch table (used while a command
  7527.         ; and/or address is being typed).
  7528.  
  7529. @8p@9l@3b@3b@17l<Backspace>
  7530. @8p@9l@3b@3b@17l<Return>
  7531. @8p@9l@3b@3b@17l<CTRL-X>
  7532. @8p@9l@3b@3b@17l<CTRL-U>
  7533. @8p@9l@3b@3b@17l>
  7534. @8p@9l@3b@3b@17l<
  7535. @8p@9l@3b@3b@17l<Space>
  7536. @8p@9l@3b@3b@17l_
  7537. @8p@9l@3b@3b@17l0 - 9
  7538. @8p@9l@3b@3b@17la - z
  7539. @8p@9l@3b@3b@17lA - Z
  7540.  
  7541. @8p@32lEnd of table marker.
  7542.  
  7543.  
  7544.         ; Table of multi-character ROM-Wack commands.
  7545.  
  7546. @8p@,22s
  7547. @8p@,22s
  7548. @8p@,22s
  7549. @8p@,12s
  7550.  
  7551.  
  7552.         ; Dispatch table for multicharacter commands.
  7553.  
  7554.         ; The fields are link to next table entry, address of command string,
  7555.         ; an unused value (presumably from a larger version of Wack), and
  7556.         ; the address to jump to for that command.
  7557.  
  7558. @a?fc33f4
  7559. @8p@9l@9l@5w@13l"alter"
  7560. @8p@9l@9l@5w@13l"boot"
  7561. @8p@9l@9l@5w@13l"clear"
  7562. @8p@9l@9l@5w@13l"fill"
  7563. @8p@9l@9l@5w@13l"find"
  7564. @8p@9l@9l@5w@13l"go"
  7565. @8p@9l@9l@5w@13l"ig"
  7566. @8p@9l@9l@5w@13l"limit"
  7567. @8p@9l@9l@5w@13l"list"
  7568. @8p@9l@9l@5w@13l"regs"
  7569. @8p@9l@9l@5w@13l"reset"
  7570. @8p@9l@9l@5w@13l"resume"
  7571. @8p@9l@9l@5w@13l"set"
  7572. @8p@9l@9l@5w@13l"show"
  7573. @8p@9l@9l@5w@13l"user"
  7574. @8p@l
  7575.  
  7576. @8p@32wPadding.
  7577.  
  7578.         ; That's it.  The next RomTag (for the audio.device) comes right
  7579.         ; after the two bytes of padding shown above.
  7580.