home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d1xx / d188 / execdis.lha / ExecDis / dis.data < prev    next >
Text File  |  1989-02-26  |  214KB  |  7,594 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 more entries remain, loop.
  1656.  
  1657.         ; When we come out of the loop, if the zero flag is set, we were
  1658.         ; unable to reclaim a piece of memory specified in the MemList.
  1659.         ; In this case, return zero and exit.  Otherwise, we have allocated
  1660.         ; them all and go on to the next MemList.
  1661.  
  1662. @36dIf failed, go exit.
  1663. @36dElse proces next MemList.
  1664. @36dIndicate all is OK.
  1665. @d
  1666.  
  1667.  
  1668. ---------------------------------------------------------------------------
  1669.   resident = FindResident( name )
  1670.   D0                       A1
  1671. ---------------------------------------------------------------------------
  1672.  
  1673. @d
  1674. @36dGet pointer to the resident module table.
  1675. @d
  1676.  
  1677.         ; Outer loop:  Step through the table(s) of RomTags, looking
  1678.         ; for one whose name matches the wanted one.
  1679.  
  1680. @36dGet a RomTag address from the table.
  1681. @36dReturn zero if end of table reached.
  1682. @36dIf table entry is a link then
  1683. @38dclear its high bit.
  1684. @38duse it as a new table pointer.
  1685. @38dGo to the top of the loop.
  1686. @36dEndif
  1687. @36dGet pointer to desired name.
  1688. @36dPoint to RomTag's name field.
  1689.  
  1690.         ; Inner loop:  Compare the wanted name with that in the RomTag.
  1691.  
  1692. @36dCompare a character.
  1693. @36dBack to top of loop if not equal.
  1694. @36dDid we reach the terminating zeros?
  1695. @36dCompare more characters if not.
  1696.  
  1697.         ; Fall through with the module's address in D0.
  1698.  
  1699. @d
  1700. @d
  1701.  
  1702.  
  1703. ---------------------------------------------------------------------------
  1704.   InitCode( startClass, version )
  1705.             D0          D1
  1706. ---------------------------------------------------------------------------
  1707.  
  1708.         ; This function initializes modules from the resident module list.
  1709.  
  1710.         ; The resident module list is one or more tables of RomTag addresses.
  1711.         ; Such tables can be linked together by including the address of the
  1712.         ; next table, with the high bit set, as the last address in a table.
  1713.  
  1714.         ; We are given a set of required flags in D0, and a minimum
  1715.         ; version number in D1.  Modules which have flags not set whose bits
  1716.         ; appear in D0, or are of a lower version than D1, will not be
  1717.         ; initialized.
  1718.  
  1719. @d
  1720. @40dGet the ResModules pointer.
  1721. @40dGet forbidden flags.
  1722. @40dGet cutoff version number.
  1723. @40dRead a module address from the table.
  1724. @40dExit if end of table reached.
  1725. @40dIs the high bit set?  If so, it's
  1726. @40da pointer to another table, so strip
  1727. @40dthe high bit off, point to the next
  1728. @40dtable, and process it.
  1729.  
  1730. @40dCheck the module's version number
  1731. @40dagainst the cutoff.
  1732. @40dIgnore module if too low.
  1733. @40dGet the module's flags.
  1734. @40dCheck against mask.
  1735. @40dIgnore it if required ones not set.
  1736. @d
  1737. @40dInitResident()
  1738. @40dProcess next resident module.
  1739. @d
  1740. @d
  1741.  
  1742.  
  1743. ---------------------------------------------------------------------------
  1744.   InitResident( resident, segList )
  1745.                 A1        D1
  1746. ---------------------------------------------------------------------------
  1747.  
  1748.         ; This initializes a resident module.  The pointer to the module
  1749.         ; is in register A1.  If the RT_FLAGS byte at offset 10 from
  1750.         ; the module pointer has the RTF_AUTOINIT flag set, we let the
  1751.         ; module initialize itself by calling its initialization code.
  1752.  
  1753.         ; Otherwise we assume it's a library type of thing, and call
  1754.         ; MakeLibrary with a set of parameters taken from the module.
  1755.         ; If the MakeLibrary succeeds, we add the module to the appropriate
  1756.         ; system list.
  1757.  
  1758. @40dCheck the RTF_AUTOINIT flag.
  1759. @d
  1760. @40dGet the RT_INIT address.
  1761. @d
  1762. @40dGet the segList pointer.
  1763. @40dCall the module's init code.
  1764. @d
  1765.  
  1766.         ; The RTF_AUTOINIT flag was not set, so we MakeLibrary() the
  1767.         ; module instead.  Note that the address at RT_INIT points to
  1768.         ; a data structure containing parameters for MakeLibrary().
  1769.  
  1770. @d
  1771. @40dGet the initialization address.
  1772. @40dGet parameters for MakeLibrary.
  1773. @40dMakeLibrary()
  1774. @d
  1775. @40dStore the library pointer.
  1776. @40dIf zero, just return it and exit.
  1777.  
  1778.         ; The library has been created successfully.
  1779.  
  1780. @40dGet the library pointer.
  1781. @40dGet the module's node type.
  1782. @40dIf the node type is NT_DEVICE then
  1783. @d
  1784. @42dAddDevice().
  1785. @d
  1786. @40dElse if it is NT_LIBRARY then
  1787. @d
  1788. @42dAddLibrary().
  1789. @d
  1790. @40dElse if it is NT_RESOURCE then
  1791. @d
  1792. @42dAddResource().
  1793. @40dEndif.
  1794. @d
  1795.  
  1796.  
  1797.         ; InitStruct entry point to copy one byte several times (-186).
  1798.  
  1799. @40dGet the byte initially.
  1800. @40dCopy it the required number of times.
  1801. @d
  1802. @40dBack to main loop.
  1803.  
  1804.         ; Entry ponint for invalid InitStruct commands (-176).  Guru time.
  1805.  
  1806. @40dSave registers.
  1807. @40dAlert number (fatal).
  1808. @40dGet ExecBase
  1809. @40dPut up the Alert.
  1810. @40dThis never gets executed.
  1811.  
  1812.         ; InitStruct entry point to copy one longword several times (-154).
  1813.  
  1814. @40dRound A1 up to next even address.
  1815. @d
  1816. @d
  1817. @d
  1818. @40dGet the longword initially.
  1819. @40dCopy it the required number of times.
  1820. @d
  1821. @40dBack to main loop.
  1822.  
  1823.         ; InitStruct entry point to copy one word several times (-134).
  1824.  
  1825. @40dRound A1 up to next even address.
  1826. @d
  1827. @d
  1828. @d
  1829. @40dGet the word initially.
  1830. @40dCopy it the required number of times.
  1831. @d
  1832. @40dBack to main loop.
  1833.  
  1834.  
  1835. ---------------------------------------------------------------------------
  1836.   InitStruct( initTable, memory, size )
  1837.               A1         A2      D0
  1838. ---------------------------------------------------------------------------
  1839.  
  1840. @36dGet structure base address.
  1841. @36dDivide size by 2 (get size in words)
  1842. @d
  1843. @36dLoop: Clear the structure's memory.
  1844. @d
  1845.  
  1846. @36dGet structure base address again.
  1847. @d
  1848. @36dRead a byte from the initTable.
  1849. @36dIf it is zero, we're done.
  1850. @36dCheck and reset offset flag.
  1851. @36dBranch if it was not set.
  1852.  
  1853.         ; Process an offset command (10ssnnnn or 11ssnnnn).
  1854.  
  1855. @36dCheck and reset byte/rptr flag.
  1856. @36dBranch if it was not set.
  1857. @36dBack up over command byte.
  1858. @36dGet cmd byte + 24 bit data.
  1859. @36dMask out the command byte.
  1860. @d
  1861.  
  1862.         ; Process an offset/byte command (10ssnnnn).
  1863.  
  1864. @d
  1865. @36dGet next byte from table into D1.
  1866.  
  1867.         ; Continue here for both offset commands.  In each case, A1 now
  1868.         ; points at the next even address in the initTable, and D1 contains
  1869.         ; the offset we have just fetched from it, as a longword.
  1870.  
  1871. @36dGet structure base address.
  1872. @36dAdd offset just computed.
  1873.  
  1874.         ; Continue here for all commands,  A0 now holds the absolute
  1875.         ; address where the next operand should go, D0 contains what is
  1876.         ; left of the command byte, and A1 points at the current even
  1877.         ; address in the table.
  1878.  
  1879. @38dGet the command byte
  1880. @38dShift and mask it so it becomes
  1881. @38d2 * (sdd)
  1882. @38dGet the jump offset from the table.
  1883. @38dMask all but (nnnn) out of the command.
  1884. @38dJump to the right routine.
  1885.  
  1886.         ; Entry point for copying multiple bytes (-42).
  1887.  
  1888. @36dCopy one byte.
  1889. @36dLoop until required number done.
  1890.  
  1891. @36dRound A1 up to next even address.
  1892. @d
  1893. @d
  1894. @d
  1895. @36dGo back to main loop.
  1896.  
  1897.         ; Entry point for copying multiple longwords (-24).
  1898.  
  1899.         ; Simply falls through to word copy routine, set up to copy twice as
  1900.         ; many words.  An extra 1 must be added to compensate for the effects
  1901.         ; of the "dbra" instruction.
  1902.  
  1903. @36dD0 = (2 * D0) + 1.
  1904. @d
  1905.  
  1906.         ; Entry point for copying multiple words (-20).
  1907.  
  1908. @36dRound A1 up to next even address.
  1909. @d
  1910. @d
  1911. @d
  1912. @36dMove the data.
  1913. @d
  1914. @36dGo back to top of main loop.
  1915.  
  1916. @d
  1917.  
  1918.         ; Dispatch table for InitStruct.
  1919.  
  1920. @8p@10w-24               (sdd = 000) longword, count.
  1921. @8p@10w-20               (sdd = 001) word, count.
  1922. @8p@10w-42               (sdd = 010) byte, count.
  1923. @8p@10w-176              (sdd = 011) Invalid.
  1924. @8p@10w-154              (sdd = 100) longword, repeat.
  1925. @8p@10w-134              (sdd = 101) word, repeat.
  1926. @8p@10w-186              (sdd = 110) byte, repeat.
  1927. @8p@10w-176              (sdd = 111) Invalid.
  1928.  
  1929. @8p@28w                  Padding.
  1930.  
  1931.  
  1932.         ; The following is used to bail out of an interrupt which we should
  1933.         ; have ignored.
  1934.  
  1935. @d
  1936. @d
  1937.  
  1938.         ; Level 1 Autovector interrupt entry point.
  1939.         ; -----------------------------------------
  1940.  
  1941. @d
  1942.  
  1943. @36dPoint to custom chip register area.
  1944. @36dGet ExecBase.
  1945. @36dGet interrupt enable register.
  1946. @36dCheck master interrupt enable.
  1947. @36dBail out if no interrupts enabled.
  1948. @36dCheck for pending & enabled interrupts.
  1949.  
  1950. @36dSerial port transmit interrupt?
  1951. @d
  1952. @36dGet IntVects[0] handler data.
  1953. @36dPush address of ExitIntr()
  1954. @d
  1955.  
  1956. @36dDisk block finished interrupt?
  1957. @d
  1958. @36dGet IntVects[1] handler data.
  1959. @36dPush address of ExitIntr()
  1960. @d
  1961.  
  1962. @36dSoftware generated interrupt?
  1963. @d
  1964. @36dGet IntVects[2] handler data.
  1965. @36dPush address of ExitIntr()
  1966. @d
  1967.  
  1968. @36dBail out if nothing found.
  1969.  
  1970.         ; Level 2 Autovector interrupt entry point.
  1971.         ; -----------------------------------------
  1972.  
  1973. @d
  1974.  
  1975. @36dSee level 1 for comments.
  1976. @d
  1977. @d
  1978. @d
  1979. @d
  1980. @d
  1981.  
  1982. @36dI/O port or timer interrupt?
  1983. @d
  1984. @36dGet IntVects[3] handler data.
  1985. @36dPush address of ExitIntr()
  1986. @d
  1987.  
  1988. @36dBail out if nothing found.
  1989.  
  1990.         ; Level 3 Autovector interrupt entry point.
  1991.         ; -----------------------------------------
  1992.  
  1993. @a?fc0cd8
  1994. @d
  1995.  
  1996. @36dSee level 1 for comments.
  1997. @d
  1998. @d
  1999. @d
  2000. @d
  2001. @d
  2002.  
  2003. @36dBlitter finished?
  2004. @d
  2005. @36dGet IntVects[6] handler data.
  2006. @36dPush address of ExitIntr()
  2007. @d
  2008.  
  2009. @36dStart of vertical blank?
  2010. @d
  2011. @36dGet IntVects[5] handler data.
  2012. @36dPush address of ExitIntr()
  2013. @d
  2014.  
  2015. @36dCopper interrupt?
  2016. @d
  2017. @36dGet IntVects[4] handler data.
  2018. @36dPush address of ExitIntr()
  2019. @d
  2020.  
  2021. @36dBail out if nothing found.
  2022.  
  2023.         ; Level 4 Autovector interrupt entry point.
  2024.         ; -----------------------------------------
  2025.  
  2026. @d
  2027.  
  2028. @36dSee level 1 for comments.
  2029. @d
  2030. @d
  2031. @d
  2032. @d
  2033. @d
  2034.  
  2035. @36dAudio channel 1?
  2036. @d
  2037. @36dGet IntVects[8] handler data.
  2038. @36dUse special ExitIntr() below.
  2039. @d
  2040. @a?fc0d62
  2041.  
  2042. @36dAudio channel 3?
  2043. @d
  2044. @36dGet IntVects[10] handler data.
  2045. @36dUse special ExitIntr() below.
  2046. @d
  2047.  
  2048. @36dAudio channel 0?
  2049. @d
  2050. @36dGet IntVects[7] handler data.
  2051. @36dUse special ExitIntr() below.
  2052. @d
  2053.  
  2054. @36dAudio channel 2?
  2055. @d
  2056. @36dGet IntVects[9] handler data.
  2057. @36dUse special ExitIntr() below.
  2058. @d
  2059.  
  2060. @36dBail out if nothing found.
  2061.  
  2062.         ; This routine allows a single invocation of the level 4 interrupt
  2063.         ; handler to service all level 4 interrupts which are pending or
  2064.         ; become pending while one is serviced.
  2065.  
  2066. @36dPoint at custom chip register area.
  2067. @36dGet ExecBase.
  2068. @36dMask for all level 4 interrupt bits.
  2069. @d
  2070. @36dFind enabled and pending level 4 ints.
  2071. @36dIf any still pending, go service them.
  2072.  
  2073. @36dOtherwise, do ExitIntr()
  2074.  
  2075.         ; Level 5 Autovector interrupt entry point.
  2076.         ; -----------------------------------------
  2077.  
  2078. @d
  2079.  
  2080. @36dSee level 1 for comments.
  2081. @d
  2082. @d
  2083. @d
  2084. @d
  2085. @d
  2086.  
  2087. @36dDisk sync interrupt?
  2088. @d
  2089. @36dGet IntVects[12] handler data.
  2090. @36dPush address of ExitIntr()
  2091. @d
  2092.  
  2093. @36dSerial port receive interrupt?
  2094. @d
  2095. @36dGet IntVects[11] handler data.
  2096. @36dPush address of ExitIntr()
  2097. @d
  2098.  
  2099. @36dBail out if nothing found.
  2100.  
  2101.         ; Level 6 Autovector interrupt entry point.
  2102.         ; -----------------------------------------
  2103.  
  2104. @d
  2105.  
  2106. @36dSee level 1 for comments.
  2107. @d
  2108. @d
  2109. @d
  2110. @d
  2111. @d
  2112.  
  2113. @36dSpecial copper interrupt?
  2114. @d
  2115. @36dGet IntVects[14] handler data.
  2116. @36dPush address of ExitIntr()
  2117. @d
  2118.  
  2119. @36dExternal level 6 interrupt?
  2120. @d
  2121. @36dGet IntVects[13] handler data.
  2122. @36dPush address of ExitIntr()
  2123. @d
  2124.  
  2125. @36dBail out if nothing found.
  2126.  
  2127.         ; Level 7 Autovector interrupt entry point.
  2128.         ; -----------------------------------------
  2129.  
  2130. @d
  2131. @d
  2132. @36d  Get IntVects[15] handler data.
  2133. @d
  2134. @d
  2135. @d
  2136.  
  2137.  
  2138. ---------------------------------------------------------------------------
  2139.   ExitIntr()
  2140. ---------------------------------------------------------------------------
  2141.  
  2142.         ; This routine is called after an interrupt handler has finished.
  2143.         ; It checks if a task switch is necessary.  If not, it returns
  2144.         ; from the interrupt.  Otherwise, it drops into the scheduler.
  2145.  
  2146.         ; The initial check for supervisor mode is very important.  If
  2147.         ; the CPU was in supervisor mode, then there either was no task
  2148.         ; running (CPU stopped), or the task had already been interrupted
  2149.         ; by a lower priority interrupt.  In either case, we may not do
  2150.         ; a task switch.  In the former case, it will be done after the
  2151.         ; CPU comes out of the STOP instruction in the dispatcher, and
  2152.         ; in the latter, it will be taken care of by the lowest priority
  2153.         ; interrupt handler (which interrupted the CPU while it was not
  2154.         ; in supervisor mode).
  2155.  
  2156. @38dCheck if CPU was in supervisor mode.
  2157. @38dIf so, just return from interrupt.
  2158. @38dGet ExecBase.
  2159. @38dSee if task switching is disabled.
  2160. @38dIf so, just return from interrupt.
  2161.  
  2162. @38dCheck the scheduling attention flag.
  2163. @38dReturn from interrupt if not set.
  2164.  
  2165. @a?fc0e7a
  2166. FC0E7A  move.w    #$2000,SR           Enable all interrupts.
  2167. @a=fc0e7e
  2168. @d
  2169.  
  2170. @d
  2171. @d
  2172.  
  2173.  
  2174. ---------------------------------------------------------------------------
  2175.   Schedule()
  2176. ---------------------------------------------------------------------------
  2177.  
  2178.         ; This is the scheduler.  It is called with the current task's
  2179.         ; registers saved on the system stack, as put there by the interrupt
  2180.         ; entry point, and PC/SR as put there by the interrupt itself.
  2181.         ;
  2182.         ; The scheduler checks if the task should be suspended and another
  2183.         ; task run in its place.  The following decision is made:
  2184.         ;
  2185.         ; IF the current task has an exception pending THEN
  2186.         ;    reschedule the current task, so that it will be redispatched,
  2187.         ;    so that the dispatcher can process the exception.
  2188.         ; ELSEIF the TaskReady queue is empty THEN
  2189.         ;    the current task is the only runnable task in the system, so
  2190.         ;    let it continue running.
  2191.         ; ELSEIF the TaskReady queue contains a higher priority task THEN
  2192.         ;    do a task switch.
  2193.         ; ELSEIF the current task's time slice has expired THEN
  2194.         ;    reschedule the current task (it may be redispatched right away,
  2195.         ;    with a new time slice).
  2196.         ; ELSE
  2197.         ;    let the current task keep running.
  2198.         ; ENDIF
  2199.  
  2200. @d
  2201. @a?fc0e8a
  2202. FC0E8A  move.w    #$2700,SR           Mask all maskable interrupts.
  2203. @a=fc0e8e
  2204. @38dReset the scheduling attention flag.
  2205. @38dGet the current task pointer.
  2206. @38dCheck the task's TB_EXCEPT flag.
  2207. @d
  2208. @38dPoint to the TaskReady queue.
  2209. @38dCheck if the queue is empty.
  2210. @38dIf so, return from interrupt.
  2211. @38dGet the queue's head node.
  2212. @38dGet the head node's priority.
  2213. @38dCompare to the current task's priority.
  2214. @38dSwitch tasks if higher priority.
  2215. @38dCheck the time slice expired flag.
  2216. @38dIf not expired, return from interrupt.
  2217.  
  2218.         ; If we get this far, it is necessary to put the current task on
  2219.         ; the TaskReady queue and then run the one at the head of the queue.
  2220.         ; This may be the same one if a TB_EXCEPT is being processed.
  2221.  
  2222. @38dPoint to the TaskReady queue.
  2223. @38dEnqueue the current task.
  2224. @38dMake the task's state TS_READY.
  2225. @a?fc0ecc
  2226. FC0ECC  move.w    #$2000,SR           Enable all interrupts.
  2227. @a=fc0ed0
  2228.  
  2229.         ; Get the current task's saved registers back.  They may have been
  2230.         ; put on the stack when an interrupt occurred, or at the start of
  2231.         ; this routine.
  2232.  
  2233. @d
  2234.  
  2235. @38dInsert some space in the system stack.
  2236. @38dPut in the address of Switch().
  2237. @38dGet A6 from the stack.
  2238. @38dGo to Switch().
  2239.  
  2240.  
  2241. ---------------------------------------------------------------------------
  2242.   Switch()
  2243.  
  2244.   [Version for machines without a numeric coprocessor]
  2245. ---------------------------------------------------------------------------
  2246.  
  2247.         ; The ExecBase "Switch()" vector points here if no FPP is installed.
  2248.  
  2249.         ; This routine does a task switch.  It stores the context of
  2250.         ; the currently running task, then drops into the dispatcher.
  2251.  
  2252.         ; The routine stores the current CPU context on the user
  2253.         ; stack.  The status register and program counter are popped from
  2254.         ; the supervisor stack.  The current interrupt disable nesting
  2255.         ; level and the user stack pointer are then saved in this task's
  2256.         ; task descriptor.
  2257.  
  2258.         ; If the TB_SWITCH bit is set in the task descriptor, the task's
  2259.         ; TC_SWITCH function is called.
  2260.  
  2261. @a?fc0ee0
  2262. FC0EE0  move      #$2000,SR             Enable all interrupts.
  2263. @a=fc0ee4
  2264. @40dStack A5 on the supervisor stack.
  2265. @40dGet the user stack pointer.
  2266. @40dStack all registers on user stack.
  2267.  
  2268. @40dGet ExecBase
  2269.  
  2270. @40dGet current interrupt disable level.
  2271. @40dSet interrupt disable level to -1.
  2272. @40dEnable interrupts.
  2273.  
  2274. @40dFix A5 in the saved register set.
  2275. @40dSave the status register.
  2276. @40dSave the program counter.
  2277.  
  2278. @40dAddress of context-restore routine
  2279.                                         for machines without an FPP.
  2280.  
  2281. @40dFind the current task descriptor.
  2282. @40dStore interrupt disable level.
  2283. @40dStore user stack pointer.
  2284. @40dCheck the TB_SWITCH bit
  2285. @d
  2286. @40dIf TB_SWITCH bit was set, then
  2287. @40dcall this task's TC_SWITCH function.
  2288. @d
  2289.  
  2290.  
  2291. ---------------------------------------------------------------------------
  2292.   Dispatch()
  2293.  
  2294.   [Version for machines without a numeric coprocessor]
  2295. ---------------------------------------------------------------------------
  2296.  
  2297.         ; This routine dispatches the next runnable task, if there is one.
  2298.  
  2299.         ; If the TaskReady queue is empty, the routine waits, stopping
  2300.         ; the processor and checking the queue again each time it resumes
  2301.         ; running (after an interrupt).
  2302.  
  2303.         ; When a runnable task is found, it is dispatched.  Its context
  2304.         ; and interrupt disable level are restored, and the TB_LAUNCH
  2305.         ; and TB_EXCEPT flags are checked.  If either is set, they are
  2306.         ; handled.
  2307.  
  2308. @40dAddress of context-restore routine
  2309.                                         for machines without an FPP.
  2310.  
  2311. @40dInitialize interrupt disable level
  2312. @40dat -1, and enable interrupts.
  2313.  
  2314. @40dPoint at the TaskReady queue.
  2315. @a?fc0f40
  2316. FC0F40  move      #$2700,SR             Mask all maskable interrupts.
  2317. @a=fc0f44
  2318. @40dCheck for a task descriptor at
  2319. @40dthe front of the queue.
  2320. @d
  2321.  
  2322.         ; TaskReady queue is empty.  Halt the processor until the next
  2323.         ; interrupt, then check for runnable tasks again.
  2324.  
  2325. @40dIncrement the idle counter.
  2326. @40dSet the rescheduling attention flag.
  2327. @a?fc0f54
  2328. FC0F54  stop      #$2000                Enable all interrupts and stop.
  2329. @a=fc0f56
  2330. @d
  2331. @40dGo back and check for runnable tasks.
  2332.  
  2333.         ; We have a runnable task.
  2334.  
  2335. @40dUnlink the task descriptor from
  2336. @40dthe TaskReady queue.
  2337. @d
  2338. @40dIncrement the dispatch counter.
  2339.  
  2340. @40dSet the current task pointer.
  2341.  
  2342. @40dInitialize the time-slice counter.
  2343.  
  2344. @40dReset the time slice expired flag.
  2345. @40dSet the task's state to TS_RUN.
  2346.  
  2347. @40dRestore the interrupt disable level.
  2348. @d
  2349. @40dDisable interrupts if interrupt
  2350. @40ddisable level >= 0.
  2351.  
  2352. @a?fc0f90
  2353. FC0F90  move      #$2000,SR             Enable all interrupts.
  2354. @a=fc0f94
  2355. @40dGet the task's flags.
  2356. @40dCheck for TB_EXCEPT or TB_LAUNCH.
  2357. @d
  2358. @40dProcess the flags if either was set.
  2359.  
  2360. @40dGet the user stack pointer.
  2361.  
  2362. @40dRestore the CPU context.
  2363.  
  2364.  
  2365.         ; Context Restore routine (non-FPP version)
  2366.         ; -----------------------------------------
  2367.  
  2368.         ; Pop the task's CPU context off the user stack, and start it
  2369.         ; running.  The program counter and status register are set by
  2370.         ; storing them on the supervisor stack for the "RTE" instruction.
  2371.  
  2372. @40dGet the user stack pointer.
  2373. @40dSet it.
  2374. @40dGet the program counter.
  2375. @40dGet the status register.
  2376. @40dRestore all the other registers.
  2377. @40dAnd start running the task.
  2378.  
  2379.         ; Subroutine to handle TB_LAUNCH and TB_EXCEPT.
  2380.  
  2381. @40dCheck the TB_LAUNCH bit.
  2382. @d
  2383. @40dIf it was set, call the task's
  2384. @40dTC_LAUNCH routine.
  2385. @d
  2386. @40dRestore D0.
  2387. @40dCheck the TB_EXCEPT bit.
  2388. @d
  2389. @40dReturn if it was clear.
  2390.  
  2391.  
  2392. ---------------------------------------------------------------------------
  2393.   Exception()
  2394. ---------------------------------------------------------------------------
  2395.  
  2396.         ; This routine handles task-level exception processing.
  2397.  
  2398.         ; It checks whether any signals have occurred which should cause
  2399.         ; a software exception.  If so, it calls the task's exception
  2400.         ; processing routine.  After this returns, it restores everything
  2401.         ; so that the task itself can be dispatched.
  2402.  
  2403. @40dReset the TB_EXCEPT bit.
  2404.  
  2405. @40dDisable()
  2406. @d
  2407.  
  2408. @40dGet received signals.
  2409. @40dCompare with exception signals.
  2410. @40dIf any exception signals were set,
  2411. @40dreset them in both places.
  2412.  
  2413. @40dEnable()
  2414. @d
  2415. @d
  2416.  
  2417. @40dGet the user stack pointer.
  2418.  
  2419.         ; Store tc_Flags, tc_State, tc_IDNestCnt, tc_TDNestCnt on user stack.
  2420.  
  2421. @d
  2422.  
  2423.         ; If interrupts have been disabled exactly once, then enable them.
  2424.  
  2425. @d
  2426. @d
  2427. @d
  2428. @d
  2429. @d
  2430.  
  2431.         ; Put the address of an exception post-processing routine on the
  2432.         ; user stack.  This gets executed when the exception routine
  2433.         ; does an RTS.
  2434.  
  2435. @40dPut return address on user stack.
  2436. @40dSet user stack pointer.
  2437. @40dSee if this is a plain 68000.
  2438. @d
  2439. @40dMake 68010/020 extended stack frame.
  2440.  
  2441. @40dPut exception code and a fake status
  2442. @40dword on the supervisor stack.
  2443. @40dPoint to the exception handler's
  2444.                                         data segment.
  2445. @d
  2446.  
  2447.         ; Continue here after the user's exception handling routine has run.
  2448.  
  2449. @40dGet ExecBase.
  2450. @40dWhere to go in supervisor mode.
  2451. @40dGo to supervisor mode.
  2452.  
  2453. @40dAddress of context restore routine.
  2454.  
  2455. @40dIs this a 68010/020?
  2456. @d
  2457. @40dIf so, handle extended stack frame.
  2458.  
  2459. @40dDo we have a 688881?
  2460. @d
  2461. @40dIf so, use the other context-restore.
  2462.  
  2463. @40dPop PC and SR from stack.
  2464. @40dGet current task descriptor.
  2465. @40dSet the exception signals up again.
  2466. @40dGet the user stack pointer.
  2467.  
  2468.         ; Restore tc_Flags, tc_State, tc_IDNestCnt, tc_TDNestCnt from
  2469.         ; user stack.
  2470.  
  2471. @d
  2472. @40dSet USP image in task descriptor.
  2473. @40dRestore interrupt disable level.
  2474. @d
  2475. @d
  2476. @40dDisable interrupts if needed.
  2477. @d
  2478.  
  2479.  
  2480. ---------------------------------------------------------------------------
  2481.   Switch()
  2482.  
  2483.   [Version for machines with a 68881 FPP]
  2484. ---------------------------------------------------------------------------
  2485.  
  2486. @a?fc108a
  2487. FC108A  move      #$2000,SR             Enable all interrupts.
  2488. @a=fc108e
  2489. @40dStore A5 on the supervisor stack.
  2490. @40dGet the user stack pointer.
  2491. @40dSave all registers on user stack.
  2492. @40dGet ExecBase.
  2493. @40dGet current interrupt disable level.
  2494. @40dSet interrupt disable level to -1.
  2495. @40dEnable interrupts.
  2496. @40dFix A5 in the saved register set.
  2497. @40dSave the status register.
  2498. @40dSave the program counter.
  2499.  
  2500.         ; 68020/68881 specific material.  Without documentation for those
  2501.         ; processors, I can't comment this.
  2502.  
  2503. @a?fc10b4
  2504. FC10B4  fsave     -(A5)
  2505. @a=fc10b6
  2506. @d
  2507. @d
  2508. @d
  2509. @d
  2510. @d
  2511. @d
  2512. @d
  2513. @d
  2514. @d
  2515. @d
  2516. @d
  2517. @d
  2518. @d
  2519. @a?fc10d6
  2520. FC10D6  fmovem.x  FP0-FP7,-(A5)
  2521. FC10DA  fmovem.l  FPCR/FPSR/FPIAR,-(A5)
  2522. @a=fc10de
  2523. @d
  2524.  
  2525. @40dPoint to 68881 context restore.
  2526.  
  2527.         ; The rest of the processing for Switch() is the same, so enter
  2528.         ; the "plain" version in the middle.
  2529.  
  2530. @d
  2531.  
  2532.  
  2533. ---------------------------------------------------------------------------
  2534.   Dispatch()
  2535.  
  2536.   [Version for machines with a 68881 FPP]
  2537. ---------------------------------------------------------------------------
  2538.  
  2539. @40dPoint to 68881 context-restore.
  2540.  
  2541.         ; The regular Dispatch() can be used for the rest.
  2542.  
  2543. @d
  2544.  
  2545.  
  2546.         ; Special 68881 FPP compatible context restore
  2547.         ; --------------------------------------------
  2548.  
  2549.         ; 68020/68881 specific material.  Without documentation for those
  2550.         ; processors, I can't comment this.
  2551.  
  2552. @d
  2553. @d
  2554. @d
  2555. @a?fc10f6
  2556. FC10F6  fmovem.l  (A5)+,FPCR/FPSR/FPIAR
  2557. FC10FA  fmovem.x  (A5)+,FP0-FP7
  2558. @a=fc10fe
  2559. @d
  2560. @d
  2561. @d
  2562. @d
  2563. @d
  2564. @d
  2565. @d
  2566. @a?fc1110
  2567. FC1110  frestore  (A5)+
  2568. @a=fc1112
  2569.  
  2570. @40dThis part is the same as the regular
  2571. @40dcontext-restore routine.
  2572. @d
  2573. @d
  2574. @d
  2575. @d
  2576.  
  2577.  
  2578. ---------------------------------------------------------------------------
  2579.   oldSR = SetSR( newSR, mask)
  2580.   D0             D0     D1
  2581. ---------------------------------------------------------------------------
  2582.  
  2583. @d
  2584. @36dWhat to execute in supervisor mode.
  2585. @36dEnter supervisor mode.
  2586. @d
  2587.  
  2588. @36dNow in supervisor mode.  Restore A5.
  2589. @36dGet status register from stack.
  2590. @36dMask unwanted bits out of newSR.
  2591. @d
  2592. @36dGet unchanged bits from old status reg.
  2593. @36dOr in the bits to be changed.
  2594. @d
  2595. @36dReturn old status codes in D0.
  2596. @36dLoad status reg. and return to user mode.
  2597.  
  2598.  
  2599. ---------------------------------------------------------------------------
  2600.   conditions = GetCC()
  2601.   D0
  2602.  
  2603.   [Version for 68000 machines only]
  2604. ---------------------------------------------------------------------------
  2605.  
  2606.         ; The ExecBase vector will have been changed not to point here
  2607.         ; unless the CPU is a 68000, since the following instruction would
  2608.         ; bomb with a privilege violation on 68010/020 processors.
  2609.  
  2610. @a?fc1140
  2611. FC1140  move      SR,D0             Get the status register.
  2612. @a=fc1142
  2613. @36dClear all but the condition codes.
  2614. @d
  2615.  
  2616.  
  2617. ---------------------------------------------------------------------------
  2618.   oldSysStack = SuperState()
  2619.   D0
  2620. ---------------------------------------------------------------------------
  2621.  
  2622. @d
  2623. @36dWhat to execute in supervisor mode.
  2624. @36dEnter supervisor mode.
  2625. @d
  2626.  
  2627. @36dContinue here.  Restore A5.
  2628. @d
  2629. @36dSet supervisor bit in status word.
  2630. @36dDo nothing more if it was already set.
  2631.  
  2632. @a?fc115e
  2633. FC115E  move      (SP)+,SR          Get status register from stack.
  2634. @a=fc1160
  2635. @36dSave supervisor stack pointer.
  2636. @36dLoad user stack pointer.
  2637.  
  2638. @36dCheck if running on a plain 68000.
  2639. @d
  2640. @36dPop 68010/020 exception info from stack.
  2641. @36dPop exception return address from stack.
  2642.  
  2643. @36dReturn to user.
  2644.  
  2645. @d
  2646.  
  2647.  
  2648. ---------------------------------------------------------------------------
  2649.   UserState( sysStack )
  2650.              D0
  2651. ---------------------------------------------------------------------------
  2652.  
  2653. @d
  2654. @36dWhere to go in supervisor mode.
  2655. @36dEnter supervisor mode (just in case).
  2656. @36dRestore A5.
  2657. @36dGet status register from stack.
  2658. @36dCopy stack pointer to user stack pointer.
  2659. @36dSet the system stack pointer.
  2660. @36dClear the supervisor mode bit.
  2661. @a?fc118a
  2662. FC118A  move      D1,SR
  2663. @a=fc118c
  2664. @36dReturn to the user.
  2665.  
  2666.  
  2667. ---------------------------------------------------------------------------
  2668.   oldInterrupt = SetIntVector( intNumber, interrupt )
  2669.   D0                           D0         A1
  2670. ---------------------------------------------------------------------------
  2671.  
  2672.         ; This routine makes an interrupt node the active interrupt node
  2673.         ; for a given interrupt number.  This node corresponds to an
  2674.         ; interrupt handler.  There can only be one node associated with
  2675.         ; each interrupt number.
  2676.  
  2677.         ; Note: Never try to SetIntVector() one of the interrupts which are
  2678.         ; dispatched as chains of servers.  The handler which does this
  2679.         ; does not use regular interrupt vectors or nodes, and it would not
  2680.         ; be possible to hook it up to the interrupt again if it became
  2681.         ; disconnected.
  2682.  
  2683. @36dCompute address of
  2684. @36dExecBase->IntVects[intNumber]
  2685.  
  2686. @36dDisable()
  2687. @d
  2688.  
  2689. @36dGet pointer to current interrupt node.
  2690. @36dInstall pointer to new interrupt node.
  2691.  
  2692. @36dIf there is a new node, then
  2693. @36d  Install interrupt data pointer.
  2694. @36d  Install interrupt code pointer.
  2695. @36dElse
  2696. @36d  Set code and data pointers to -1.
  2697. @d
  2698. @36dEndif
  2699.  
  2700. @36dEnable()
  2701. @d
  2702. @d
  2703. @d
  2704.  
  2705.  
  2706. ---------------------------------------------------------------------------
  2707.    AddIntServer( intNumber, interrupt )
  2708.                  D0         A1
  2709. ---------------------------------------------------------------------------
  2710.  
  2711.         ; Adds an interrupt server to the server chain for a given
  2712.         ; interrupt number.  The interrupt number must be one of the
  2713.         ; set for which interrupt server lists have been set up.
  2714.  
  2715.         ; The interrupt for which the server is being added will be enabled
  2716.         ; if it is not already enabled.
  2717.  
  2718. @d
  2719. @36dSave interrupt number.
  2720. @d
  2721. @36dCompute
  2722. @36dExecBase->IntVects[intNumber].is_Node
  2723. @d
  2724.  
  2725. @36dDisable()
  2726. @d
  2727.  
  2728. @36dEnqueue the interrupt server.
  2729.  
  2730. @36dHardware-enable the interrupt
  2731. @36dcorresponding to the server just added.
  2732. @d
  2733.  
  2734. @36dEnable()
  2735. @d
  2736. @d
  2737.  
  2738. @d
  2739. @d
  2740.  
  2741.  
  2742. ---------------------------------------------------------------------------
  2743.    RemIntServer( intNumber, interrupt )
  2744.                  D0         A1
  2745. ---------------------------------------------------------------------------
  2746.  
  2747.         ; This routine takes an interrupt server off the server chain for
  2748.         ; a given interrupt.  The interrupt is disabled if this leaves the
  2749.         ; server chain empty.
  2750.  
  2751. @d
  2752. @36dCompute
  2753. @36dExecBase->IntVects[intNumber].is_Node
  2754. @d
  2755.  
  2756. @36dSave interrupt number and node.
  2757. @d
  2758.  
  2759. @36dDisable()
  2760. @d
  2761.  
  2762. @36dUnlink interrupt server from the chain.
  2763. @d
  2764. @36dCheck if the chain is now empty.
  2765. @d
  2766.  
  2767. @36dChain is empty.  Disable the interrupt
  2768. @36dcorresponding to this node.
  2769. @d
  2770.  
  2771. @36dEnable()
  2772. @d
  2773. @d
  2774.  
  2775. @d
  2776. @d
  2777.  
  2778.  
  2779.         ; The following routine is used at system startup to initialize
  2780.         ; the exec's internal interrupt handlers.
  2781.  
  2782.         ; It initializes the server chains used to dispatch servers for
  2783.         ; I/O and timer, Copper, vertical blank, external level 6, and
  2784.         ; non-maskable interrupts, and establishes vectors to the exec's
  2785.         ; built-in interrupt handlers.
  2786.  
  2787.         ; For each server chain, a 22-byte data structure is built,
  2788.         ; consisting of a list header and 4 words of control data.  The
  2789.         ; 5 server chain headers are put into a contiguous 110-byte
  2790.         ; section of memory.  The server chains are initialized to empty,
  2791.         ; and the rest of the data structure is initialized with the
  2792.         ; data required to assert, deassert, and cancel the interrupt.
  2793.  
  2794.  
  2795. @d
  2796. @36d110 bytes needed.
  2797. @36dAttributes = MEMF_PUBLIC | MEMF_CLEAR.
  2798. @36dRequest memory.
  2799. @36dSee if we got the memory.
  2800. @d
  2801. @36dIf not, it's guru time!
  2802. @36dUse this alert number.
  2803. @36dGet ExecBase.
  2804. @36dGo put up the alert.
  2805. @36dNever reached.
  2806.  
  2807. @36dLoop 5 times (4 + 1 for dbra).
  2808. @36dGet pointer to allocated memory.
  2809. @36dPoint to the data table below.
  2810.  
  2811.         ; Loop:  Divide the 110 byte data area up into five data
  2812.         ; structures, each consisting of a list header and some control
  2813.         ; words.
  2814.  
  2815. @36dSave pointer to current node.
  2816. @36dInitialize the node's server chain
  2817. @36dto empty.
  2818. @d
  2819. @d
  2820.  
  2821. @36dPoint to the node's data area.
  2822. @36dGet interrupt number from table.
  2823. @36dMake the control word needed to disable
  2824. @36dthis interrupt.
  2825. @36dWrite it in the node's data area.
  2826. @36dMake the control word needed to enable
  2827. @36dthis interrupt and store it also.
  2828. @36dGet the cancel interrupt control word.
  2829. @36dMove a word of pad data.
  2830. @36dPoint to the generic interrupt handler.
  2831.  
  2832.         ; Set up this interrupt in the exec table.  The interrupt vector
  2833.         ; is at ExecBase + $54 + 12 * interrupt number.  We write the code
  2834.         ; and data addresses only; we don't bother with the node address.
  2835.  
  2836. @d
  2837. @d
  2838.  
  2839. @36dLoop until all interrupts done.
  2840.  
  2841.         ; Install the address of the software interrupt handler.  The
  2842.         ; software interrupt lists have already been cleared earlier in
  2843.         ; the system startup code.
  2844.  
  2845. @d
  2846.  
  2847.         ; Now enable interrupts and exit.  Note that only the software
  2848.         ; interrupts are enabled.  The interrupts handled by the handler
  2849.         ; below will be enabled if and when servers are put on their
  2850.         ; chains.  Interrupts handled external to the exec must be enabled
  2851.         ; by whoever provides the handler.
  2852.  
  2853. @d
  2854. @d
  2855. @d
  2856.  
  2857.  
  2858.         ; Interrupt initialization table.  Each line consists of an
  2859.         ; interrupt number, and a control word which is used to cancel
  2860.         ; the interrupt if pending.  The last column appears to be padding.
  2861.  
  2862.  
  2863. @8p@5w@5w@w
  2864. @8p@5w@5w@w
  2865. @8p@5w@5w@w
  2866. @8p@5w@5w@w
  2867. @8p@5w@5w@w
  2868.  
  2869.  
  2870.         ; Generic Interrupt Handler
  2871.         ; -------------------------
  2872.  
  2873.         ; Each logical interrupt (0-15) has a handler.  Some logical
  2874.         ; interrupts are accessible to the user not as handlers, but rather,
  2875.         ; as chains of servers.  Most of these (all but the Blitter one)
  2876.         ; use this code, which acts as a handler and dispatches the servers.
  2877.  
  2878.         ; A data structure set up by the previous routine exists for each
  2879.         ; interrupt to store the list header for the server chain, and some
  2880.         ; control words.
  2881.  
  2882. @d
  2883. @d
  2884. @35dCheck the head of the server chain.
  2885.  
  2886.         ; Main loop:  Here we dispatch a server from the queue.
  2887.  
  2888. @35dIs this the end of the chain?
  2889. @35dIf so, exit.
  2890. @35dGet the server's code and data addresses.
  2891. @35dCall it.
  2892.  
  2893.         ; Servers return with the zero flag indicating whether they have
  2894.         ; taken care of the interrupt.  We keep calling servers until
  2895.         ; we either run out or until one returns the zero flag clear.
  2896.  
  2897. @35dIf the zero flag is clear, exit.
  2898. @35dGo to next node in the queue.
  2899. @35dGo back to top of loop.
  2900.  
  2901.         ; Either we ran out of servers, or one of them accepted the
  2902.         ; interrupt.  Either way, clear the interrupt and exit.
  2903.  
  2904. @d
  2905. @35dClear the interrupt.
  2906. @d
  2907.  
  2908.  
  2909. ---------------------------------------------------------------------------
  2910.   Cause( interrupt )
  2911.          A1
  2912. ---------------------------------------------------------------------------
  2913.  
  2914. @36dDisable()
  2915. @d
  2916.  
  2917. @36dCheck if node type is already NT_SOFTINT.
  2918. @36dIf so, do nothing.
  2919.  
  2920. @36dMake node type NT_SOFTINT.
  2921. @d
  2922. @36dGet node priority.
  2923. @36dTruncate to a multiple of 16.
  2924. @36dSign extend to a word quantity.
  2925. @36dPoint at middle of ExecBase->SoftInts
  2926. @36dGet address of SoftInts entry correspon-
  2927.                                     ding to this priority (-32,-16,0,16,32).
  2928.  
  2929.         ; Now enqueue the node on the SoftIntList for this priority.
  2930.  
  2931. @d
  2932. @36dGet old TailPred pointer.
  2933. @36dSet TailPred pointer to new node.
  2934. @36dSet forward pointer of new node.
  2935. @36dSet back pointer of new node.
  2936. @d
  2937. @36dSet forward pointer of old tail node.
  2938.  
  2939. @36dSet the software interrupt pending flag.
  2940. @36dGenerate a level 1 "software" interrupt.
  2941. @36dEnable()
  2942. @d
  2943. @d
  2944. @d
  2945.  
  2946.         ; Software Interrupt Handler
  2947.         ; --------------------------
  2948.  
  2949.         ; This is the interrupt handler for logical interrupt #2, which
  2950.         ; is used for software interrupts.  It will be called as soon after
  2951.         ; the above routine as its interrupt priority will allow.
  2952.  
  2953. @36dClear the interrupt.
  2954. @36dClear the software int. pending flag.
  2955. @36dIf it wasn't set, ignore the interrupt.
  2956. @d
  2957.  
  2958. @36dDisable further software interrupts.
  2959. @36dGo and scan the SoftInts table.
  2960.  
  2961.         ; This code is called (from below) when a non-empty SoftIntList
  2962.         ; has been found.  The pointer of the list will be in A0.
  2963.  
  2964. @a?fc139c
  2965. FC139C  move.w    #$2700,SR         Mask all maskable interrupts.
  2966. @a=fc13a0
  2967. @36dGet the pointer to the first list node.
  2968. @d
  2969. @d
  2970. @36dUnlink the node from the list.
  2971. @d
  2972. @d
  2973. @d
  2974. @36dMake the node type NT_INTERRUPT.
  2975. @a?fc13b6
  2976. FC13B6  move.w    #$2000,SR         Enable all interrupts.
  2977. @a=fc13ba
  2978. @36dGet the interrupt code and data.
  2979. @36dCall the node's interrupt handler.
  2980.  
  2981.         ; The following scans the SoftInts[] table for non-empty
  2982.         ; SoftIntLists.  If it finds one, it executes the code above.
  2983.  
  2984. @36dLoop 5 times (1 less for dbra).
  2985. @36dStart at SoftInts[4] (priority 32).
  2986. @36dClear the software interrupt.
  2987. @36dSee if there are any nodes on this list.
  2988. @36dIf so, process the list.
  2989. @36dOtherwise, go to next lower priority,
  2990. @36dand loop back.
  2991.  
  2992.         ; No (more) nodes found.
  2993.  
  2994. @a?fc13de
  2995. FC13DE  move      #$2100,SR
  2996. @a=fc13e2
  2997. @36dReenable software interrupts and exit.
  2998. @d
  2999.  
  3000.  
  3001. ---------------------------------------------------------------------------
  3002.   Disable()
  3003. ---------------------------------------------------------------------------
  3004.  
  3005.         ; Hardware disable all interrupts, and log the fact that this
  3006.         ; was done in the interrupt disable nesting level counter.
  3007.  
  3008. @d
  3009. @d
  3010. @d
  3011.  
  3012.  
  3013. ---------------------------------------------------------------------------
  3014.   Enable()
  3015. ---------------------------------------------------------------------------
  3016.  
  3017.         ; Decrement the interrupt level nesting counter, and if it goes
  3018.         ; negative, enable interrupts again.
  3019.  
  3020. @d
  3021. @d
  3022. @d
  3023. @d
  3024.  
  3025. @8p@28wPadding.
  3026.  
  3027.  
  3028. ---------------------------------------------------------------------------
  3029.   AddLibrary( library )
  3030.               A1
  3031. ---------------------------------------------------------------------------
  3032.  
  3033. @36dPoint to system library list.
  3034. @36dAdd the library to the list.
  3035. @36dUpdate the library vector checksum.
  3036. @d
  3037.  
  3038.  
  3039. ---------------------------------------------------------------------------
  3040.   error = RemLibrary( library )
  3041.   D0                  A1
  3042. ---------------------------------------------------------------------------
  3043.  
  3044.         ; NOTE: Some other part of the system, presumably DOS, will patch
  3045.         ; itself in ahead of this.
  3046.  
  3047. @d
  3048. @36dForbid()
  3049. @36dSave ExecBase.
  3050. @d
  3051. @36dCall the library's Expunge() function.
  3052. @36dRestore ExecBase.
  3053. @36dPermit()
  3054. @d
  3055.  
  3056.  
  3057. ---------------------------------------------------------------------------
  3058.   library = OldOpenLibrary( libName )
  3059.   D0                        A1
  3060. ---------------------------------------------------------------------------
  3061.  
  3062.         ; This is just OpenLibrary() without the "version" parameter.
  3063.  
  3064. @36dAny version of the library will do.
  3065. @36dOpenLibrary()
  3066. @d
  3067.  
  3068.  
  3069. ---------------------------------------------------------------------------
  3070.   library = OpenLibrary( libName, version )
  3071.   D0                     A1       D0
  3072. ---------------------------------------------------------------------------
  3073.  
  3074.         ; NOTE: Some other part of the system, presumably DOS, will patch
  3075.         ; itself in ahead of this, presumably so it can pull libraries off
  3076.         ; disk if they aren't already in the library list.
  3077.  
  3078.         ; Note how several versions of a library can be in the system
  3079.         ; library list (although the initial RomTag system of putting them
  3080.         ; there will only take the newest one), and this routine will keep
  3081.         ; looking for one new enough to satisfy the request if it finds
  3082.         ; one which is too old.
  3083.  
  3084. @d
  3085. @d
  3086. @36dForbid()
  3087. @36dPoint to the system library list.
  3088. @36dFindName()
  3089. @36dDid we find the library?
  3090. @36dReturn zero and exit if not.
  3091. @d
  3092. @36dCheck the version number.
  3093. @36dTry to find another one if too old.
  3094.  
  3095.         ; We have an acceptable library.
  3096.  
  3097. @36dSave ExecBase.
  3098. @36dPoint A6 at the library base address.
  3099. @36dCall the library's Open() function.
  3100. @36dRestore ExecBase.
  3101. @36dPermit()
  3102. @d
  3103. @d
  3104.  
  3105.  
  3106. ---------------------------------------------------------------------------
  3107.   CloseLibrary( library )
  3108.                 A1
  3109. ---------------------------------------------------------------------------
  3110.  
  3111.         ; NOTE: Some other part of the system, presumably DOS, will patch
  3112.         ; itself in ahead of this.
  3113.  
  3114. @36dForbid()
  3115. @36dSave ExecBase.
  3116. @d
  3117. @36dCall the library's Close() function.
  3118. @36dRestore ExecBase.
  3119. @36dPermit()
  3120. @d
  3121.  
  3122.  
  3123. ---------------------------------------------------------------------------
  3124.   oldFunc = SetFunction( library, funcOffset, funcEntry )
  3125.   D0                     A1       A0.W        D0
  3126. ---------------------------------------------------------------------------
  3127.  
  3128. @36dIndicate that library is modified.
  3129. @36dCompute address of jump instruction.
  3130. @36dGet the old jump destination address.
  3131. @36dInstall a "JMP" instruction.
  3132. @36dInstall the new destination address.
  3133. @36dRe-checksum the library.
  3134. @36dReturn the previous jump destination.
  3135. @d
  3136.  
  3137.  
  3138. ---------------------------------------------------------------------------
  3139.   SumLibrary( library )
  3140.               A1
  3141. ---------------------------------------------------------------------------
  3142.  
  3143. @36dCheck the "sum used" flag.
  3144. @36dIf sum not used, then don't bother.
  3145.  
  3146. @d
  3147. @36dClear the "changed" flag.
  3148. @d
  3149. @36dIf the flag was set, clear the checksum.
  3150. @d
  3151. @36dGet the negative size.
  3152. @36dDivide by 2 (gives size in words).
  3153. @36dStart the sum at zero.
  3154. @d
  3155.  
  3156.         ; Loop:  Add up all the 16-bit words in the library's jump vector.
  3157.  
  3158. @d
  3159. @d
  3160.  
  3161. @36dGet the old checksum.
  3162. @d
  3163. @36dOld checksum wasn't zero, so compare
  3164. @36dit to the new checksum.
  3165.  
  3166.         ; Checksums didn't match, so put up an alert.
  3167.  
  3168. @d
  3169. @36dLibrary checksum alert number.
  3170. @d
  3171. @36dCall the alert function.
  3172. @d
  3173.  
  3174. @36dStore the new checksum in the library.
  3175.  
  3176. @36dEnable multitasking.
  3177. @d
  3178.  
  3179.  
  3180. ---------------------------------------------------------------------------
  3181.   library = MakeLibrary( vectors, structure, init, dataSize, segList )
  3182.   D0                     A0       A1         A2    D0        D1
  3183. ---------------------------------------------------------------------------
  3184.  
  3185. @d
  3186.  
  3187. @36dSize of library data area.
  3188. @36dPointer to library vector table.
  3189. @36dPointer to initialization structure.
  3190. @36dFunction to call after creating library.
  3191. @36dSegList (for DOS use).
  3192. @36dGet pointer to vector table.
  3193. @36dSkip the following if no vectors.
  3194.  
  3195. @d
  3196. @d
  3197. @36dCheck if vector data is absolute or
  3198. @36drelative (first word = -1).
  3199. @d
  3200. @36dRelative vectors.  Skip over the flag.
  3201. @36dCount the vectors up to the terminating
  3202. @36dflag.  D3 holds -(number of vectors + 1)
  3203. @d
  3204. @36dAbsolute vectors.  Count as above.
  3205. @d
  3206. @36dMake number of vectors positive.
  3207. @36dMultiply by 6.
  3208.  
  3209. @d
  3210. @36dAdd size of data area.
  3211.  
  3212. @36dMEMF_PUBLIC | MEMF_CLEAR
  3213. @36dRequest memory for library node.
  3214.  
  3215. @36dSee if the memory was allocated.
  3216. @d
  3217. @36dDidn't get any memory.  Fail by returning
  3218. @36da nil pointer to the caller.
  3219.  
  3220. @36dPoint to start of allocated memory.
  3221. @36dSkip over jump vector area.
  3222. @36dInstall negative size in library node.
  3223. @36dInstall positive size.
  3224. @d
  3225. @36dClear A2.
  3226. @36dPoint at vector table again.
  3227. @36dCheck if vectors are relative.
  3228. @d
  3229. @36dIf vectors are relative, skip over flag,
  3230. @36dand set A2 to vector table address.
  3231.  
  3232. @36dInstall the jump vector.
  3233.  
  3234. @36dCheck if there is an initialization
  3235. @36dstructure.  Skip the following if not.
  3236.  
  3237. @d
  3238. @d
  3239. @36dDo not clear memory before initializing.
  3240. @36dProcess the initialization structure.
  3241.  
  3242. @36dGet pointer to library node.
  3243. @36dCheck if there is initialization code.
  3244. @36dSkip the following if not.
  3245.  
  3246. @36dGet the address of the code.
  3247. @36dGet the address of the segList
  3248. @36dCall the initialization code.
  3249.  
  3250. @d
  3251. @d
  3252.  
  3253.  
  3254. ---------------------------------------------------------------------------
  3255.   size = MakeFunctions( vectors, offset )
  3256.   D0                    A1       A2
  3257. ---------------------------------------------------------------------------
  3258.  
  3259. @d
  3260. @36dClear size counter.
  3261. @36dCheck if vector table is relative.
  3262. @d
  3263.  
  3264.         ; Process a relative vector initialization table.
  3265.  
  3266. @36dGet a relative table entry.
  3267. @36dCheck if end of table marker.
  3268. @d
  3269. @36dCompute absolute vector address.
  3270. @36dInstall in jump vector.
  3271. @36dInstall "JMP" instruction.
  3272. @36dIncrement size counter.
  3273. @d
  3274.  
  3275.         ; Process an absolute vector initialization table.
  3276.  
  3277. @36dGet an absolute table entry.
  3278. @36dCheck if end of table marker.
  3279. @d
  3280. @36dInstall it in the jump table.
  3281. @36dInstall "JMP" instruction.
  3282. @36dIncrement size counter.
  3283. @d
  3284.  
  3285. @36dDone, return to caller.
  3286. @d
  3287.  
  3288.  
  3289. ---------------------------------------------------------------------------
  3290.   Insert( list, node, listNode )
  3291.           A0    A1    A2
  3292. ---------------------------------------------------------------------------
  3293.  
  3294. @32dCheck if node to insert after is zero.
  3295. @32dIf so, do an AddHead instead.
  3296.  
  3297. @32dSee if list node indicates end of list.
  3298. @32dBranch if so.
  3299.  
  3300.         ; If we get this far, A2 must point to a list node.
  3301.  
  3302. @d
  3303. @32dSet forward and back pointers of new node.
  3304. @32dSet back pointer of next node.
  3305. @32dSet forward pointer of previous node.
  3306. @d
  3307.  
  3308.         ; The "Successor" field of the listNode was zero, i.e. listNode
  3309.         ; is really the end of list marker.  In this case, insert just
  3310.         ; before listNode, i.e. at the end of the list (undocumented).
  3311.  
  3312. @32dSet forward pointer of new node to end.
  3313. @32dGet old TailPred pointer
  3314. @32dLink previous end node to new node.
  3315. @32dSet the TailPred pointer to the new node.
  3316. @32dLink this node to the previous end node.
  3317. @d
  3318.  
  3319.  
  3320. ---------------------------------------------------------------------------
  3321.   AddHead( list, node )
  3322.            A0    A1
  3323. ---------------------------------------------------------------------------
  3324.  
  3325. @32dGet old pointer to first node.
  3326. @32dMake the first node the new node.
  3327. @32dSet forward and back pointers in new node.
  3328. @d
  3329. @32dFix back pointer in previous first node.
  3330. @d
  3331.  
  3332.  
  3333. ---------------------------------------------------------------------------
  3334.   AddTail( list, node )
  3335.            A0    A1
  3336. ---------------------------------------------------------------------------
  3337.  
  3338. @32dPoint A0 to list's "Tail" field.
  3339. @32dSave old value of TailPred field.
  3340. @32dMake the new node the last node.
  3341. @32dSet new node's back pointer to list header.
  3342. @32dSet new node's back pointer.
  3343. @d
  3344. @32dLink new node to previous last node.
  3345. @d
  3346.  
  3347.  
  3348. ---------------------------------------------------------------------------
  3349.   Remove( node )
  3350.           A1
  3351. ---------------------------------------------------------------------------
  3352.  
  3353. @32dGet pointer to successor node.
  3354. @32dGet pointer to predecessor node.
  3355. @32dPoint predecessor to successor.
  3356. @32dPoint successor to predecessor.
  3357. @d
  3358.  
  3359.  
  3360. ---------------------------------------------------------------------------
  3361.   node = RemHead( list )
  3362.   D0              A0
  3363. ---------------------------------------------------------------------------
  3364.  
  3365. @32dGet list's head pointer.
  3366. @32dGet first node's successor.
  3367. @32dIf zero, list is empty, so return zero.
  3368.  
  3369. @32dPoint head pointer past removed node.
  3370. @d
  3371. @32dPoint new head node back at list header.
  3372. @d
  3373.  
  3374.  
  3375. ---------------------------------------------------------------------------
  3376.   node = RemTail( list )
  3377.   D0              A0
  3378. ---------------------------------------------------------------------------
  3379.  
  3380. @a?fc161e
  3381. @32dGet list's TailPred pointer.
  3382. @32dCheck if the last node has a predecessor.
  3383. @32dIf not, the list is empty, so return zero.
  3384. @32dPoint TailPred pointer at second-last node.
  3385. @d
  3386. @32dPoint second-last node at the list header.
  3387. @32dIncrement to point at "Tail" field.
  3388. @d
  3389.  
  3390.  
  3391. ---------------------------------------------------------------------------
  3392.   Enqueue( list, node )
  3393.            A0    A1
  3394. ---------------------------------------------------------------------------
  3395.  
  3396. @32dGet the priority field of the node.
  3397. @32dGet the head pointer of the queue.
  3398.  
  3399.         ; Loop:  Keep skipping nodes until the end of the list is
  3400.         ; reached or the next node has a lower priority.
  3401.  
  3402. @32dPoint at the current node.
  3403. @32dCheck if there is a successor.
  3404. @32dIf not, we are at the end of the list.
  3405. @32dCompare priorities.
  3406. @32dLoop until priority is lower than new node's.
  3407.  
  3408.         ; A0 now points at the node to insert before, or at the end
  3409.         ; of the list (i.e. the list header plus 4).
  3410.  
  3411. @32dGet old value of back pointer
  3412.                                 (or TailPred pointer of list header).
  3413. @32dChange it to point to the new node.
  3414. @32dSet new node's forward pointer.
  3415. @32dSet new node's back pointer to last node
  3416.                                 skipped, or list header.
  3417. @d
  3418. @32dSet list's head field, or forward pointer
  3419.                                 of previous node, to new node.
  3420. @d
  3421.  
  3422.  
  3423. ---------------------------------------------------------------------------
  3424.   node = FindName( start, name )
  3425.   D0               A0     A1
  3426. ---------------------------------------------------------------------------
  3427.  
  3428. @d
  3429. @36dPoint to list header or first node.
  3430. @36dSave address of match string in D1.
  3431. @d
  3432. @36dExit if list is empty.
  3433.  
  3434.         ; Main loop:  Check if node pointed to by D0 has the same name
  3435.         ; as the string pointed to by D1.
  3436.  
  3437. @36dGet the address of the node to check.
  3438. @d
  3439. @36dExit if this is the end of the list.
  3440.  
  3441. @36dPoint A0 at name of this node.
  3442. @36dPoint A1 at match string.
  3443.  
  3444.         ; Inner loop:  Compare the strings.
  3445.  
  3446. @36dCompare one character.
  3447. @36dSkip to next node if not equal.
  3448. @36dWas this the terminating zero?
  3449. @36dContinue comparing if not.
  3450.  
  3451. @36dGot a match - point D0 to the node.
  3452.  
  3453. @36dRestore registers and exit.
  3454. @d
  3455. @d
  3456.  
  3457.         ; Protected enqueue and dequeue routines
  3458.         ; --------------------------------------
  3459.  
  3460. @36dForbid()
  3461. @36dEnqueue()
  3462. @36dPermit()
  3463. @d
  3464.  
  3465. @36dForbid()
  3466. @36dRemove()
  3467. @36dPermit()
  3468. @d
  3469.  
  3470.  
  3471. ---------------------------------------------------------------------------
  3472.   memoryBlock = Allocate( freeList, byteSize )
  3473.   D0                      A0        D0
  3474. ---------------------------------------------------------------------------
  3475.  
  3476. @36dZero bytes requested?
  3477. @36dIf so, just return.
  3478. @d
  3479. @36dRound D0 up to nearest multiple of 8.
  3480. @d
  3481. @d
  3482. @36dCompare D0 to total number of bytes free.
  3483. @36dIf greater, return zero.
  3484. @36dPoint at the link to the first MemChunk.
  3485.  
  3486.         ; Loop:  Scan the free list for a MemChunk big enough to satisfy
  3487.         ; the request.
  3488.  
  3489. @36dGet the pointer to the next MemChunk.
  3490. @36dIf no more MemChunks, return zero.
  3491. @d
  3492. @36dCheck D0 against size of this chunk.
  3493. @36dIf smaller or equal, take it.
  3494. @36dOtherwise, go to next MemChunk.
  3495. @36dContinue searching.
  3496.  
  3497.         ; This is where memory fragmentation occurs.  If the block we've
  3498.         ; found is bigger than what we need, we take what we need and make
  3499.         ; a smaller block out of the rest.
  3500.  
  3501. @36dIf sizes are not the same, then
  3502. @36d  Compute address of leftover block.
  3503. @36d  Move the MemChunk pointer up.
  3504. @36d  Get the current size.
  3505. @36d  Subtract the allocated amount.
  3506. @36d  Put it into the new MemChunk.
  3507. @36d  Link to previous MemChunk (or header).
  3508. @36dElse
  3509. @36d  Unlink this MemChunk.
  3510.                                     Endif
  3511. @36dDecrease free memory value in header.
  3512. @36dGet address of allocated block.
  3513.  
  3514. @36dReturn zero or address of block.
  3515. @d
  3516. @d
  3517.  
  3518.         ; Routine to put up a "Corrupt Free List" dead-end alert.
  3519.  
  3520. @a?fc16ee
  3521. @d
  3522. @36dAlert number.
  3523. @36dGet ExecBase.
  3524. @36dPut up the alert.
  3525. @36dNever reached.
  3526.  
  3527.  
  3528. ---------------------------------------------------------------------------
  3529.   Deallocate( freeList, memoryBlock, byteSize )
  3530.               A0        A1           D0
  3531. ---------------------------------------------------------------------------
  3532.  
  3533. @36dSee if byte size is zero.
  3534. @36dDo nothing if so.
  3535. @d
  3536. @d
  3537. @36dTruncate block address to nearest
  3538. @36dmultiple of 8.
  3539. @36dFind out by how much that decreased
  3540. @36dthe address, then add this amount to
  3541. @36dthe number of bytes to free.
  3542. @36dNow round number of bytes to free up to
  3543. @36dnearest multiple of 8.
  3544. @36dExit if the result is zero bytes.
  3545.  
  3546.         ; Block address and size are now nice multiples of 8, so we can
  3547.         ; go ahead and put the block into the free list.
  3548.  
  3549. @36dPoint at the link to the first MemChunk.
  3550. @36dGet the address of the first MemChunk.
  3551. @36dBranch if there are no MemChunks.
  3552.  
  3553.         ; Main loop: Find the first MemChunk with an address greater than
  3554.         ; that of our memory block.
  3555.  
  3556. @36dCompare addresses.
  3557. @36dExit loop if right MemChunk found.
  3558. @36dIf addresses are equal, guru time!
  3559. @d
  3560. @36dGet address of next MemChunk.
  3561. @36dContinue searching.
  3562.  
  3563.         ; A2 now points at the link which comes directly before the position
  3564.         ; where our block must be inserted.  First, we check whether this
  3565.         ; is the start of the list.  If so, we just link it in.
  3566.  
  3567. @36dCompute address of MemHeader's link.
  3568. @d
  3569. @36dSee if A2 still points there.
  3570. @36dIf so, insert block at head of the list.
  3571.  
  3572.         ; We are somewhere other than at the start of the list.  It is
  3573.         ; possible that we can join the block to the previous MemChunk.
  3574.         ; Try this now.
  3575.  
  3576. @36dCompute first address after the
  3577. @36dprevious MemChunk.
  3578. @36dCompare to address of our new block.
  3579. @36dIf equal, join the two together.
  3580. @36dIf greater, free list is corrupt.
  3581.  
  3582.         ; Enter here to make a new MemChunk and link it into the free list.
  3583.  
  3584. @36dSet new MemChunk's link field.
  3585. @36dPoint previous link at the MemChunk.
  3586. @36dPut the block size into the MemChunk.
  3587. @d
  3588.  
  3589.         ; Enter here to attach the new block to the previous MemChunk.
  3590.  
  3591. @36dAdd to previous MemChunk's size.
  3592. @36dBack pointer up to that MemChunk.
  3593.  
  3594.         ; Now the block is taken care of.  Either we have built a MemChunk
  3595.         ; for it, or we have attached it to a MemChunk directly before the
  3596.         ; block.  Either way, the address of the MemChunk where the block
  3597.         ; now is is in A1.  It remains to check whether we can join this
  3598.         ; MemChunk with the next one down the line.
  3599.  
  3600. @36dSee if there is a next MemChunk.
  3601. @36dExit if not.
  3602. @36dGet our MemChunk's size.
  3603. @36dAdd to its base address.
  3604. @36dCompare to address of next MemChunk.
  3605. @36dIf higher, free list is corrupt.
  3606. @36dIf not equal, we can't join them.
  3607.  
  3608.         ; If we get this far, we can join this MemChunk to the next one down
  3609.         ; the line, so we delete the next one and add its size to this one.
  3610.  
  3611. @36dGet pointer to next MemChunk.
  3612. @36dFetch its link and put in our MemChunk.
  3613. @36dGet its size.
  3614. @36dAdd to size of our MemChunk.
  3615.  
  3616.         ; This is where all the paths meet again.
  3617.  
  3618. @36dAdd size of freed block to free counter.
  3619. @d
  3620. @d
  3621.  
  3622.         ; Error exit routine.  Generate a dead-end alert.
  3623.  
  3624. @d
  3625. @36dAlert number.
  3626. @36dGet ExecBase.
  3627. @36dGo put up the alert.
  3628. @36dNever reached.
  3629.  
  3630.  
  3631. ---------------------------------------------------------------------------
  3632.   memoryBlock = AllocMem( byteSize, requirements )
  3633.   D0                      D0        D1
  3634. ---------------------------------------------------------------------------
  3635.  
  3636.         ; NOTE: Some other part of the system, presumably DOS, will patch
  3637.         ; itself in ahead of this, presumably so it can throw out unused
  3638.         ; libraries, devices, fonts, etc. when memory runs low.
  3639.  
  3640. @36dForbid()
  3641. @d
  3642. @d
  3643. @d
  3644. @36dPoint to the system free memory list.
  3645.  
  3646.         ; Loop:  Step through the system free memory list looking for
  3647.         ; a MemHeader which can satisfy the memory request.
  3648.  
  3649. @36dGet pointer to a MemHeader.
  3650. @36dEnd of memory list reached?
  3651. @d
  3652. @36dIf so, return a null pointer and exit.
  3653. @d
  3654. @36dGet the MemHeader's attributes.
  3655. @36dCheck against needed attributes.
  3656. @d
  3657. @36dGo to next MemHeader if not present.
  3658.  
  3659.         ; The current MemHeader has the right attribute flags, now try
  3660.         ; to get a block of the required size out of its free list.
  3661.  
  3662. @36dPoint to the MemHeader.
  3663. @36dIndicate size of block required.
  3664. @36dAllocate()
  3665. @36dDid we get the memory?
  3666. @36dIf not, go to next MemHeader.
  3667.  
  3668.         ; We got a memory block.  Clear it if necessary.
  3669.  
  3670. @36dWas the MEMF_CLEAR flag set?
  3671. @36dJust return if not.
  3672. @d
  3673. @36dConvert number of bytes to nearest number
  3674. @36dof longwords.
  3675. @36dPoint to the memory block.
  3676. @36dEnter the loop at the bottom.
  3677.  
  3678.         ; Loop: Clear the memory block.
  3679.  
  3680. @36dClear one longword.
  3681. @36dLoop back until none remain.
  3682.  
  3683. @36dDBRA instruction only uses low 16 bits
  3684. @36das program counter, so if any remain
  3685. @36dset in the upper half of D3, decrement
  3686. @36dthem manually and loop back.
  3687. @d
  3688. @d
  3689.  
  3690. @36dPermit()
  3691. @d
  3692. @d
  3693.  
  3694.  
  3695. ---------------------------------------------------------------------------
  3696.   FreeMem( memoryBlock, byteSize )
  3697.            A1           D0
  3698. ---------------------------------------------------------------------------
  3699.  
  3700. @36dForbid()
  3701. @36dIs number of bytes to free zero?
  3702. @36dIf so, just exit.
  3703. @36dPoint to system free memory list.
  3704.  
  3705.         ; Loop: Look for the right MemHeader to put the block back into.
  3706.  
  3707. @36dPoint to the next MemHeader.
  3708. @36dEnd of list reached?
  3709.  
  3710.         ; If no MemHeader can be found to put this block on, something
  3711.         ; is wrong, so it's guru time.
  3712.  
  3713. @36dGuru time if end of list reached.
  3714.  
  3715.         ; See if the block falls into the address range covered by this
  3716.         ; MemHeader.
  3717.  
  3718. @36dDoes block start before mh_Lower?
  3719. @36dIf so, try next MemHeader.
  3720. @36dDoes block start after mh_Upper?
  3721. @36dIf so, try next MemHeader.
  3722.  
  3723.         ; The block belongs to this MemHeader, so go link it back into
  3724.         ; the free list.
  3725.  
  3726. @36dDeallocate()
  3727. @36dPermit()
  3728. @d
  3729.  
  3730.  
  3731. ---------------------------------------------------------------------------
  3732.   attributes = TypeOfMem( address )
  3733.   D0                      A1
  3734. ---------------------------------------------------------------------------
  3735.  
  3736. @36dForbid()
  3737. @36dPoint to system free memory list.
  3738. @d
  3739. @36dPoint to next MemHeader.
  3740. @36dEnd of list reached?
  3741. @36dIf so, return zero and exit.
  3742. @36dCheck if the block is in the address
  3743. @36drange covered by this MemHeader.
  3744. @d
  3745. @36dIf it is, return the contents of the
  3746. @36dMemHeader's attribute field.
  3747. @36dPermit()
  3748. @d
  3749.  
  3750.  
  3751. ---------------------------------------------------------------------------
  3752.   memoryBlock = AllocAbs( byteSize, location )
  3753.   D0                      D0        A1
  3754. ---------------------------------------------------------------------------
  3755.  
  3756. @36dForbid()
  3757. @d
  3758. @36dGet the start address.
  3759. @36dTruncate down to nearest multiple of 8.
  3760. @d
  3761. @36dAdd any difference to number of bytes
  3762. @36dwanted, then round number of bytes
  3763. @36dup to nearest multiple of 8.
  3764. @36dPoint to the system free memory list.
  3765.  
  3766.         ; Loop: Scan through all the MemHeaders in the free list.
  3767.  
  3768. @36dPoint to next MemHeader.
  3769. @36dEnd of list reached?
  3770. @36dIf so, allocation failed, return zero.
  3771.  
  3772.         ; Check whether the block we want is covered by this MemHeader.
  3773.  
  3774. @36dIf block starts before this MemHeader's
  3775. @36darea, go on to the next one.
  3776. @36dIf block starts after this MemHeader's
  3777. @36darea, go on to next one.
  3778.  
  3779.         ; The desired block starts in the address range covered by this
  3780.         ; MemHeader, so it's either this one or nothing.
  3781.  
  3782.         ; Quick check:  If the total number of bytes free in this MemHeader's
  3783.         ; free list is less than the size of the block wanted, then the
  3784.         ; allocation is going to fail anyway.
  3785.  
  3786. @37dCheck block size against mh_Free.
  3787. @37dAllocation failed if higher.
  3788. @37dGet start address of block wanted.
  3789. @d
  3790. @37dCompute end address of block wanted.
  3791. @37dPoint to link to first MemChunk.
  3792.  
  3793.         ; Loop:  Find the MemChunk in the free list which contains the
  3794.         ; wanted block.
  3795.  
  3796. @37dGet pointer to next MemChunk.
  3797. @37dAllocation failed if no more MemChunks.
  3798. @d
  3799. @37dGet the MemChunk's size.
  3800. @37dCompute its end address.
  3801. @37dCheck against needed end address.
  3802. @37dExit loop if equal or higher.
  3803. @d
  3804. @37dGo to the next MemChunk.
  3805.  
  3806.         ; We have a MemChunk whose end address is greater than or equal
  3807.         ; to the end address of the block we want.  It's either this
  3808.         ; MemChunk or none at all.
  3809.  
  3810. @37dCheck start addresses.
  3811. @37dAllocation failed if needed block
  3812.                                      starts before this MemChunk.
  3813.  
  3814.         ; The block we want is entirely within this MemChunk, so now we
  3815.         ; cut it out and make zero, one or two MemChunks out of what's left.
  3816.  
  3817. @37dRemove block size from free count.
  3818. @37dCompare end addresses.
  3819. @d
  3820.  
  3821.         ; The end addresses of the allocated block and the MemChunk it
  3822.         ; was in were exactly equal.
  3823.  
  3824. @d
  3825. @d
  3826.  
  3827.         ; Memory was left over between the allocated block and the end of
  3828.         ; the MemChunk.  Make a new MemChunk out of this and link it into
  3829.         ; the free list.
  3830.  
  3831. @37dCompute base address of new MemChunk.
  3832. @37dStore pointer to next MemChunk.
  3833. @37dLink to previous MemChunk.
  3834. @37dStore number of bytes in MemChunk.
  3835.  
  3836.         ; At this point, whatever was left after the block was taken
  3837.         ; care of, and a pointer to the next MemChunk after the block is
  3838.         ; in A0.
  3839.  
  3840. @37dCompare start addresses.
  3841. @d
  3842.  
  3843.         ; The block started after the beginning of this MemChunk, so we
  3844.         ; just truncate the MemChunk to contain the leftover memory before
  3845.         ; the allocated block.
  3846.  
  3847. @d
  3848. @37dCompute remaining size.
  3849. @37dStore in the MemChunk.
  3850. @37dAll done.
  3851.  
  3852.         ; The block started exactly at the beginning of the MemChunk, so
  3853.         ; the MemChunk must be deleted.
  3854.  
  3855. @37dUnlink this MemChunk from the chain.
  3856. @37dReturn address of allocated block.
  3857. @d
  3858. @37dPermit()
  3859. @d
  3860.  
  3861. @37dReturn zero if allocation failed.
  3862. @d
  3863.  
  3864.  
  3865. ---------------------------------------------------------------------------
  3866.   size = AvailMem( requirements )
  3867.   D0               D1
  3868. ---------------------------------------------------------------------------
  3869.  
  3870. @d
  3871. @36dInitialize free memory counter.
  3872. @36dPoint at the ExecBase->MemList.
  3873. @36dForbid()
  3874. @d
  3875. @36dGet address of first MemHeader.
  3876. @36dExit if list is empty.
  3877. @36dGet this MemHeader's attributes.
  3878. @36dMask with required attributes.
  3879. @36dCheck if all attributes are satisfied.
  3880. @36dGo to next MemHeader if not.
  3881. @36dAre we looking for the largest
  3882.                                     contiguous block of memory?
  3883. @d
  3884. @36dIf not, just add the size,
  3885. @36dand loop back.
  3886.  
  3887.         ; We are looking for the largest contiguous block of memory.
  3888.  
  3889. @36dGet address of first MemChunk.
  3890. @36dLoop back if there is no MemChunk.
  3891. @d
  3892. @36dSee if this MemChunk is the biggest yet.
  3893. @d
  3894. @36dIf it is, keep its base address (why?),
  3895. @36dand its size.
  3896. @d
  3897. @36dGo to next MemChunk.
  3898. @36dPermit()
  3899. @36dReturn the accumulated or largest size.
  3900. @d
  3901. @d
  3902.  
  3903.  
  3904. ---------------------------------------------------------------------------
  3905.   memList = AllocEntry( memList )
  3906.   D0                    A0
  3907. ---------------------------------------------------------------------------
  3908.  
  3909. @d
  3910. @36dSave pointer to request MemList.
  3911. @36dClear loop counter.
  3912. @d
  3913. @36dGet the number of MemEntries.
  3914. @d
  3915. @36dCompute the size of the MemList needed
  3916. @36dto keep track of the MemEntries.
  3917. @36dSet MEMF_CLEAR.
  3918. @36dAllocate that amount of memory.
  3919. @36dIf we didn't get it, go exit.
  3920. @d
  3921. @36dPoint to base of new MemList structure.
  3922. @36dPut in the number of MemEntries.
  3923. @36dPoint to MemEntries in request MemList.
  3924. @36dPoint to MemEntries in result MemList.
  3925.                                     For each MemEntry do
  3926. @36d  Get its required attributes.
  3927. @36d  Get its required size.
  3928. @36d  Store the size in the result list.
  3929. @36d  If size is not zero then
  3930. @36d    Allocate the memory.
  3931. @36d    Go exit if unsuccessful.
  3932. @36d  Endif
  3933. @36d  Store memory address in result list.
  3934. @36d  Go to next request MemEntry.
  3935. @36d  Go to next result MemEntry.
  3936. @36d  Increment loop counter.
  3937. @36d  Compare to number of MemEntries.
  3938. @36dEndfor.
  3939. @d
  3940. @36dCompute -(size of MemEntry list).
  3941. @36dPoint A2 back at the request MemList.
  3942. @36dPoint A3 back at the result MemList.
  3943. @36dReturn the address of the result MemList.
  3944. @d
  3945. @d
  3946.  
  3947.         ; Enter here if one of the MemEntries could not be allocated.
  3948.  
  3949. @36dSave size of the allocate which failed.
  3950. @36dTest number of allocated MemEntries.
  3951. @36dExit if none remaining.
  3952. @36dDecrement number of MemEntries.
  3953. @36dPoint to the allocated MemEntry.
  3954. @36dGet the address and size of the block
  3955. @36dcorresponding to it.
  3956. @36dDeallocate the block.
  3957. @36dGo back and check for more MemEntries.
  3958.  
  3959.         ; Enter here if the AllocEntry failed, after deallocating anything
  3960.         ; which was allocated before the failure.
  3961.  
  3962. @36dGet size of the allocate which failed.
  3963. @d
  3964. @36dSet the high bit.
  3965. @36dReturn it to the user.
  3966.  
  3967.  
  3968. ---------------------------------------------------------------------------
  3969.   FreeEntry( memList )
  3970.              A0
  3971. ---------------------------------------------------------------------------
  3972.  
  3973. @d
  3974. @36dPoint to the MemList.
  3975. @36dPoint to the first MemEntry.
  3976. @36dGet number of MemEntries.
  3977. @36dFor each MemEntry in the MemList do
  3978. @36d  Get the address of the memory block.
  3979. @36d  Get the sizde of the memory block.
  3980. @36d  If size is not zero then
  3981. @36d    Deallocate the block.
  3982. @36d  Endif
  3983. @36dEndfor
  3984. @d
  3985. @36dGet the number of MemEntries again.
  3986. @d
  3987. @36dCompute the size of the MemList.
  3988. @36dPoint to the base of the MemList.
  3989. @36dDeallocate it.
  3990. @d
  3991. @d
  3992.  
  3993.  
  3994. ---------------------------------------------------------------------------
  3995.   error = AddMemList( size, attributes, pri, base, name )
  3996.   D0                  D0    D1          D2   A0    A1
  3997. ---------------------------------------------------------------------------
  3998.  
  3999.         ; This routine takes a block of memory, builds a MemHeader at the
  4000.         ; start of it, and puts the rest of the block into the MemHeader's
  4001.         ; free list.  Then it adds the MemHeader to the system free memory
  4002.         ; list.
  4003.  
  4004. @36dStore the name in the MemHeader.
  4005. @36dCompute first address after MemHeader.
  4006. @36dMemHeader's node type is NT_MEMORY.
  4007. @36dSet the MemHeader's priority.
  4008. @36dSet the memory attributes.
  4009. @d
  4010. @36dRound the base address of the block up
  4011. @36dto the nearest multiple of 8.
  4012. @d
  4013. @36dCompute by how much it changed,
  4014. @36dand add this amount to the length.
  4015. @36dTruncate the length to a multiple of 8.
  4016. @36dSubtract the size of the MemHeader.
  4017. @36dStore base address as lower bound of
  4018. @36dmemory and link to first MemChunk.
  4019. @d
  4020. @36dCompute upper bound address.
  4021. @36dStore it in the MemHeader.
  4022. @36dStore the amount of free memory.
  4023. @36dBuild a MemChunk at the start of free
  4024. @36dmemory (clear link, store size).
  4025. @36dGet base address of MemHeader
  4026. @36dPoint to the system free memory list.
  4027. @36dPut the MemHeader on the list.
  4028. @d
  4029.  
  4030. @8p@28wPadding.
  4031.  
  4032.  
  4033.         ; Data table used to build the exec jump vector table.
  4034.  
  4035.         ; There are 105 entries, corresponding to the 105 exec functions,
  4036.         ; followed by a -1 table end marker.  Each entry is a 16-bit
  4037.         ; relative offset from the start of the table.
  4038.  
  4039. @7p@9l@9l@9l@l
  4040. @7p@9l@9l@9l@l
  4041. @7p@9l@9l@9l@l
  4042. @7p@9l@9l@9l@l
  4043. @7p@9l@9l@9l@l
  4044. @7p@9l@9l@9l@l
  4045. @7p@9l@9l@9l@l
  4046. @7p@9l@9l@9l@l
  4047. @7p@9l@9l@9l@l
  4048. @7p@9l@9l@9l@l
  4049. @7p@9l@9l@9l@l
  4050. @7p@9l@9l@9l@l
  4051. @7p@9l@9l@9l@l
  4052. @7p@w
  4053.  
  4054. @7p@29wEnd of table marker.
  4055.  
  4056. @7p@29wLooks like garbage.
  4057. @7p@w
  4058.  
  4059.  
  4060. ---------------------------------------------------------------------------
  4061.   AddPort( port )
  4062.            A1
  4063. ---------------------------------------------------------------------------
  4064.  
  4065. @36dAddress of port's message list.
  4066. @36dInitialize the list's head pointer.
  4067. @d
  4068. @36dInitialize the list's Tail field.
  4069. @36dInitialize the list's TailPred pointer.
  4070. @36dAddress of the public message port list.
  4071. @36dSafely add port to the list.
  4072.  
  4073.  
  4074. ---------------------------------------------------------------------------
  4075.   RemPort( port )
  4076.            A1
  4077. ---------------------------------------------------------------------------
  4078. @a?fc1b30
  4079.  
  4080.         ; Call a general purpose subroutine which unlinks something from
  4081.         ; its queue while disabling multitasking.
  4082.  
  4083. @d
  4084.  
  4085.  
  4086. ---------------------------------------------------------------------------
  4087.   PutMsg( port, message )
  4088.           A0    A1
  4089. ---------------------------------------------------------------------------
  4090.  
  4091. @36dMake sure message node type is NT_MESSAGE
  4092. @d
  4093. @36dCompute address of port's message list
  4094.  
  4095. @36dDisable()
  4096. @d
  4097.  
  4098.         ; Enqueue the message at the end of the port's message list
  4099.  
  4100. @36dPoint A0 at port's Tail field.
  4101. @36dSave pointer to last node in list
  4102. @36dMake new node the last node
  4103. @36dNew node has no next node
  4104. @36dLink new node back to old last node
  4105. @d
  4106. @36dLink old last node to new node
  4107.  
  4108.         ; Do whatever needs to be done on message arrival.
  4109.  
  4110. @d
  4111. @36dGet address of message port's task.
  4112. @36dExit if port has no task.
  4113.  
  4114. @36dGet port's flag bits.
  4115. @d
  4116. @36dDecode the flag bits.
  4117. @d
  4118. @d
  4119.  
  4120.         ; Processing for PA_SOFTINT
  4121.  
  4122. @d
  4123. @36dCause the software interrupt.
  4124. @d
  4125.  
  4126.         ; If PA_IGNORE, do nothing.
  4127.  
  4128. @d
  4129. @d
  4130.  
  4131.         ; (Undocumented?) processing for mp_Flags = 3.  Apparently,
  4132.         ; calls a subroutine at mp_SigTask.
  4133.  
  4134. @d
  4135. @d
  4136. @d
  4137.  
  4138.         ; Processing for PA_SIGNAL
  4139.  
  4140. @36dGet SigBit.
  4141. @d
  4142. @36dCompute corresponding signal mask.
  4143. @d
  4144. @d
  4145. @36dSignal the task.
  4146.  
  4147. @36dEnable()
  4148. @d
  4149. @d
  4150. @d
  4151.  
  4152.  
  4153. ---------------------------------------------------------------------------
  4154.   message = GetMsg( port )
  4155.   D0                A0
  4156. ---------------------------------------------------------------------------
  4157.  
  4158. @36dPoint A0 at head of port's message list.
  4159.  
  4160. @36dDisable()
  4161. @d
  4162.  
  4163.         ; Try to dequeue a message from the message list.
  4164.  
  4165. @36dGet head pointer into A1.
  4166. @d
  4167. @36dIf list is empty, just return zero.
  4168. @d
  4169. @36dUnlink the message from the list.
  4170. @d
  4171.  
  4172.         ; Reenable interrupts if necessary and exit.
  4173.  
  4174. @36dEnable()
  4175. @d
  4176. @d
  4177. @d
  4178.  
  4179.  
  4180. ---------------------------------------------------------------------------
  4181.   ReplyMsg( message )
  4182.             A1
  4183. ---------------------------------------------------------------------------
  4184.  
  4185. @36dGet address of reply port.
  4186. @d
  4187. @36dNo reply port.  Set node type to
  4188. @36dNT_FREEMSG and exit.
  4189.  
  4190. @36dSet node type to NT_REPLYMSG.
  4191. @d
  4192. @36dSend the message via the reply port.
  4193.  
  4194.  
  4195. ---------------------------------------------------------------------------
  4196.   message = WaitPort( port )
  4197.   D0                  A0
  4198. ---------------------------------------------------------------------------
  4199.  
  4200. @36dGet head pointer of port's message list.
  4201. @36dCheck if list is empty.
  4202. @36dIf not empty, return right away.
  4203.  
  4204. @36dList was empty.  Get signal bit.
  4205. @36dPoint A0 at message list.
  4206. @d
  4207. @36dCompute signal mask.
  4208. @d
  4209. @d
  4210. @36dWait()
  4211. @d
  4212. @36dCheck message list.
  4213. @36dIf still empty, go back and wait again.
  4214. @d
  4215. @36dReturn first message in the list.
  4216. @d
  4217.  
  4218.  
  4219. ---------------------------------------------------------------------------
  4220.   port = FindPort( name )
  4221.   D0               A1
  4222. ---------------------------------------------------------------------------
  4223.  
  4224. @36dPoint to the public port list.
  4225. @36dSearch it for a port of the given name.
  4226. @d
  4227.  
  4228.  
  4229. ---------------------------------------------------------------------------
  4230.   AddResource( resource )
  4231.                A1
  4232. ---------------------------------------------------------------------------
  4233.  
  4234. @36dPoint to the resource list.
  4235. @36dAdd the resource to the list.
  4236.  
  4237.  
  4238. ---------------------------------------------------------------------------
  4239.   RemResource( resource )
  4240.                A1
  4241. ---------------------------------------------------------------------------
  4242.  
  4243. @36dUnlink the resource from the list.
  4244.  
  4245.  
  4246. ---------------------------------------------------------------------------
  4247.   resource = OpenResource( resName )
  4248.   D0                       A1
  4249. ---------------------------------------------------------------------------
  4250.  
  4251. @36dPoint to the resource list.
  4252. @36dForbid()
  4253. @36dFindName()
  4254. @36dPermit()
  4255. @d
  4256.  
  4257.  
  4258. @8p@28wPadding.
  4259.  
  4260. ---------------------------------------------------------------------------
  4261.   AddTask( task, initialPC, finalPC )
  4262.            A1    A2         A3
  4263. ---------------------------------------------------------------------------
  4264.  
  4265. @d
  4266. @36dMake the task state TS_ADDED.
  4267. @36dClear the task's flags.
  4268. @36dSet IDNestCnt and TDNestCnt to -1.
  4269. @d
  4270. @36dTask is not waiting for any signals.
  4271. @36dTask has not received any signals.
  4272. @36dTask does not have any exception signals.
  4273. @36dSet allocated traps.
  4274. @36dNo traps are enabled.
  4275.  
  4276. @36dInstall default system exception handler
  4277. @36dif the user has not provided one.
  4278. @d
  4279. @d
  4280. @d
  4281. @d
  4282.  
  4283. @36dGet the initial stack pointer.
  4284. @36dPut the exit code address on the stack.
  4285. @d
  4286. @36dUse system default if no exit code.
  4287.  
  4288. @36dClear 15 longwords below the process's
  4289. @36dinitial stack pointer, so all registers
  4290. @36dwill be zero when initially loaded.
  4291.  
  4292. @36dClear the initial status register.
  4293. @36dPut the initial PC on the stack.
  4294.  
  4295. @36dIf we have a 68881, then put another
  4296. @36dlongword on the stack.
  4297. @d
  4298. @d
  4299. @36dPut the initial stack pointer back.
  4300.  
  4301. @d
  4302. @36dDisable()
  4303. @d
  4304. @36dMake the task state TS_READY.
  4305. @36dPut the task on the TaskReady queue.
  4306. @d
  4307. @36dEnable()
  4308. @d
  4309. @d
  4310. @36dIf the task ended up at the front of the
  4311. @36dTaskReady queue, then
  4312. @36dReschedule()
  4313. @d
  4314.  
  4315.         ; System default task exit function
  4316.         ; ---------------------------------
  4317.  
  4318. @36dGet ExecBase.
  4319. @d
  4320. @36dAsk for current task to be removed.
  4321.  
  4322.         ; fall through into RemTask.
  4323.  
  4324.  
  4325. ---------------------------------------------------------------------------
  4326.   RemTask( task )
  4327.            A1
  4328. ---------------------------------------------------------------------------
  4329.  
  4330. @d
  4331. @36dCheck address of task to be removed.
  4332. @36dBranch if not zero.
  4333. @36dIf zero, use the current task.
  4334. @d
  4335. @36dIf not zero, check if it was the current
  4336. @36dtask anyway.
  4337.  
  4338.         ; The following is executed only if the task to be removed is not
  4339.         ; the current one.  This is because the currently running task isn't
  4340.         ; on a queue anywhere.
  4341.  
  4342. @36dDisable()
  4343. @d
  4344. @36dUnlink the task from its queue.
  4345. @d
  4346. @36dEnable()
  4347. @d
  4348.  
  4349. @36dGet the address of the task back.
  4350. @36dMake the task TS_REMOVED.
  4351. @36dCheck if it is the current task.
  4352. @d
  4353. @36dIf so, disable task switching now.
  4354.  
  4355. @36dPoint to allocated memory list.
  4356. @d
  4357. @36dExit if the head pointer is zero,
  4358. @36dor if the tail pointer points back at
  4359. @36dthe list header.
  4360. @36dZero the list head pointer.
  4361.  
  4362.         ; Loop:  Release all the memory blocks which the task had allocated.
  4363.  
  4364. @36dGet pointer to current list node.
  4365. @36dGet pointer to next list node.
  4366. @36dExit if the end of the list was reached.
  4367. @36dFreeEntry() this list node.
  4368. @36dBack to the head of the loop.
  4369.  
  4370. @36dCheck if the current task was removed.
  4371. @36dIf not, indicate success and exit.
  4372. @d
  4373. @36dGo to supervisor mode.
  4374. @36dPop exception data from the stack.
  4375. @36dDispatch() a new task.
  4376.  
  4377. @36dIf the current task was not removed,
  4378. @36dindicate success and return.
  4379. @d
  4380.  
  4381.  
  4382. ---------------------------------------------------------------------------
  4383.   task = FindTask( name )
  4384.   D0               A1
  4385. ---------------------------------------------------------------------------
  4386.  
  4387. @36dSee if a name was given.
  4388. @d
  4389. @36dIf not, use this task.
  4390. @d
  4391. @36dPoint at the TaskReady queue.
  4392. @36dDisable()
  4393. @d
  4394. @36dCall FindName() to look for the task.
  4395. @36dCheck if found, return address if so.
  4396. @d
  4397. @36dTask not found, try TaskWait queue.
  4398. @36dCall FindName() to look for the task.
  4399. @36dCheck if found, return address if so.
  4400. @d
  4401. @36dStill not found, compare name with that
  4402. @36dof the current task.
  4403. @d
  4404. @36dIf names differ, return zero (not found).
  4405. @d
  4406. @d
  4407. @36dTask was the current task.
  4408. @36dEnable()
  4409. @d
  4410. @d
  4411. @d
  4412.  
  4413.  
  4414. ---------------------------------------------------------------------------
  4415.   oldPriority = SetTaskPri( task, priority )
  4416.   D0                        A1    D0
  4417. ---------------------------------------------------------------------------
  4418.  
  4419. @36dDisable()
  4420. @d
  4421. @36dSave the task's current priority.
  4422. @36dSet the task's new priority.
  4423. @36dCheck if it was the current task.
  4424. @36dIf so, go reschedule it.
  4425. @36dCheck if the task was TS_READY.
  4426. @36dIf not, we're done.
  4427. @d
  4428. @36dTake the task out of the TaskReady queue.
  4429. @d
  4430. @36dAnd put it back in the right place
  4431. @36dcorresponding to its new priority.
  4432. @36dSee if it ended up at the front.
  4433. @36dIf not, we're done.
  4434.  
  4435.         ; If we get here, either we've changed the priority of the current
  4436.         ; task, or we've moved another task to the front of the TaskReady
  4437.         ; queue.  Either way, we have to check if the current task should
  4438.         ; be preempted.
  4439.  
  4440. @36dReschedule()
  4441. @d
  4442. @36dEnable()
  4443. @d
  4444. @d
  4445. @36dReturn the previous priority.
  4446. @d
  4447.  
  4448.  
  4449. ---------------------------------------------------------------------------
  4450.   oldSignals = SetExcept( newSignals, signalMask )
  4451.   D0                      D0          D1
  4452. ---------------------------------------------------------------------------
  4453.  
  4454. @36dGet pointer to current task.
  4455. @36dPoint to its SigExcept longword.
  4456. @36dDrop into SetSignal.
  4457.  
  4458.  
  4459. ---------------------------------------------------------------------------
  4460.   oldSignals = SetSignal( newSignals, signalMask )
  4461.   D0                      D0          D1
  4462. ---------------------------------------------------------------------------
  4463.  
  4464. @36dGet pointer to current task.
  4465. @36dPoint to its SigRecvd longword.
  4466.  
  4467.         ; This code is common to SetExcept and SetSignal.
  4468.  
  4469. @36dMask out signals to be left alone.
  4470. @36dDisable()
  4471. @d
  4472. @36dSave current value of signal word.
  4473. @36dMake mask of singnals to leave alone.
  4474. @36dGet those signals only.
  4475. @36dOr in the changed signals.
  4476. @36dPut the result back in the task.
  4477.  
  4478.         ; Now we drop into Signal(), which will process any new signals
  4479.         ; we may have set in the SigRecvd longword.
  4480.  
  4481. @36dGet the SigRecvd data.
  4482. @36dDrop into Signal.
  4483.  
  4484.  
  4485. ---------------------------------------------------------------------------
  4486.   Signal( task, signals )
  4487.           A1    D0
  4488. ---------------------------------------------------------------------------
  4489.  
  4490. @36dGet the set of received signals.
  4491. @36dDisable()
  4492. @d
  4493. @36dStore the signals.
  4494. @36dOr the new signals into the old ones.
  4495.  
  4496.         ; The code from here down is common to SetExcept, SetSignal, and
  4497.         ; Signal.  It checks if the task whose signals are being modified
  4498.         ; should be awakened.
  4499.  
  4500. @36dCheck the exception signals,
  4501. @36dand see if any of them have become set.
  4502. @36dIf so, go process them.
  4503. @36dSee if the task is in the TS_WAIT state.
  4504. @36dIf not, we're done.
  4505. @36dSee if a signal being waited for has been
  4506. @36dset.  If not, we are done.
  4507.  
  4508.         ; We have set a signal which the task was currently waiting for,
  4509.         ; so we must awaken it.  First, we take it out of the TaskWait
  4510.         ; list then we make it TS_READY, then we put it on the TaskReady
  4511.         ; queue and check if it should preempt the current task.
  4512.  
  4513. @d
  4514. @36dSave pointer to the task.
  4515. @36dGet pointer to the next task in the list.
  4516. @36dGet pointer to the previous task.
  4517. @36dUnlink from the previous task.
  4518. @36dUnlink from the next task.
  4519. @36dRestore pointer to the task.
  4520. @36dMake the task TS_READY.
  4521. @36dPoint to the TaskReady queue.
  4522. @36dEnqueue the task in the right place.
  4523. @36dCheck if it was put at the head of the
  4524. @36dTaskReady queue, and exit if not.
  4525. @d
  4526. @36dEnable()
  4527. @d
  4528. @36dReturn old signals to caller eventually.
  4529. @36dReschedule() so the task can run.
  4530.  
  4531.         ; Enter here if we have set an exception signal, or if a previously
  4532.         ; set signal has become an exception signal.
  4533.  
  4534. @36dSet the task's TB_EXCEPT flag.
  4535. @36dSee if it is in the TS_WAIT state.
  4536.  
  4537.         ; If the task for which the exception occurred was in the TS_WAIT
  4538.         ; state, make it TS_READY and move it from the TaskWait list to
  4539.         ; the TaskReady queue.  Otherwise, just dispatch it.
  4540.  
  4541. @d
  4542. @d
  4543.  
  4544.         ; Exit here if the current task was allowed to keep running (i.e.
  4545.         ; the other task did not preempt it).
  4546.  
  4547. @36dEnable()
  4548. @d
  4549. @d
  4550. @36dReturn old signals.
  4551. @d
  4552.  
  4553.  
  4554. ---------------------------------------------------------------------------
  4555.   signals = Wait( signalSet )
  4556.   D0              D0
  4557. ---------------------------------------------------------------------------
  4558.  
  4559. @36dGet the pointer to the current task.
  4560. @36dRecord which signals we are waiting for.
  4561. @36dDisable()
  4562. @d
  4563. @36dEnter the loop at the bottom.
  4564.  
  4565.         ; Main loop:  We stay here until we have a signal we want.
  4566.  
  4567. @36dMake the task state TS_WAIT.
  4568. @36dPoint to the TaskWait list.
  4569. @d
  4570. @36dUnlink the task from the TaskReady
  4571. @36dqueue, and put it in the TaskWait
  4572. @36dlist.
  4573. @d
  4574. @d
  4575. @d
  4576.  
  4577.         ; Here we block.  Calling Switch() gives control to any other
  4578.         ; process.  Eventually, someone else doing a Signal() will put us
  4579.         ; back on the TaskReady list, and then we will return from the
  4580.         ; Switch() when our priority comes up again.
  4581.  
  4582. @36dSave A5.
  4583. @36dGet ready to call Switch(), but first...
  4584. @36dEnter Supervisor mode.
  4585.  
  4586.         ; We're back.  See if we now have a signal we want.
  4587.  
  4588. @36dRestore A5.
  4589. @36dGet pointer to current process.
  4590. @36dGet the signals we are waiting for.
  4591.  
  4592.         ; We initially enter here to see if we have to block at all, and
  4593.         ; again each time we have been unblocked to see if we can now
  4594.         ; continue running.
  4595.  
  4596. @36dGet the signals which are currently set.
  4597. @36dCheck against signals to wait for.
  4598. @36dIf not, go back and block again.
  4599.  
  4600.         ; Eventually, we end up here.  We now have one or more signals
  4601.         ; that were being waited for.  We take these out of the set of
  4602.         ; received signals, since we will return them to the caller.
  4603.  
  4604. @36dUpdate the set of received signals.
  4605. @d
  4606. @36dEnable()
  4607. @d
  4608. @36dReturn the signals.
  4609. @d
  4610.  
  4611.  
  4612. ---------------------------------------------------------------------------
  4613.   Reschedule()
  4614. ---------------------------------------------------------------------------
  4615.  
  4616.         ; This function is used when it is possible that a task should
  4617.         ; be preempted and another task run in its place.  It sets the
  4618.         ; scheduling attention flag to force the scheduler to do its thing
  4619.         ; as soon as possible.  If multitasking is disabled, that's all
  4620.         ; it does, since Permit() will do the rest when multitasking is
  4621.         ; turned on again.  If interrupts are disabled, it sets the software
  4622.         ; generated interrupt.  Since this is not accompanied by setting
  4623.         ; the software interrupt pending flag, it will do nothing but
  4624.         ; run ExitIntr() as soon as the interrupt level allows it.
  4625.         ; ExitIntr() will then cause the outstanding scheduling operation
  4626.         ; to be done.
  4627.  
  4628.         ; Note that part of Permit() is used to switch into supervisor
  4629.         ; mode and call the scheduler.
  4630.  
  4631. @36dSet the scheduling attention flag.
  4632. @36dSave its previous state.
  4633. @36dCheck if multitasking enabled.
  4634. @36dIf not, exit.
  4635. @36dCheck if interrupts enabled.
  4636. @36dIf so, go and do the scheduling.
  4637. @36dCheck the (old) scheduling attn flag.
  4638. @36dExit if it was already set.
  4639. @36dAssert the software generated interrupt.
  4640. @d
  4641.  
  4642.  
  4643. ---------------------------------------------------------------------------
  4644.   Forbid()
  4645. ---------------------------------------------------------------------------
  4646.  
  4647. @36dIncrement the TDNestCnt.
  4648. @d
  4649.  
  4650.  
  4651. ---------------------------------------------------------------------------
  4652.   Permit()
  4653. ---------------------------------------------------------------------------
  4654.  
  4655. @36dDecrement the TDNestCnt.
  4656. @36dExit if still positive.
  4657. @36dCheck if interrupts disabled.
  4658. @36dExit if yes.
  4659.  
  4660.         ; The current task has just reenabled multitasking.  If the system
  4661.         ; is waiting to switch tasks, now is the time to do it.
  4662.  
  4663. @36dCheck the scheduling attention flag.
  4664. @36dExit if not pending.
  4665. @36dSave A5.
  4666. @36dSet address to go to in supervisor mode.
  4667. @36dEnter supervisor mode.
  4668. @36dRestore A5 and return.
  4669. @d
  4670.  
  4671.         ; This is executed in supervisor mode.
  4672.  
  4673. @36dCheck caller's supervisor mode flag.
  4674. @36dIf the caller was in supervisor mode,
  4675. @36dthen don't switch tasks.
  4676.  
  4677.         ; Eventually, this task will be dispatched again, using the program
  4678.         ; counter and status register left on the stack by the supervisor
  4679.         ; mode call.  Then it continues running above, pops A5 from the
  4680.         ; stack, and returns to the caller.
  4681.  
  4682. @36dGo and do the scheduling.
  4683.  
  4684.  
  4685. ---------------------------------------------------------------------------
  4686.   trapNum = AllocTrap( trapNum )
  4687.   D0                   D0
  4688. ---------------------------------------------------------------------------
  4689.  
  4690. @36dGet pointer to the current task.
  4691. @36dGet the task's TrapAlloc flags.
  4692. @36dSee if we want a particular trap number.
  4693. @d
  4694. @36dIf so, set this trap number's flag bit.
  4695. @36dIf it wasn't set, indicate success.
  4696. @36dIt was already set, indicate failure.
  4697.  
  4698.         ; Look for a free trap number.
  4699.  
  4700. @36d16 traps to check.  Start at #15.
  4701. @36dTry to set this trap's flag bit.
  4702. @36dIf not set before, indicate success.
  4703. @36dLoop until all flags checked.
  4704. @36dIndicate failure.
  4705. @36dPut updated trap flags back.
  4706. @d
  4707.  
  4708.  
  4709. ---------------------------------------------------------------------------
  4710.   FreeTrap( trapNum )
  4711.             D0
  4712. ---------------------------------------------------------------------------
  4713.  
  4714. @36dGet pointer to the current task.
  4715. @36dGet the task's TrapAlloc flags.
  4716. @36dClear the specified flag.
  4717. @36dPut the flags back.
  4718. @d
  4719.  
  4720.  
  4721. ---------------------------------------------------------------------------
  4722.   signalNum = AllocSignal( signalNum )
  4723.   D0                       D0
  4724. ---------------------------------------------------------------------------
  4725.  
  4726. @36dGet pointer to the current task.
  4727. @36dGet the task's SigAlloc flags.
  4728. @36dSee if we want a particular signal.
  4729. @d
  4730. @36dIf so, try to set its flag.
  4731. @36dIndicate success if it was clear.
  4732. @36dIndicate failure if already set.
  4733.  
  4734.         ; Look for a free signal.
  4735.  
  4736. @36d32 Signals to check.  Start at 31.
  4737. @36dTry to set the signal's flag.
  4738. @36dIf it wasn't already set, success.
  4739. @36dOtherwise, keep looking.
  4740. @36dIndicate failure.
  4741. @d
  4742.  
  4743. @36dSuccess.  Update allocated signal flags.
  4744. @d
  4745. @36dSet all but this signal bit in D1.
  4746. @36dMake sure this signal isn't set.
  4747. @36dMake sure it's not an exception signal.
  4748. @36dIndicate that we are not waiting for it.
  4749. @d
  4750.  
  4751.  
  4752. ---------------------------------------------------------------------------
  4753.   FreeSignal( signalNum )
  4754.               D0
  4755. ---------------------------------------------------------------------------
  4756.  
  4757. @36dGet pointer to the current task.
  4758. @36dGet the SigAlloc flags.
  4759. @36dClear the indicated signal bit.
  4760. @36dPut the flags back.
  4761. @d
  4762.  
  4763.  
  4764.         ; Subroutines for RawDoFmt()
  4765.         ; --------------------------
  4766.  
  4767.         ; Find the length of a null-terminated string pointed to by A0.
  4768.         ; For efficiency, the length is counted up as a negative number.
  4769.  
  4770. @a?fc200c
  4771. @40dStart the length at -1.
  4772. @40dGet string character, test for end.
  4773. @40dCount, and loop until end of string.
  4774. @d
  4775. @40dConvert length to correct +ve value.
  4776. @d
  4777.  
  4778.  
  4779.         ; Evaluate a decimal numeric constant pointed to by A4.
  4780.  
  4781. @40dStart the result at 0.
  4782. @d
  4783. @40dGet a character from the input.
  4784. @a?fc2020
  4785. FC2020  cmp.b     #'0',D2
  4786. @a=fc2024
  4787. @d
  4788. FC2026  cmp.b     #'9',D2               If not a numeric digit, exit.
  4789. @a=fc202a
  4790. @d
  4791. @40dMultiply previous result by 10.
  4792. @d
  4793. @d
  4794. @d
  4795. @d
  4796. @a?fc2036
  4797. FC2036  sub.b     #'0',D2               Convert digit to number 0 - 9.
  4798. @a=fc203a
  4799. @40dAdd to result.
  4800. @40dGo evaluate next character.
  4801.  
  4802.         ; Finish up by pointing back at the non-digit character.
  4803.  
  4804. @40dBackspace the input pointer.
  4805. @d
  4806.  
  4807.  
  4808.         ; Convert the number in D4 to its decimal ASCII representation.
  4809.  
  4810. @40dIs the number zero?
  4811. @40dIf so, just output "0" and return.
  4812. @40dIs it negative?
  4813. @40dIf not, make it negative.
  4814. @d
  4815. @a?fc204c
  4816. FC204C  move.b    #'-',(A5)+            If so, output a "-".
  4817. @a=fc2050
  4818.  
  4819.         ; The minus sign is taken care of, and negative the number to
  4820.         ; be output is in D4.
  4821.  
  4822. @40dPoint at table of divisors.
  4823. @40dClear the "non-zero digit" flag.
  4824.  
  4825. @40dGet a divisor from the table.
  4826. @40dIf zero, output last digit and exit.
  4827.  
  4828.         ; Subtract the current divisor from the number as many times as
  4829.         ; possible (actually, add to its negative).
  4830.  
  4831. @40dStart the counter at -1.
  4832. @40dTry to add the divisor to D4.
  4833. @40dLoop until D4 is greater than zero.
  4834. @40dMake the number less than zero again.
  4835. @40dIncrement the counter by 1.
  4836.  
  4837.         ; D0 now contains negative the current digit to output.  Discard
  4838.         ; it if it is a leading zero.
  4839.  
  4840. @40dIf the current digit is zero then
  4841. @40dif no non zero digits have been
  4842. @40doutput, then discard it.
  4843.  
  4844.         ; Output the digit.
  4845.  
  4846. @40dSet "non-zero digit" flag.
  4847. @40dMake D0 positive.
  4848. @a?fc2072
  4849. FC2076  add.b     #'0',D0               Convert to an ASCII digit.
  4850. @a=fc2076
  4851. @40dPut it into the buffer.
  4852. @40dGo do the next digit.
  4853.  
  4854.         ; Enter here to output the last digit, or the single "0" if the
  4855.         ; number is zero.
  4856.  
  4857. @40dMake D0 positive.
  4858. @a?fc207c
  4859. FC207C  add.b     #'0',D4               Convert to an ASCII digit.
  4860. @a=fc2080
  4861. @40dPut it into the buffer.
  4862. @d
  4863.  
  4864.  
  4865.         ; Table of divisors.
  4866.  
  4867. @8p@32l1000000000 decimal.
  4868. @8p@33l100000000 decimal.
  4869. @8p@34l10000000 decimal.
  4870. @8p@35l1000000 decimal.
  4871. @8p@36l100000 decimal.
  4872. @8p@37l10000 decimal.
  4873. @8p@38l1000 decimal.
  4874. @8p@39l100 decimal.
  4875. @8p@40l10 decimal.
  4876. @8p@41l0 decimal.
  4877.  
  4878.  
  4879.         ; Convert the number in D4 to its hexadecimal ASCII representation.
  4880.  
  4881. @a?fc20ac
  4882. @40dIs the number zero?
  4883. @40dIf so, just output "0" and exit.
  4884. @40dClear "non-zero digit" flag.
  4885. @40dIs the data 32 bits long?
  4886. @d
  4887. @40dIf not, output 4 digits,
  4888. @40dfrom the high word of D4.
  4889. @d
  4890. @40dIf so, output 8 digits.
  4891.  
  4892.         ; Digit output loop.
  4893.  
  4894. @40dRotate leftmost digit into bits 0-3.
  4895. @d
  4896. @40dMask out all but bits 0-3.
  4897.  
  4898.         ; Skip leading zeros.
  4899.  
  4900. @40dIf no non-zero digit has been
  4901. @40dencountered yet, and this is a zero,
  4902. @40dskip it.
  4903.  
  4904. @40dSet "non-zero digit" flag.
  4905. @40dIs the digit greater than 9?
  4906. @d
  4907. @a?fc20d6
  4908. FC20D6  add.b     #'0',D0               If not, convert to ASCII numeral.
  4909. @a=fc20DA
  4910. @d
  4911. FC20DC  add.b     #$37,D0               If so, convert to upper case letter.
  4912. @a=fc20e0
  4913. @40dPut digit in buffer.
  4914. @40dLoop until all digits done.
  4915. @d
  4916.  
  4917.  
  4918. ---------------------------------------------------------------------------
  4919.   RawDoFmt( FormatString, DataStream, PutChProc, PutChData )
  4920.             A0            A1          A2         A3
  4921. ---------------------------------------------------------------------------
  4922.  
  4923. @d
  4924. @40dReserve stack space for buffer.
  4925. @40dStore data stream pointer.
  4926. @40dPoint to the format string.
  4927. @40dGet a byte from the format string.
  4928. @40dCheck for end and exit if found.
  4929. @a?fc20f8
  4930. FC20F8  cmp.b     #'%',D0               Check for format specifier.
  4931. @a=fc20fc
  4932. @40dProcess it if found.
  4933. @40dOtherwise, output the character,
  4934. @40dand go on to the next one.
  4935. @40dOutput the terminating zero.
  4936. @40dDeallocate the output buffer.
  4937. @d
  4938. @d
  4939.  
  4940.         ; Enter here if the "%" format specifier was found.  Next we check
  4941.         ; for the characters "-", signaling that the printed item should
  4942.         ; be left-aligned in its field, and "0", signaling that leading
  4943.         ; zeros should be attached.
  4944.  
  4945. @40dPoint to the output buffer.
  4946. @40dClear the option flags.
  4947. @a?fc2112
  4948. FC2112  cmp.b     #'-',(A4)             Left alignment desired?
  4949. @a=fc2116
  4950. @d
  4951. @40dIf so, set the corresponding flag,
  4952. @40dand go on to the next character.
  4953. FC211E  cmp.b     #'0',(A4)             Zero fill desired?
  4954. @a=fc2122
  4955. @d
  4956. @40dIf so, set the corresponding flag.
  4957. @40dGet the field width.
  4958. @40dStore it in D6.
  4959. @40dAssume no maximum length.
  4960. @a?fc2130
  4961. FC2130  cmp.b     #'.',(A4)             Maximum length specifier?
  4962. @a=fc2134
  4963. @d
  4964. @40dIf so, go on to the next character,
  4965. @40dand get the maximum length.
  4966. @40dStore maximum length.
  4967. FC213E  cmp.b     #'l',(A4)             32 bit data?
  4968. @a=fc2142
  4969. @d
  4970. @40dIf so, set the corresponding flag,
  4971. @40dand go on to the next character.
  4972.  
  4973.         ; At this point, we have interpreted a format string of the format
  4974.         ; "%-0xxx.yyyl".  In D3, bit 0 is set if the "-" was present, bit 1
  4975.         ; is set if the "0" was present, and bit 2 is set if the "l"
  4976.         ; was present.  D6 contains the value of "xxx" (numeric constant),
  4977.         ; and D5 contains the value of "yyy" if present, or 0 if not.
  4978.  
  4979.         ; Now we process the actual format characters: "s" for string, "c"
  4980.         ; for character, "d" for decimal, "x" for hex.  In all cases, the
  4981.         ; goal is to build a null-terminated string, pointed to by A0,
  4982.         ; containing the formatted output.
  4983.  
  4984. @40dGet the next character.
  4985. @a?fc214c
  4986. FC214C  cmp.b     #'d',D0               Decimal output?
  4987. @a=fc2150
  4988. @40dSkip to next option if not.
  4989. @40dGet data item.
  4990. @40dFormat as decimal number.
  4991. @40dOutput the buffer.
  4992. FC215A  cmp.b     #'x',D0               Hexadecimal output?
  4993. @a=fc215e
  4994. @40dSkip to next option if not.
  4995. @40dGet data item.
  4996. @40dFormat as hexadecimal number.
  4997. @40dOutput the buffer.
  4998.  
  4999.         ; Subroutine to get a number from the data stream.  We get either
  5000.         ; a word or a longword, depending on whether an "l" was in the
  5001.         ; format specification.
  5002.  
  5003. @40dIf data size is 16 bits then
  5004. @d
  5005. @40d  Get data stream pointer.
  5006. @40d  Get a word from the data stream.
  5007. @40d  Put data stream pointer back.
  5008. @40d  Extend to longword.
  5009. @40dElse
  5010. @40d  Get data stream pointer.
  5011. @40d  Get a longword from data stream.
  5012. @40d  Put data stream pointer back.
  5013. @40dEndif
  5014.  
  5015.         ; Continue here if not formatting a number.
  5016.  
  5017. @a?fc2188
  5018. FC2188  cmp.b     #'s',D0               String output?
  5019. @a=fc218c
  5020. @40dIf not, skip to next.
  5021. @40dGet data stream pointer.
  5022. @40dPoint directly at the string.
  5023. @40dPut data stream pointer back.
  5024. @40dOutput the string.
  5025. FC2196  cmp.b     #'c',D0               Single character output?
  5026. @a=fc219a
  5027. @40dIf not, discard format specifier.
  5028. @40dGet character from input stream.
  5029. @40dPut it into the buffer.
  5030.  
  5031.         ; Numeric and character output, having put their formatted argument
  5032.         ; into the buffer, meet here.
  5033.  
  5034. @40dZero-terminate the buffer.
  5035. @40dPoint back to its start.
  5036.  
  5037.         ; All output options continue here.  A5 now points to a
  5038.         ; null-terminated string to output.
  5039.  
  5040. @d
  5041. @40dFind the length of the string.
  5042. @40dWas a maximum length specified?
  5043. @d
  5044. @40dIf so, and if the output string is
  5045. @40dlonger, set the length to the
  5046. @40dmaximum length.
  5047. @40dCompute amount of padding needed.
  5048. @d
  5049. @40dSet to zero if negative.
  5050. @40dWas left alignment desired?
  5051. @d
  5052. @40dIf not, output padding first.
  5053. @d
  5054. @40dLoop to copy the string to the output
  5055. @40duntil its end or the given maximum
  5056. @40dnumber of characters.
  5057. @40dWas left alignment desired?
  5058. @d
  5059. @40dIf so, output padding now.
  5060. @40dContinue with format string.
  5061.  
  5062.  
  5063.         ; Subroutine to output the right amount of padding.
  5064.  
  5065. @a?fc21de
  5066. FC21DE  move.b    #' ',D2               Assume padding with spaces.
  5067. @a=fc21e2
  5068. @40dWas zero-fill desired?
  5069. @d
  5070. FC21E8  move.b    #'0',D2               If so, pad with zeros.
  5071. @a=fc21ec
  5072. @d
  5073. @40dLoop to output the required number
  5074. @40dof padding characters.
  5075. @d
  5076. @d
  5077.  
  5078.  
  5079. ---------------------------------------------------------------------------
  5080.   RawIOInit()
  5081. ---------------------------------------------------------------------------
  5082.  
  5083.         ; Set the serial port for receiving 8 bit data at 9600 bps.
  5084.  
  5085. @40dSet up the SERPER register.
  5086. @d
  5087.  
  5088.  
  5089. ---------------------------------------------------------------------------
  5090.   RawMayGetChar()
  5091. ---------------------------------------------------------------------------
  5092.  
  5093. @d
  5094. @40dRead SERDATR.
  5095. @40dIs a byte in the receive buffer?
  5096. @40dIf not, return -1 and exit.
  5097. @40dClear the serial receive interrupt.
  5098. @40dGet the received character.
  5099. @40dReturn it to the caller.
  5100. @d
  5101.  
  5102.  
  5103.         ; Subroutine to wait for a character on the serial port.
  5104.  
  5105. @40dRawMayGetChar()
  5106. @40dDid we get a character?
  5107. @40dContinue waiting if not.
  5108. @40dReturn the character.
  5109.  
  5110.  
  5111.         ; This looks like a C entry point for RawPutChar.
  5112.  
  5113. @40dGet the first C parameter.
  5114.  
  5115. ---------------------------------------------------------------------------
  5116.   RawPutChar()
  5117. ---------------------------------------------------------------------------
  5118.  
  5119.         ; Don't output code 0, and expand newlines to CRLF.
  5120.  
  5121. @40dIs the character to send zero?
  5122. @40dIf so, don't send it.
  5123. @40dSave the character.
  5124. @40dIs it a newline?
  5125. @d
  5126. @40dIf so, send a carriage return first.
  5127. @d
  5128. @40dGet the character back.
  5129.  
  5130.         ; Enter here to send the character in D0 on the serial port.
  5131.  
  5132. @40dRead SERDATR.
  5133. @40dTransmitter ready?
  5134. @40dWait until true.
  5135.  
  5136. @40dMask out all but bits 0-7.
  5137. @40dSet the stop bit.
  5138. @40dWrite to SERDAT.
  5139.  
  5140.         ; Handle XON/XOFF and/or escape into the debugger if DEL pressed.
  5141.  
  5142. @40dRawMayGetChar()
  5143. @40dDid we get an XOFF?
  5144. @d
  5145. @40dIf yes, wait for any other character.
  5146. @d
  5147. @40dDid we get a DEL?
  5148. @40dReturn if not.
  5149. @40dIf so, Debug()
  5150. @40dOn return, check for XOFF again.
  5151. @d
  5152.  
  5153.  
  5154.         ; C compatible routine to print a string.
  5155.  
  5156. @40dGet first C parameter (string addr.)
  5157.  
  5158.         ; Assembly language entry point (address in A0).
  5159.  
  5160. @40dGet a string character.
  5161. @40dExit if is the terminating zero.
  5162. @40dIs it a newline?
  5163. @d
  5164. @40dIf so, output a CR first.
  5165. @d
  5166. @d
  5167. @40dOutput the character.
  5168. @40dGo on to next character.
  5169. @d
  5170.  
  5171.  
  5172.         ; C compatible function to output a hex number.  First argument
  5173.         ; is the number, second one is the number of digits.  The number
  5174.         ; will be output with one space following.
  5175.  
  5176. @40dGet C parameters.
  5177.  
  5178.         ; Assembly language entry point.
  5179.  
  5180. @d
  5181. @d
  5182. @d
  5183. @40dCompute 8 - number of digits.
  5184. @40dLoop that many times, rotating the
  5185. @40dnumber left by a digit each time,
  5186. @40dto left-align the number in D2.
  5187.  
  5188. @40dGet number of digits.
  5189. @d
  5190. @40dShift current digit into bits 0-3.
  5191. @d
  5192. @40dExtract bits 0-3 from the number.
  5193. @40dNumeric or alphabetic digit?
  5194. @d
  5195. @40dIf alphabetic, add ('A'-'9').
  5196. @a?fc22ba
  5197. FC22BA  add.b     #'0',D0               Convert to ASCII digit.
  5198. @a=fc22be
  5199. @40dOutput the digit.
  5200. @40dLoop until all digits done.
  5201. @d
  5202. @40dOutput a space.
  5203. @d
  5204. @d
  5205.  
  5206.  
  5207.         ; Entry point to do a RawDoFmt() to the serial port.
  5208.  
  5209. @40dSave A2.
  5210. @40dPoint A2 to RawPutChar() function.
  5211. @40dRawDoFmt()
  5212. @40dRestore A2.
  5213. @d
  5214.  
  5215.  
  5216. ---------------------------------------------------------------------------
  5217.   Open()
  5218. ---------------------------------------------------------------------------
  5219.  
  5220.         ; This gets executed if someone actually opens "exec.library".
  5221.  
  5222. @40dReturn ExecBase.
  5223. @40dIncrement exec.library open count.
  5224. @d
  5225.  
  5226.  
  5227. ---------------------------------------------------------------------------
  5228.   Close()
  5229. ---------------------------------------------------------------------------
  5230.  
  5231.         ; This gets executed if someone tries to close "exec.library".
  5232.  
  5233. @40dDecrement exec.library open count.
  5234.  
  5235.  
  5236. ---------------------------------------------------------------------------
  5237.   Expunge()
  5238. ---------------------------------------------------------------------------
  5239.  
  5240.         ; This gets executed if someone tries to Expunge() the exec.
  5241.         ; Needless to say, we won't do anything of the sort, but we'll make
  5242.         ; the caller happy by returning zero.
  5243.  
  5244.         ; The reserved jump vector (at ExecBase - 24) also points here.
  5245.  
  5246. @d
  5247. @d
  5248.  
  5249.  
  5250. @a?fc22f0
  5251.         ; ROM-Wack
  5252.         ; --------
  5253.  
  5254.         ; This is the Amiga's ROM resident mini-debugger.  The following
  5255.         ; string is sent out the serial port when it starts up.
  5256.  
  5257. @8p@,10s
  5258.  
  5259.         ; ROM-Wack has a private, 236 byte data area at $000200.  The
  5260.         ; following is a memory map of this area.  Addresses are given as
  5261.         ; hex offsets from $000200.
  5262.  
  5263.         ;-------------------------------------------------------------------
  5264.         ; 00  (32 bit)  Pointer to current key bindings.
  5265.         ; 04  (32 bit)  Saved key binding pointer if not using main ones.
  5266.         ; 08  (32 bit)  Value of last number entered by the user.
  5267.         ; 0C  (32 bit)  The "current address" for all operations.
  5268.         ; 10 - 13       (not used).
  5269.         ; 14  (32 bit)  The current "frame size".
  5270.         ; 18  (32 bit)  The upper limit address for searches and fills.
  5271.         ; 1C  (16 bit)  Number of characters in the input buffer.
  5272.         ; 1E  (8 bit)   Flag indicating whether the "frame" should be
  5273.         ;               redisplayed after a command has executed.
  5274.         ; 1F  (8 bit)   Flag indicating whether we are in "alter" mode.
  5275.         ; 20  (16 bit)  Flag indicating whether there is unprocessed data
  5276.         ;               in the buffer (0 if yes, 1 if no).
  5277.         ; 22  (16 bit)  Number of digits in the number most recently entered.
  5278.         ; 24  (16 bit)  Flag indicating whether a number is being gathered as
  5279.         ;               a parameter to a command, or being entered unprompted
  5280.         ;               (in which case it becomes the current address).
  5281.         ; 26  (32 bit)  Indirection stack pointer (for following pointers).
  5282.         ; 2A - 4F       (not used).
  5283.         ; 50 - 81       Input buffer for user commands.
  5284.         ; 82  (16 bit)  Last character typed by the user.
  5285.         ; 84  (32 bit)  Pointer to data area on the stack, holding CPU and
  5286.         ;               process related information (map farther down)
  5287.         ; 88  (16 bit)  Instruction to use for breakpoints (TRAP #15).
  5288.         ; 8A - E9       Breakpoint table.  Each entry consists of an address
  5289.         ;               where an instruction was replaced with TRAP #15, and
  5290.         ;               the word which had been there before.
  5291.         ; EA  (16 bit)  Value to be written to INTENA to restore serial
  5292.         ;               port interrupts to their original state.
  5293.         ;-------------------------------------------------------------------
  5294.  
  5295.  
  5296.         ; This gets called from the exec initialization code.
  5297.  
  5298. @40dSave ExecBase.
  5299. @40dPoint to ROM-Wack's data area.
  5300. @40dInitialize it.
  5301. @40dRestore ExecBase.
  5302. @40dInstall default ExecBase->DebugEntry.
  5303. @40dInstall default Debug() vector.
  5304. @40dRawIOInit()
  5305. @d
  5306.  
  5307.  
  5308.         ; Special exception handlers for ROM-Wack
  5309.         ; ---------------------------------------
  5310.  
  5311.         ; ROM-Wack trace exception handler.
  5312.  
  5313. @40dPush "Trace" exception number.
  5314. @40dEnter the debugger.
  5315.  
  5316.         ; ROM-Wack breakpoint exception handler.  A "TRAP #15" instruction
  5317.         ; is used for the breakpoint.
  5318.  
  5319. @40dPush "TRAP #15" exception number.
  5320. @40dEnter the debugger.
  5321.  
  5322. ---------------------------------------------------------------------------
  5323.   Debug()
  5324. ---------------------------------------------------------------------------
  5325.  
  5326.         ; This entry point is used when an actual function call to Debug()
  5327.         ; is made.  We set up the supervisor stack to look like it would
  5328.         ; after an exception handled by the exec exception entry points.
  5329.  
  5330. @40dSave A5.
  5331. @40dWhere to go in supervisor mode.
  5332. @40dSupervisor()
  5333.  
  5334.         ; We now have an exception stack frame from the Supervisor() call.
  5335.  
  5336. @40dPop the return address from the
  5337. @40dDebug() call from the user stack.
  5338. @d
  5339. @40dGet the return address back.
  5340. @40dFake exception number zero.
  5341.  
  5342.         ; Now the supervisor and user stacks look as if an exception had
  5343.         ; occurred and was handled by the exec, with the difference that
  5344.         ; the original value of A5 is on the supervisor stack, and A5 now
  5345.         ; contains the return address from the Debug() call.
  5346.  
  5347.  
  5348.         ; Exception entry point.
  5349.         ; ----------------------
  5350.  
  5351.         ; The debugger is entered here with the stacks already set up as
  5352.         ; above (by the system exception handler).  First, we verify if
  5353.         ; the stack is even working (pointing at RAM).
  5354.  
  5355. @40dPut a signature on the stack.
  5356. @40dCheck if it can be read back.
  5357. @d
  5358.  
  5359.         ; A signature pushed on the supervisor stack could not be read
  5360.         ; back, so we are in serious trouble.  Initialize the stack at
  5361.         ; the top of the first 256K of chip memory.  Put a fake exception
  5362.         ; stack frame on the new stack.
  5363.  
  5364. @40dStart stack at 256K.
  5365. @40dFake program counter.
  5366. @40dFake status register.
  5367. @40dPush exception number -1.
  5368. @d
  5369.  
  5370.         ; We now have a working supervisor stack with the exception
  5371.         ; number and stack frame on it.
  5372.  
  5373. @40dSave most of the CPU registers.
  5374. @40dPoint A5 at the exception number.
  5375. @40dReserve 22 bytes of stack space,
  5376. @40dand point A4 to the bottom of this.
  5377. @d
  5378. @40dGet the exception number.
  5379. @40dStore it.
  5380. @40dStore supervisor stack pointer.
  5381. @d
  5382. @40dStore user stack pointer.
  5383.  
  5384.         ; When a 680x0 hits an exception, it pushes the program counter, then
  5385.         ; the status register, onto the supervisor stack.  For bus and
  5386.         ; address errors, however, more information is saved.  On 68010 and
  5387.         ; 68020 processors, this comes before the program counter and status
  5388.         ; register, i.e. the stack pointer after an exception always points
  5389.         ; at these.  On the 68000, however, 8 bytes of other information
  5390.         ; are pushed on the stack AFTER the PC and SP.  The following code
  5391.         ; compensates for this.
  5392.  
  5393. @40dCheck CPU/FPP configuration.
  5394. @40dIs it a plain vanilla 68000?
  5395. @d
  5396. @40dWas it an address error?
  5397. @d
  5398. @40dWas it a bus error?
  5399. @d
  5400. @40dIf either, skip past bus error info.
  5401.  
  5402.         ; For all CPUs, A5 now points to where the status register and
  5403.         ; program counter are stored on the supervisor stack.
  5404.  
  5405. @40dCheck the supervisor mode bit.
  5406. @40dIf it was set,
  5407. @40dget ExecBase,
  5408. @40dand get the current task pointer.
  5409. @40dGet and store the status register.
  5410. @40dGet and store the program counter.
  5411.  
  5412.         ; Time for a summary (so I don't get confused).  A4 currently
  5413.         ; points at a data structure, on the supervisor stack, containing
  5414.         ; the following:
  5415.  
  5416.         ; (60 bytes) Register dump (D0-D7, A0-A6).
  5417.  
  5418.         ; (32 bit)   Current task pointer or zero.
  5419.         ; (32 bit)   Number of the exception that got us here (see below).
  5420.         ; (32 bit)   Saved supervisor stack pointer.
  5421.         ; (32 bit)   Saved user stack pointer.
  5422.         ; (16 bit)   Saved status register (from exception stack frame).
  5423.         ; (32 bit)   Saved program counter (from exception stack frame).
  5424.  
  5425.         ; If the exception number is zero, Debug() was used to get here.
  5426.  
  5427.         ; If the exception number is -1, we somehow got here, but the
  5428.         ; supervisor stack pointer was clobbered and not pointing to RAM.
  5429.         ; In this case, we have just set it to 256K, and the saved
  5430.         ; program counter and status register are invalid.
  5431.  
  5432. @40dPoint to ROM-Wack's data area.
  5433.  
  5434.         ; Disable serial port interrupts, and make a control word which,
  5435.         ; when written to INTENA, will return them to their original status.
  5436.  
  5437. @40dStore interrupt enable status.
  5438. @40dDisable serial port interrupts.
  5439. @d
  5440. @40dMake the control word to be used
  5441. @40dto restore those two interrupts.
  5442.  
  5443. @40dRawIOInit()
  5444. @d
  5445. @40dPrint a newline and "rom-wack".
  5446.  
  5447. @40dSave pointer to stack-resident data.
  5448. @40dMake the saved exception program
  5449. @40dcounter even (if not already so),
  5450. @40dand put it back.
  5451. @40dSet the "current address" there.
  5452. @40dDid a TRAP #15 get us here?
  5453. @40dSkip the following if not.
  5454.  
  5455.         ; Special handling for breakpoints.  Back the PC up by 2 (over
  5456.         ; the TRAP #15 instruction used for the breakpoint), and clear
  5457.         ; the breakpoint (restore the original instruction).
  5458.  
  5459. @40dBack up to breakpoint address.
  5460. @40d"clear" the breakpoint.
  5461.  
  5462. @40dUpdate the saved program counter.
  5463. @40dPoint to the stack-resident data.
  5464.  
  5465.         ; Install the exception vectors needed for breakpoints and
  5466.         ; single-stepping.
  5467.  
  5468. @40dInstall TRAP #15 exception vector.
  5469. @40dInstall "Trace" exception vector.
  5470. @40dSet the search limit to 16 megabytes.
  5471. @40dDisplay the ROM-Wack register frame.
  5472. @40dEnter the ROM-Wack main loop.
  5473.  
  5474.  
  5475.         ; Entry point for <Tab> command.
  5476.  
  5477.         ; Entry point to run a single instruction in trace mode.  This does
  5478.         ; everything required to resume running as below, but with the trace
  5479.         ; mode bit set in the saved status register, so only a single
  5480.         ; instruction will be executed after the RTE (and then we come back
  5481.         ; in at the top).
  5482.  
  5483. @40dPoint to data on system stack.
  5484. @40dGet the saved status register, set
  5485. @40dthe trace mode bit, and store it.
  5486. @d
  5487.  
  5488.         ; Set up to continue running after exit from ROM-Wack.  Note that
  5489.         ; to compensate for the different exception stack frame formats of
  5490.         ; bus error and regular exceptions, we don't even try to compensate
  5491.         ; for the format of the exception stack frame, just build one
  5492.         ; containing a simple status register and program counter right
  5493.         ; above the register dump.  This allows the RTE instruction to
  5494.         ; conveniently resume running whatever called ROM-Wack, but
  5495.         ; some garbage may be left on the stack.
  5496.  
  5497.         ; Entry point for "go" command.
  5498.  
  5499.         ; This starts running wherever the current address is pointing.
  5500.  
  5501. @40dPoint to data on system stack.
  5502. @40dMake PC the current address.
  5503.  
  5504.         ; Entry point for "^D" and "resume" commands.
  5505.  
  5506.         ; This continues running where it left off.
  5507.  
  5508. @d
  5509. @40dGet the saved status register.
  5510. @40dClear the trace mode flag and put
  5511.                                         it on the stack.
  5512. @40dRestore serial port interrupt status.
  5513. @40dPut the program counter on the stack.
  5514. @40dGet the saved user stack pointer,
  5515. @40dand restore it.
  5516. @40dPoint to the register dump.
  5517. @40dRestore all the other registers.
  5518. @40dPop the exception number.
  5519. @40dReturn from the exception.
  5520.  
  5521.  
  5522.         ; Subroutine to initialize ROM-Wack's data area.
  5523.  
  5524. @40dPoint to data area.
  5525. @d
  5526. @40dClear 236 bytes.
  5527. @d
  5528. @40dUse primary key bindings.
  5529. @40dFrame size = 16 bytes.
  5530. @40dUse "TRAP #15" for breakpoints.
  5531. @d
  5532.  
  5533. @8p@32wPadding.
  5534.  
  5535.         ; A lot of the functions in ROM-Wack have C compatible entry points
  5536.         ; (which get the parameters from the stack), and most of them have
  5537.         ; C compatible return values (in D0).  I guess this is to interface
  5538.         ; them to other functions, written in C, in the bigger versions of
  5539.         ; Wack.  Likewise, the following are probably C interface functions,
  5540.         ; but they (and most of the C entry points) aren't used anywhere.
  5541.  
  5542.  
  5543.         ; "Peek" function for C.  Takes address, returns 16-bit contents.
  5544.  
  5545. @a?fc2498
  5546. @d
  5547. @d
  5548. @d
  5549.  
  5550.         ; I have no idea why this is here twice.
  5551.  
  5552. @d
  5553. @d
  5554. @d
  5555.  
  5556.         ; "Poke" function for C.  Takes address and a word, and stores the
  5557.         ; word at the address given.
  5558.  
  5559. @d
  5560. @d
  5561. @d
  5562.  
  5563.  
  5564.         ; Entry point for "user" command.
  5565.  
  5566.         ; Takes all the data currently resident on the supervisor
  5567.         ; stack (exception stack frame, exception number, register dump,
  5568.         ; ROM-Wack data area, and any other stuff), and moves it onto the
  5569.         ; user stack.  Then puts the CPU into user mode.
  5570.  
  5571.         ; In effect, this switches ROM-Wack from running as part of the
  5572.         ; exec kernel (in supervisor mode) to running as a plain, ordinary
  5573.         ; task, along with other tasks.  The good side is that the system
  5574.         ; can now go and clean up (flush disk buffers, etc), while the
  5575.         ; user can go on playing with ROM-Wack.  The bad side is that the
  5576.         ; task which did Debug() or trapped into ROM-Wack is stuck there
  5577.         ; forever.  "go", and "resume" commands will no longer work.
  5578.  
  5579. @40dPoint to data area on stack.
  5580. @40dWas CPU in supervisor mode?
  5581. @40dIf not, exit.
  5582. @40dGet the user stack pointer.
  5583. @40dReserve 92 bytes on user stack.
  5584. @40dMake this the new data area.
  5585. @40dPoint to top of new data area.
  5586. @40dPoint to top of old data area.
  5587. @40dSave the supervisor stack pointer.
  5588. @d
  5589. @d
  5590. @40dCopy exception stack frame, register
  5591. @40ddump, data area, and any other stuff
  5592. @40dto the user stack.
  5593. @40dBump supervisor stack pointer up.
  5594. @40dBump user stack pointer down.
  5595. @d
  5596. @40dGet the saved status register.
  5597. @40dPrint a newline.
  5598. @d
  5599.  
  5600.  
  5601.         ; String compare function.  This checks if a command entered by
  5602.         ; the user, pointed to by A1, matches a command, pointed to by A0,
  5603.         ; from the command table.  It returns zero if so, else it returns
  5604.         ; the character number at which the mismatch occurred.
  5605.  
  5606.         ; C style entry point.
  5607.  
  5608. @d
  5609.  
  5610.         ; Assembler entry point.
  5611.  
  5612. @d
  5613. @40dGet a byte from reference string.
  5614. @40dEnd of string?
  5615. @40dCompare to byte from second string.
  5616. @40dLoop while strings are equal.
  5617. @40dCompute number of equal characters.
  5618. @40dExit.
  5619.  
  5620. @40dCheck if other string ends also.
  5621. @d
  5622. @40dReturn zero (strings match).
  5623. @d
  5624.  
  5625.  
  5626.         ; Entry point for <Return> command (Redisplay frame).
  5627.  
  5628. @40dRequest redisplay of current frame.
  5629. @d
  5630.  
  5631.  
  5632.         ; I don't know what this is for.  It's not referenced anywhere.
  5633.  
  5634. @d
  5635. @d
  5636. @d
  5637. @d
  5638.  
  5639.  
  5640.         ; Entry point for ">", <Space> commands (Move forward a word).
  5641.  
  5642. @40dIncrement current address by 1 word.
  5643. @40dRequest frame display.
  5644. @d
  5645. @d
  5646. @40dPrint a newline.
  5647. @d
  5648. @d
  5649. @d
  5650.  
  5651.  
  5652.         ; Entry point for "<", <Backspace> commands (Move back a word).
  5653.  
  5654. @40dDecrement current address by 1 word.
  5655. @40dRequest frame display.
  5656. @d
  5657. @d
  5658. @40dPrint a newline.
  5659. @d
  5660. @d
  5661. @d
  5662.  
  5663.  
  5664.         ; Entry point for "." command (move forward a frame).
  5665.  
  5666. @40dGet frame size.
  5667. @40dAdd to current address.
  5668. @40dRequest frame display.
  5669. @d
  5670.  
  5671.  
  5672.         ; Entry point for "," command (move back a frame).
  5673.  
  5674. @40dGet frame size.
  5675. @40dSubtract from current address.
  5676. @40dRequest frame display.
  5677. @d
  5678.  
  5679.  
  5680.         ; Entry point for "[" command.
  5681.  
  5682.         ; This follows a pointer at the current address.
  5683.  
  5684. @40dGet indirection stack pointer.
  5685. @40dGet current location.
  5686. @40dStore in indirection stack.
  5687. @40dPut indirection stack pointer back.
  5688. @40dMake the current location even.
  5689. @40dGet the pointer.
  5690. @40dPut it in the current location.
  5691. @40dRequest display of frame.
  5692. @d
  5693.  
  5694.  
  5695.         ; Entry point for "]" command.
  5696.  
  5697.         ; This walks undoes a "[" command, good for walking back along
  5698.         ; singly linked lists or backing out of nested structure pointers.
  5699.  
  5700. @40dGet indirection stack pointer.
  5701. @40dGet address from indirection stack.
  5702. @40dRequest frame display.
  5703. @40dUpdate the indirection stack pointer.
  5704. @d
  5705.  
  5706.  
  5707.         ; Entry point for "+" command.
  5708.  
  5709. @40dEcho "+" on the user's terminal.
  5710. @d
  5711. @40dRead a number from the keyboard.
  5712. @d
  5713. @40dIf none, print newline and exit.
  5714. @40dGet the number which was entered.
  5715. @40dAdd to current address.
  5716. @40dRequest frame redisplay.
  5717. @d
  5718.  
  5719.  
  5720.         ; Entry point for "-" command.
  5721.  
  5722. @40dEcho "-" on the user's terminal.
  5723. @d
  5724. @40dRead a number from the keyboard.
  5725. @d
  5726. @40dIf none, print newline and exit.
  5727. @40dGet the number which was entered.
  5728. @40dSubtract from the current address.
  5729. @40dRequest frame redisplay.
  5730. @d
  5731.  
  5732.  
  5733.         ; The following isn't referenced anywhere.  Perhaps an outdated
  5734.         ; bit of code to set the current address to the last number entered.
  5735.         ; This is now unnecessary.
  5736.  
  5737. @d
  5738. @d
  5739. @d
  5740.  
  5741.  
  5742.         ; Entry point for ":" command (set frame size).
  5743.  
  5744. @40dEcho ":" on the terminal.
  5745. @d
  5746. @40dGet a number from the terminal.
  5747. @40dSet the frame size.
  5748. @40dRequest frame redisplay.
  5749. @d
  5750.  
  5751.  
  5752.         ; Routine to print a prompt for memory-modify commands.
  5753.  
  5754. @40dGet the current address.
  5755. @40dPrint it (6 digits).
  5756. @40dIs the frame size zero?
  5757. @40dIf frame size is not zero, then
  5758. @d
  5759. @40d  Get word at current address.
  5760. @40d  Print it (4 digits).
  5761. @40d  Print "=".
  5762. @d
  5763. @40dElse
  5764. @40d  Print "xxxx ="
  5765. @40dEndif
  5766. @d
  5767.  
  5768.  
  5769.         ; Entry point for "=" command (modify one word of memory).
  5770.  
  5771.         ; This is also used by the "alter" routine below.  It returns 1
  5772.         ; if a value was entered, and 0 if not.
  5773.  
  5774. @40dPrint a prompt.
  5775. @40dGet a number from the terminal.
  5776. @40dDid we get one?
  5777. @d
  5778. @40dIf so, update the word pointed
  5779. @40dto by the current address with the
  5780. @40ddata which was entered, and return
  5781. @40da non-zero value.
  5782. @40dAre we in "alter" mode?
  5783. @d
  5784. @40dIf not, request frame redisplay.
  5785. @d
  5786.  
  5787. @8p@,8s
  5788.  
  5789.  
  5790.         ; Entry point for "alter" command.
  5791.  
  5792. @40dSet "alter mode" flag.
  5793. @40dPrint a newline.
  5794. @40dDo an "=" command.
  5795. @d
  5796. @40dIf a value was entered, increase the
  5797. @40dcurrent location by 2, and loop back.
  5798. @d
  5799.  
  5800. @40dClear "alter mode" flag.
  5801. @40dPrint a newline.
  5802. @d
  5803.  
  5804.  
  5805.         ; I don't know what this is for.  Perhaps a remnant from an old
  5806.         ; version of ROM-Wack, or something from a bigger version of Wack.
  5807.         ; It's not called from anywhere.
  5808.  
  5809. @a?fc2692
  5810. @40dPoint to the string below.
  5811. @40dPrint it.
  5812. @d
  5813.  
  5814. @8p@,22s
  5815.  
  5816.  
  5817.         ; Entry point for "list" command.
  5818.  
  5819.         ; This will traverse a standard exec list, displaying information
  5820.         ; about each node.  It should be called when the current address is
  5821.         ; either that of the list header, or of any node.
  5822.  
  5823. @d
  5824. @40dGet the current address.
  5825. @40dList header ("Tail" field zero)?
  5826. @d
  5827. @40dIf yes, go to first node.
  5828. @40dSee if now at end of list (or empty).
  5829. @40dIf no more nodes, exit.
  5830. @40dGet the node's name.
  5831. @40dIf name pointer is null, replace
  5832. @40dit with a pointer to a zero.
  5833. @40dSave name pointer on stack.
  5834. @d
  5835. @40dGet priority field.
  5836. @40dPut it on the stack.
  5837. @40dGet type field.
  5838. @40dPut it on the stack.
  5839. @40dPut node address to stack.
  5840. @40dPoint to data on stack.
  5841. @40dPoint to format string below.
  5842. @40dRawDoFmt() to serial port.
  5843. @40dPop data back off the stack.
  5844. @40dMove to next node.
  5845. @40dLoop until no more nodes.
  5846. @40dPrint a newline.
  5847. @d
  5848. @d
  5849.  
  5850. @a?fc26fc
  5851. @8p@,36s
  5852.  
  5853.  
  5854.         ; Subroutine to display a "frame" of data from memory.  On entry,
  5855.         ; the address of the frame is given in D0, and its size in D1.
  5856.  
  5857.         ; Data is displayed in lines of up to 8 words, and as an address,
  5858.         ; followed by hex words, followed by their ASCII character
  5859.         ; equivalents.
  5860.  
  5861. @d
  5862. @40dReserve 40 bytes of stack space.
  5863. @40dPrint a newline.
  5864. @d
  5865. @40dSet number of bytes remaining.
  5866. @40dJust exit if frame size is zero.
  5867.  
  5868.         ; Outer loop:  Display one line of the frame.
  5869.  
  5870. @a?fc2732
  5871. @d
  5872. @40dPrint the address.
  5873. @40dMaximum 8 words per line.
  5874. @40dPoint to reserved stack space.
  5875.  
  5876.         ; Inner loop:  Display one word of data.
  5877.  
  5878. @40dGet a word from memory.
  5879. @40dPrint it.
  5880. @d
  5881. @40dGet high 8 bits of current word.
  5882. @40dConvert to printable data.
  5883. @40dAdd to character string.
  5884. @d
  5885. @40dDo likewise for low 8 bits.
  5886. @d
  5887. @40dDecrement number of bytes remaining.
  5888. @40dExit if zero,
  5889. @40dotherwise continue until line full.
  5890.  
  5891.         ; End of line reached.
  5892.  
  5893. @40dMark end of character string.
  5894. @40dPoint to beginning.
  5895. @40dPrint the string and a newline.
  5896. @40dGo and do next line.
  5897.  
  5898.         ; End of frame reached.
  5899.  
  5900. @40dMark end of character string.
  5901. @40dPoint to beginning.
  5902. @40dPrint the string and a newline.
  5903. @d
  5904. @d
  5905. @d
  5906.  
  5907.  
  5908.         ; Subroutine to display an 8-digit hex number.
  5909.  
  5910. @d
  5911. @40d8 digits.
  5912. @d
  5913.  
  5914.  
  5915.         ; Subroutine to display a 6-digit hex number (address).
  5916.  
  5917. @d
  5918. @40d6 digits.
  5919. @d
  5920.  
  5921.  
  5922.         ; Subroutine to display a 4-digit hex number.
  5923.  
  5924. @d
  5925. @40d4 digits.
  5926. @40dGo print the number.
  5927. @d
  5928. @d
  5929.  
  5930.  
  5931.         ; Subroutine to print the "DR:", "AR:", and "SF:" portions of
  5932.         ; the ROM-Wack register frame.
  5933.  
  5934. @d
  5935. @d
  5936. @40d7 Data registers.
  5937. @40dPoint to "\nDR: " string.
  5938. @40dDisplay data registers.
  5939. @40d6 Address registers.
  5940. @40dPoint to "\nAR: " string.
  5941. @40dDisplay address registers.
  5942. @40dSkip exception number on stack.
  5943. @40dSupervisor mode?
  5944. @d
  5945. @40dIf not, get saved USP.
  5946. @d
  5947. @40dPoint to "\nSF: " string.
  5948. @40dPrint it.
  5949. @d
  5950. @40dDisplay 14 words of stack data.
  5951. @d
  5952. @d
  5953. @40dPrint a newline.
  5954. @d
  5955. @d
  5956.  
  5957.  
  5958.         ; Subroutine to print a string pointed to by A0, followed by (D2)
  5959.         ; longwords from memory pointed to by A2.
  5960.  
  5961. @40dPrint the string.
  5962. @d
  5963. @40dLoop and print all the data.
  5964. @d
  5965. @d
  5966.  
  5967.  
  5968.         ; Subroutine to print the first ("PC: ...") line of the register
  5969.         ; frame, followed by the rest of the register frame via the routine
  5970.         ; above.  Note, we just give RawDoFmt() a format string describing
  5971.         ; the data structure on the supervisor stack
  5972.  
  5973.         ; Also entry point for "regs" command.
  5974.  
  5975. @40dGet pointer to stack-resident data.
  5976. @d
  5977. @40dPoint to format string.
  5978. @40dFormat the data.
  5979. @d
  5980. @40dPoint to the register dump area.
  5981. @40dPrint it.
  5982.  
  5983.  
  5984.         ; Text strings used to display register frames.  The second one
  5985.         ; isn't used anywhere.
  5986.  
  5987. @a?fc27fc
  5988. @8p@,52s
  5989. @8p@,19s
  5990.  
  5991. @8p@,33s
  5992.  
  5993. @8p@,6s
  5994. @8p@,6s
  5995. @8p@,6s
  5996.  
  5997.  
  5998.         ; Memory fill routine.  Fills (D1) words, starting at (D0), with
  5999.         ; the value in D2.  Not used anywhere.
  6000.  
  6001. @d
  6002. @d
  6003. @d
  6004. @d
  6005. @d
  6006. @d
  6007. @d
  6008.  
  6009.  
  6010.         ; Subroutine to find a breakpoint in the breakpoint table, given
  6011.         ; its address.  If successful, returns address of breakpoint table
  6012.         ; entry, if not, returns zero.
  6013.  
  6014. @a?fc2886
  6015. @40dPrint a newline.
  6016. @40dPoint to breakpoint table.
  6017. @d
  6018. @40dScan breakpoint table for a
  6019. @40dbreakpoint address matching A1.
  6020. @d
  6021. @d
  6022. @40dNot found, so return zero.
  6023. @d
  6024. @40dReturn address of table entry.
  6025. @d
  6026.  
  6027.         ; Entry point for "clear" command.
  6028.  
  6029.         ; Deactivate the breakpoint at the current program address,
  6030.         ; if there is one.
  6031.  
  6032. @40dGet current address.
  6033. @40dSee if it is a breakpoint address.
  6034. @d
  6035. @40dIf so, deactivate it and write the
  6036. @40doriginal instruction back.
  6037. @d
  6038.  
  6039.  
  6040.         ; Entry point for "reset" command.
  6041.  
  6042.         ; Deactivates all breakpoints.
  6043.  
  6044. @40dPoint to ROM-Wack's breakpoint table.
  6045. @40dSize of breakpoint table - 1.
  6046. @40dGet breakpoint address.
  6047. @40dIf breakpoint in use then
  6048. @d
  6049. @40d  Clear breakpoint address.
  6050. @40d  Fix instruction at breakpoint.
  6051.                                         Endif
  6052. @40dGo to next table entry.
  6053. @40dLoop until whole table done.
  6054. @40dPrint a newline.
  6055. @d
  6056.  
  6057.  
  6058.         ; Entry point for "set" command.
  6059.  
  6060.         ; Activates a breakpoint at the current address.
  6061.  
  6062. @40dGet current address.
  6063. @40dSee if it is a breakpoint.
  6064. @40dIf so, do nothing.
  6065. @d
  6066. @40dScan the breakpoint table for an
  6067. @40dunused entry.
  6068. @d
  6069. @d
  6070. @d
  6071.  
  6072.         ; No unused breakpoint table entry found.
  6073.  
  6074. @40dPoint at "too many" string.
  6075. @40dPrint it.
  6076. @40dReturn.
  6077.  
  6078.         ; Unused entry in the breakpoint table found.  Activate a breakpoint.
  6079.  
  6080. @40dSave instruction at breakpoint.
  6081. @40dReplace with TRAP #15.
  6082. @40dSave the breakpoint address.
  6083. @d
  6084.  
  6085. @8p@,12s
  6086.  
  6087.  
  6088.         ; Entry point for "show" command.
  6089.  
  6090.         ; Lists all active breakpoints.
  6091.  
  6092. @40dPoint to breakpoint table.
  6093. @40dLoop for 16 entries.
  6094. @40dGet current breakpoint address.
  6095. @40dSkip if zero.
  6096. @40dPrint a newline.
  6097. @40dPrint the breakpoint address.
  6098. @40dGo to next table entry.
  6099. @40dLoop until done.
  6100. @40dPrint a newline.
  6101. @d
  6102.  
  6103. @40dGarbage.
  6104.  
  6105.  
  6106.         ; Subroutine to get a character and echo it to the user.
  6107.  
  6108. @40dGet a character.
  6109. @d
  6110. @40dEcho it back.
  6111. @d
  6112. @d
  6113.  
  6114.         ; Entry point for "!" command (Modify a register).
  6115.  
  6116. @d
  6117. @40dPrint "!".
  6118. @d
  6119. @40dGet a character.
  6120. @40dConvert to upper case.
  6121. @40dGet pointer to stack-resident data.
  6122. @40dPoint to data register dump area.
  6123. @40dMaximum data register # = 7.
  6124. @a?fc2952
  6125. FC2952  cmp.b     #'D',D0               [D]ata register?
  6126. @a=fc2956
  6127. @d
  6128. @40dPoint to address register dump.
  6129. @40dMaximum address register # = 6.
  6130. FC295E  cmp.b     #'A',D0               [A]ddress register?
  6131. @a=fc2962
  6132. @d
  6133. @40dPoint to user stack pointer.
  6134. FC2968  cmp.b     #'U',D0               [U]SP?
  6135. @a=fc296c
  6136. @40dIf so, go change it.
  6137. @40dOtherwise, exit.
  6138.  
  6139.         ; Enter here with A0 pointing to a dump area containing sequential
  6140.         ; images of the address or data registers, and D2 containing the
  6141.         ; maximum register number.
  6142.  
  6143. @40dGet a character.
  6144. @40dBackspace?
  6145. @40dIf so, exit.
  6146. @40dIs it a digit?
  6147. @40dIf not, exit.
  6148. @40dConvert to number.
  6149. @40dGreater than maximum?
  6150. @40dIf so, exit.
  6151. @40dCompute offset to given register.
  6152. @40dCompute address of register.
  6153.  
  6154.         ; Enter here with A2 pointing to a longword containing the image
  6155.         ; of the register to modify.
  6156.  
  6157. @40dGet the current value.
  6158. @40dPrint a space.
  6159. @40dDisplay value as 8 hex digits.
  6160. @40dPrint "="
  6161. @d
  6162. @40dGet the new value from the user.
  6163. @40dWas a value entered?
  6164. @40dIf not, exit.
  6165. @40dUpdate the register.
  6166. @40dPrint a newline.
  6167. @d
  6168. @d
  6169.  
  6170.  
  6171.         ; Entry point for "^" and "limit" commands.
  6172.  
  6173.         ; This copies the current address to the "limit" address, i.e. the
  6174.         ; address to stop searching or filling memory at.
  6175.  
  6176. @40dCopy current address to limit.
  6177. @40dRequest frame redisplay.
  6178. @d
  6179.  
  6180.  
  6181.         ; Entry point for "find" command.
  6182.  
  6183. @d
  6184. @40dGet the search pattern.
  6185. @40dExit if none entered.
  6186. @40dDo the searching.
  6187. @40dExit if not found.
  6188. @40dRound result address down to even.
  6189. @40dStore it in current address.
  6190. @40dRequest frame redisplay.
  6191. @d
  6192. @d
  6193.  
  6194.         ; Search routine for the "find" command.
  6195.  
  6196. @d
  6197. @40dStart searching at start address - 2.
  6198.  
  6199. @40dSet the number of bytes to match.
  6200. @40dSet the search pattern address.
  6201. @40dGo to next address.
  6202. @d
  6203. @40dSee if limit address reached.
  6204. @40dIf so, return false.
  6205. @40dCompare one byte.
  6206. @40dGo to next address if mismatch.
  6207. @40dDecrement byte counter.
  6208. @40dLoop until all matched.
  6209. @40dFound: return the address where.
  6210. @d
  6211. @40dReturn false.
  6212. @d
  6213. @d
  6214.  
  6215.         ; Search/fill pattern input routine.  Prompts for a pattern,
  6216.         ; accepts it, and returns the following:
  6217.  
  6218.         ;   D0: Number of bytes in search pattern.
  6219.         ;   D1: True if pattern entered, false if aborted.
  6220.         ;   A0: Lower bound for search.
  6221.         ;   A2: Upper bound for search.
  6222.         ;   A3: Address of search pattern.
  6223.  
  6224. @40dPoint to "pattern? " string.
  6225. @40dPrint it.
  6226. @40dGet a number from the terminal.
  6227. @40dDid we get one?
  6228. @40dIf not, return false.
  6229. @d
  6230. @40dCompute 4-(d+1)/2, where d is the
  6231. @40dnumber of digits entered.
  6232. @d
  6233. @40dGet the number entered.
  6234. @40dGet the current address,
  6235. @40dand the limit address.
  6236. @40dReturn true.
  6237. @d
  6238.  
  6239. @a?fc2a2c
  6240. @8p@,12s
  6241.  
  6242.  
  6243.         ; Entry point for "fill" command.
  6244.  
  6245. @d
  6246. @40dGet the fill pattern.
  6247. @d
  6248. @40dIf one entered, go do the fill.
  6249. @40dRequest frame redisplay.
  6250. @d
  6251. @d
  6252.  
  6253.         ; Fill routine for the "fill" command.
  6254.  
  6255. @40dAdjust number of bytes for "dbra".
  6256. @40dInitialize loop counter.
  6257. @40dInitialize pattern address.
  6258. @40dUpper limit reached?
  6259. @40dExit if so.
  6260. @40dCopy one byte from the fill pattern.
  6261. @40dLoop until pattern done.
  6262. @40dLoop back and do pattern again.
  6263. @d
  6264.  
  6265.  
  6266.         ; Subroutine to print a single space.
  6267.  
  6268. @d
  6269. @40dCharacter code for a space.
  6270. @40dRawPutChar()
  6271. @d
  6272. @d
  6273.  
  6274.  
  6275.         ; Subroutine to print a single newline.
  6276.  
  6277. @d
  6278. @40dPoint to string below.
  6279. @40dPrint it.
  6280. @d
  6281. @d
  6282.  
  6283. @8p@,2s
  6284.  
  6285.  
  6286.         ; Subroutine to print string at address pointed to by A0, followed
  6287.         ; by a newline.
  6288.  
  6289. @d
  6290. @40dPrint the string.
  6291. @40dPrint a newline.
  6292. @d
  6293. @d
  6294.  
  6295.  
  6296.         ; I don't know what this is for.  It's not referenced anywhere.
  6297.  
  6298. @d
  6299. @d
  6300.  
  6301.  
  6302.         ; Subroutine to get a character.  Returns with the zero flag clear
  6303.         ; if a character was received, set otherwise.
  6304.  
  6305. @d
  6306. @d
  6307. @d
  6308. @d
  6309. @d
  6310.  
  6311.  
  6312.         ; Isdigit() type of function.  Enter with a character in D0, returns
  6313.         ; with the zero flag set if the character is a numeric digit.
  6314.  
  6315. @a?fc2aac
  6316. FC2AAC  cmp.b     #'0',D0
  6317. @a=fc2ab0
  6318. @d
  6319. FC2AB2  cmp.b     #'9',D0
  6320. @a=fc2ab6
  6321. @d
  6322. @d
  6323. @d
  6324.  
  6325.  
  6326.         ; Subroutine to convert an 8-bit code in D0 to a 2 character
  6327.         ; printable ASCII version.
  6328.  
  6329.         ; Codes 0 and 128-255 return "..", control codes are shown as "^A"
  6330.         ; to "^\", other characters are shown as a space, then the actual
  6331.         ; character.
  6332.  
  6333. @d
  6334. @40dMove ".." into D2.
  6335. @40dIs the code zero?
  6336. @40dIf so, return ".." and exit.
  6337. @40dIs the high bit set?
  6338. @40dIf so, return ".." and exit.
  6339. @40dMove space and null into D2.
  6340. @d
  6341. @40dIf the character is a control code,
  6342. @d
  6343. @40d  Move "^" and null into D2.
  6344. @a?fc2adc
  6345. FC2ADC  or.b      #$40,D0                 Convert to printable character.
  6346. @a=fc2ae0
  6347. @40d  Put it into D2.
  6348.                                         Endif
  6349. @40dReturn D2.
  6350. @d
  6351. @d
  6352.  
  6353.  
  6354.         ; ROM-Wack command execution function.  Calls the command function
  6355.         ; given in A0, and on return, displays the current "frame" if
  6356.         ; requested by the command function.
  6357.  
  6358. @d
  6359. @40dGet the command function address.
  6360. @40dExecute the function.
  6361. @40dNeed to display frame?
  6362. @40dExit if not.
  6363. @40dGet current address.
  6364. @40dGet frame size.
  6365. @40dDisplay the frame.
  6366. @d
  6367.  
  6368.  
  6369.         ; Entry point for "?" command (Display multi-character commands).
  6370.  
  6371. @d
  6372. @40dPoint to ROM-Wack command table.
  6373. @40dGet a character.
  6374. @d
  6375. @40dIf not zero, print it, and loop
  6376. @40dback to do the next one.
  6377. @40dPrint a space.
  6378. @40dAnother zero?
  6379. @40dIf not, loop back & print next cmd.
  6380. @40dPrint a newline.
  6381. @d
  6382. @d
  6383.  
  6384.  
  6385.         ; ROM-Wack command dispatch table scanner.
  6386.  
  6387.         ; Enter with a character code in D0.  This routine runs through the
  6388.         ; command table, and returns either the address of the command table
  6389.         ; entry matching the character, or zero.
  6390.  
  6391.         ; Each command table entry either corresponds to exactly one
  6392.         ; character, or to a range of characters.  This may sound confusing,
  6393.         ; but I've commented the command table itself, so you can just look
  6394.         ; there and it will be perfectly obvious.
  6395.  
  6396. @d
  6397. @40dPoint to command table.
  6398. @d
  6399. @40dGet link to next table entry.
  6400. @40dStrip off high 8 bits.
  6401. @40dExit if no next entry.
  6402. @40dPoint ot next entry.
  6403. @40dSee if command matches table entry.
  6404. @40dExit if it does.
  6405. @40dGo to next entry if smaller.
  6406. @40dCheck if in range.
  6407. @40dGo to next entry if not.
  6408. @40dReturn table entry address.
  6409. @d
  6410.  
  6411.  
  6412.         ; ROM-Wack command dispatcher.  Given a command character, looks it
  6413.         ; up in the command dispatch table and executes the command if found.
  6414.  
  6415.         ; C style entry point.
  6416.  
  6417. @d
  6418.  
  6419.         ; Assembler entry point.
  6420.  
  6421. @40dLook command up in command table.
  6422. @40dFound it?
  6423. @40dExit if not.
  6424. @d
  6425. @40dGet execution address from table
  6426.                                         and store it on the stack.
  6427. @40dExecute the function.
  6428. @40dPop address back off the table.
  6429. @d
  6430.  
  6431.  
  6432.         ; Multi-character command lookup function.
  6433.  
  6434.         ; This takes a pointer to a command string in A0, and looks it up
  6435.         ; in the table of multi-character commands.  It returns the address
  6436.         ; of the table entry corresponding to the command, or zero if the
  6437.         ; command was not found.
  6438.  
  6439.         ; C style entry point.
  6440.  
  6441. @d
  6442.  
  6443.         ; Assembler entry point.
  6444.  
  6445. @d
  6446. @d
  6447. @40dPoint at command dispatch table.
  6448. @d
  6449. @40dGet pointer to next table entry.
  6450. @40dExit if null (end of table).
  6451. @d
  6452. @40dGet pointer to string.
  6453. @40dPoint to string to match.
  6454. @40dCompare them.
  6455. @40dGot a match?
  6456. @40dKeep looking if not.
  6457. @40dReturn table address.
  6458. @d
  6459. @d
  6460.  
  6461.  
  6462.         ; ROM-Wack main loop:  Gets a character from the user, then
  6463.         ; interprets it, then gets next characer, etc.
  6464.  
  6465. @40dGet a character from the user.
  6466. @40dStore it.
  6467. @40dProcess it.
  6468. @40dGo get next character.
  6469.  
  6470.  
  6471.         ; Entry point for letters, numbers and underline characters typed
  6472.         ; at the ROM-Wack command level.  This function collects them in
  6473.         ; a buffer.
  6474.  
  6475. @40dAddress of secondary key bindings.
  6476. @40dAlready using them?
  6477. @d
  6478.  
  6479.         ; This is the first character of a multi character command, so
  6480.         ; clear the buffer and point to the other set of key bindings.
  6481.  
  6482. @40dZero characters in buffer so far.
  6483. @40dSave address of primary key bindings.
  6484. @40dPoint at secondary key bindings.
  6485.  
  6486. @a?fc2bbe
  6487. FC2BBE  cmp.b     #' ',$82(A6)          Was the key a space?
  6488. @a=fc2bc4
  6489. @40dIf so, ignore it (kludge, see below).
  6490. @40dGet number of chars in buffer
  6491. @40d50 characters already?
  6492. @40dIf equal or more, ignore this one.
  6493. @40dGet command character.
  6494. @40dEcho it to the user.
  6495. @40dPoint to buffer.
  6496. @40dGet offset into buffer.
  6497. @40dStore character in buffer.
  6498. @40dIncrement buffer count.
  6499. @40dThere is unprocessed data in the
  6500. @40dbuffer, so set the flag.
  6501.  
  6502.  
  6503.         ; Entry point to get a number from the user.
  6504.  
  6505. @a?fc2bf0
  6506. FC2BF0  move.b    #' ',$82(A6)           Start using secondary key bindings.
  6507. @a=fc2bf6
  6508. @d
  6509. @40d Indicate that input is being
  6510.                                          gathered for a specific function.
  6511.  
  6512.         ; Loop to read the digits.  We stay in this loop, using the
  6513.         ; secondary (input gathering) key bindings until some command
  6514.         ; function switches us back to the primary ones.  That means
  6515.         ; the user either canceled the line, or pressed RETURN.
  6516.  
  6517. @40d Using secondary key bindings now?
  6518. @40d Exit loop if not.
  6519. @40d Get a key from the user.
  6520. @40d Store it in "last key typed".
  6521. @40d Dispatch it as a command character.
  6522. @40d Loop.
  6523.  
  6524.         ; The input line has been processed.  Either it was a command
  6525.         ; (and was executed), or it was a number, or it was an error.
  6526.  
  6527. @40d Clear "parameter input" flag.
  6528. @d
  6529. @40d Get number of digits.
  6530. @40d If no useful data in buffer (line
  6531. @40d canceled, command already executed,
  6532. @40d bad symbol...), return zero digits.
  6533. @d
  6534.  
  6535.  
  6536.         ; Entry point for <Space> while using the secondary key bindings.
  6537.  
  6538. @d
  6539.  
  6540.  
  6541.         ; Entry point for CTRL-U and CTRL-X.  Point back to the original
  6542.         ; set of key bindings, and set the buffer to empty.
  6543.  
  6544. @40d-1 characters in buffer.
  6545. @40dRestore top-level key bindings.
  6546. @40dPrint a linefeed.
  6547. @40dBuffer contains no useful data.
  6548. @d
  6549.  
  6550.  
  6551.         ; Entry point for <Backspace>.  This deletes one charaacter from
  6552.         ; the input buffer.
  6553.  
  6554. @40dAny characters in the buffer?
  6555. @40dIf none, cancel input.
  6556. @40dPoint to buffer.
  6557. @40dGet buffer offset.
  6558. @40dClear last character in buffer.
  6559. @40dDecrement buffer count.
  6560. @40dPoint to string below.
  6561. @40dPrint it.
  6562. @40dIs buffer now empty?
  6563. @40dIf so, cancel input.
  6564. @d
  6565.  
  6566.         ; String used to erase one character from the user's terminal.
  6567.  
  6568. @8p@,4s
  6569.  
  6570.  
  6571.         ; Entry point for <Return>.
  6572.  
  6573. @40dRestore previous key bindings.
  6574. @40dPoint to input buffer.
  6575. @40dGet number of characters in it.
  6576. @d
  6577. @40dIndicate that no data is in the
  6578.                                         buffer waiting for processing.
  6579. @d
  6580. @d
  6581.  
  6582.         ; There was data in the buffer, now interpret it.
  6583.  
  6584. @40dZero-terminate the buffer.
  6585. @40dPoint to it.
  6586. @40dLook command up in table.
  6587. @40dBranch if not found.
  6588. @d
  6589. @40dIndicate that buffer was processed.
  6590. @40dGet the command table offset.
  6591. @40dGet execution address from table.
  6592. @40dExecute the command.
  6593. @40dClear frame redisplay flag.
  6594. @40dPop execution address of stack.
  6595. @d
  6596.  
  6597.         ; Continue here if the buffer contained a string not found
  6598.         ; in the command table.  For a full Wack, this means it would
  6599.         ; either be a number, or a symbol.  For ROM-Wack, it's either
  6600.         ; a number or an error.
  6601.  
  6602. @40dPoint to the string in the buffer.
  6603. @40dPoint to input number location.
  6604. @40dInterpret input buffer as a number.
  6605. @40dStore number of digits.
  6606. @d
  6607. @40dIf 0 digits (bad hex number), print
  6608. @40d"unknown symbol", indicate that no
  6609. @40ddata is waiting in the buffer, and
  6610. @40dexit.
  6611.  
  6612.         ; Continue here if number of digits was non-zero.  If the number
  6613.         ; wasn't being gathered as a parameter to another command, make it
  6614.         ; the current location.
  6615.  
  6616. @40dParameter being gathered?
  6617. @40dExit if so.
  6618. @40dRound number down to even.
  6619. @d
  6620. @40dSet the current location to it.
  6621. @40dRequest (re)display of frame.
  6622. @d
  6623.  
  6624. @8p@,18s
  6625.  
  6626.  
  6627.         ; Hex number interpreting routine.
  6628.  
  6629. @d
  6630. @40dStart result at zero.
  6631. @40dStart with "-1 digits".
  6632. @d
  6633. @40dJump into the loop.
  6634. @40dEntry point for hex digits:  Add 10.
  6635. @d
  6636. @40dShift previous number left by 4 bits.
  6637. @40dAdd in new digit.
  6638. @40dIncrement digit counter.
  6639. @40dGet a digit from the input string.
  6640. @40dExit if end of string reached.
  6641. @a?fc2d14
  6642. FC2D14  sub.b     #'0',D0               Subtract '0'.
  6643. @a=fc2d18
  6644. @40dExit if result less than zero.
  6645. @40dGreater than 9?
  6646. @40dBranch if not.
  6647. @40dSubtract 17.
  6648. @40dExit if result less than zero.
  6649. @40dBranch if less than 7.
  6650. @d
  6651. @a?fc2d2c
  6652. FC2D2C  sub.b     #$20,D0               Subtract ('a' - 'A').
  6653. @a=fc2d30
  6654. @40dBranch if less than zero.
  6655. @d
  6656. @40dBranch if less than 7.
  6657.  
  6658.         ; If we branch here, the number entered contained an invalid
  6659.         ; hexadecimal digit.
  6660.  
  6661. @40dReturn "0 digits".
  6662.  
  6663.         ; Branch here if end of string reached with no invalid digits.
  6664.  
  6665. @40dStore result where indicated.
  6666. @40dReturn number of digits.
  6667. @d
  6668. @d
  6669.  
  6670.  
  6671.         ; Some sort of format string.  Not used anywhere.
  6672.  
  6673. @a?fc2d42
  6674. @8p@,6s
  6675.  
  6676.  
  6677.         ; Toupper() type of function.  Converts character in D0 to upper
  6678.         ; case if necessary.
  6679.  
  6680. @a?fc2d48
  6681. FC2D48  cmp.b     #'a',D0               Less than 'a'?
  6682. @a=fc2d4c
  6683. @d
  6684. @a?fc2d4e
  6685. FC2D4E  cmp.b     #'z',D0               Greater than 'z'?
  6686. @a=fc2d52
  6687. @d
  6688. FC2D54  sub.b     #$20,D0               If neither, convert to upper case.
  6689. @a=fc2d58
  6690. @d
  6691.  
  6692. @8p@32wPadding.
  6693.  
  6694. ---------------------------------------------------------------------------
  6695.   result = Procure( semaphore, bidMessage )
  6696.   D0                A0         A1
  6697. ---------------------------------------------------------------------------
  6698.  
  6699.         ; A Procure/Vacate semaphore is a message port structure plus a
  6700.         ; counter.  A task can "lock" the semaphore, by calling Procure().
  6701.         ; Further attempts to lock the semaphore won't succeed until the
  6702.         ; original locker unlocks the semaphore by Vacate().
  6703.  
  6704.         ; A sm_Bids value of -1 indicates that the semaphore is free, zero
  6705.         ; indicates it's locked and no one is waiting, 1 means one task is
  6706.         ; waiting, etc.
  6707.  
  6708.         ; Whenever Procure() is called, a pointer to a message must be
  6709.         ; given.  This message is enqueued on the semaphore's port if the
  6710.         ; semaphore is not currently available, and returned when the
  6711.         ; caller's turn comes up to get the lock.  If the semaphore was
  6712.         ; available (sm_Bids = -1), the message is not used.
  6713.  
  6714. @40dIncrement the sm_Bids field.
  6715. @40dCheck if the semaphore was free.
  6716. @40dIf it was, store pointer to the
  6717.                                         current locker's message
  6718. @40dand return TRUE.
  6719. @d
  6720. @40dIf it wasn't, enqueue the message
  6721. @40don the semaphore's port and return
  6722. @40dFALSE.
  6723.  
  6724.  
  6725. ---------------------------------------------------------------------------
  6726.   Vacate( semaphore )
  6727.           A0
  6728. ---------------------------------------------------------------------------
  6729.  
  6730.         ; A task which has successfully obtained a semaphore via Procure()
  6731.         ; calls this to release it again.  The sm_Bids field is decremented.
  6732.         ; If it was zero and ends up at -1, nobody else was waiting to use
  6733.         ; the semaphore.  If it ends up positive, someone else is waiting
  6734.         ; and we must send his bid message back to let him know he has it
  6735.         ; now.  The first message enqueued on the semaphore's port is the
  6736.         ; task which has waited longest and gets it.
  6737.  
  6738. @40dClear pointer to locker's message.
  6739. @40dDecrement sm_Bids field.
  6740. @40dReturn if it is now -1.
  6741. @d
  6742. @40dSave semaphore pointer.
  6743. @40dDequeue the oldest bid message.
  6744. @40dRestore semaphore pointer.
  6745. @40dStore pointer to the message.
  6746. @40dExit if no message (error).
  6747. @d
  6748. @40dReplyMsg() to inform the waiting
  6749. @40dtask, then exit.
  6750.  
  6751.  
  6752. ---------------------------------------------------------------------------
  6753.   InitSemaphore( signalSemaphore )
  6754.                  A0
  6755. ---------------------------------------------------------------------------
  6756.  
  6757. @40dPoint to the waiting task list.
  6758. @40dInitialize it to empty.
  6759. @d
  6760. @d
  6761. @d
  6762. @40dClear the ss_Owner field to null.
  6763. @40dClear the ss_NestCount to zero.
  6764. @40dSet the ss_QueueCount to -1.
  6765. @d
  6766.  
  6767.  
  6768. ---------------------------------------------------------------------------
  6769.   ObtainSemaphore( signalSemaphore )
  6770.                    A0
  6771. ---------------------------------------------------------------------------
  6772.  
  6773. @40dForbid()
  6774. @40dIncrement the ss_QueueCount.
  6775. @d
  6776.  
  6777.         ; If the ss_Queuecount is now 0, then the semaphore was free and
  6778.         ; we got it.  Set the pointer to the owning task, set the nesting
  6779.         ; level to 1, and exit.
  6780.  
  6781. @40dStore pointer to owning task.
  6782. @d
  6783.  
  6784.         ; The ss_Queuecount was not -1, so the semaphore was already owned
  6785.         ; by someone.  Check if it is the calling task.
  6786.  
  6787. @d
  6788. @40dGet current task pointer.
  6789. @40dDo we own the semaphore already?
  6790. @40dIf so, increment nest count and exit.
  6791.  
  6792.         ; Another task owns the semaphore at the moment, so we must block.
  6793.         ; Since all non-running tasks must be on the TaskWait queue, we
  6794.         ; can't just enqueue the task on the semaphore.  Instead, we build
  6795.         ; a temporary node on the stack, and enqueue that.  Then we clear
  6796.         ; signal #2, and wait for someone to set it, which will occur when
  6797.         ; the current owner of the semaphore releases it.  When we wake up,
  6798.         ; we deallocate the temporary node, and return to the user.
  6799.  
  6800. @40dReserve 12 bytes of stack space.
  6801. @40dStore pointer to this task.
  6802. @40dClear signal #2.
  6803. @40dPoint to waiting task list.
  6804. @d
  6805. @40dEnqueue the temporary list node.
  6806. @d
  6807. @40dWait for signal #2.
  6808. @40dRelease the reserved stack space.
  6809. @d
  6810.  
  6811. @40dIncrement the nesting count.
  6812. @40dPermit()
  6813. @d
  6814.  
  6815.  
  6816. ---------------------------------------------------------------------------
  6817.   ReleaseSemaphore( signalSemaphore )
  6818.                     A0
  6819. ---------------------------------------------------------------------------
  6820.  
  6821. @40dDecrement the nesting count.
  6822. @40dIf zero, release the semaphore.
  6823. @40dIf it went negative, guru city!
  6824. @40dOtherwise, just decrement the
  6825. @40dss_QueueCount and exit.
  6826.  
  6827.         ; Continue here when the nesting count went to zero, and we
  6828.         ; therefore don't want the semaphore any more.
  6829.  
  6830. @40dForbid()
  6831. @40dDecrement the ss_QueueCount.
  6832. @40dIf now -1, nobody was waiting.
  6833.  
  6834.         ; The ss_Queuecount is still positive, so someone is blocked on
  6835.         ; the semaphore and waiting to be awakened.  The first (oldest)
  6836.         ; entry on the semaphore's queue gets it.
  6837.  
  6838. @d
  6839. @40dSave semaphore pointer.
  6840. @40dPoint to semaphore's queue.
  6841. @40dRemHead()
  6842. @40dIf the queue was empty, guru city!
  6843. @d
  6844.  
  6845.         ; We have a pointer (in D0) to a node which identifies the
  6846.         ; waiting process (the temporary one allocated on that process's
  6847.         ; stack).
  6848.  
  6849. @d
  6850. @d
  6851. @40dGet pointer to waiting task.
  6852. @40dMake this task the ss_Owner.
  6853. @d
  6854. @40dSet waiting task's signal #2.
  6855. @d
  6856. @40dExit.
  6857.  
  6858.         ; Continue here if nobody was waiting for the semaphore.  In this
  6859.         ; case just clear the semaphore's owner field.
  6860.  
  6861. @40dClear ss_Owner to null.
  6862. @40dPermit()
  6863. @d
  6864.  
  6865.         ; Put up an alert if the semaphore's nest count went negative
  6866.         ; (should never happen, we give away the semaphore when it reaches
  6867.         ; zero), or if the semaphore's queue was empty even though the
  6868.         ; ss_QueueCount said it isn't.
  6869.  
  6870. @d
  6871. @40dAlert number (fatal).
  6872. @40dGet ExecBase.
  6873. @40dPut up the alert.
  6874. @40dNever executed.
  6875. @d
  6876.  
  6877.  
  6878. ---------------------------------------------------------------------------
  6879.   success = AttemptSemaphore( signalSemaphore )
  6880.   D0                          A0
  6881. ---------------------------------------------------------------------------
  6882.  
  6883. @40dGet pointer to current task.
  6884. @40dForbid()
  6885. @40dIncrement the ss_QueueCount.
  6886. @40dBranch if now zero.
  6887. @40dDo we own the semaphore already?
  6888. @40dBranch if true.
  6889. @40dDecrement the ss_QueueCount again.
  6890. @40dPermit()
  6891. @40dReturn FALSE.
  6892. @d
  6893.  
  6894.         ; Continue here if we were able to get the semaphore.
  6895.  
  6896. @40dInstall pointer to owning task.
  6897. @40dIncrement nest count.
  6898. @40dPermit()
  6899. @40dReturn TRUE.
  6900. @d
  6901.  
  6902.  
  6903. ---------------------------------------------------------------------------
  6904.   ObtainSemaphoreList( list )
  6905.                        A0
  6906. ---------------------------------------------------------------------------
  6907.  
  6908.         ; This function is given a linked list of semaphore structures, and
  6909.         ; obtains them all.  This is done in two passes.  On the first pass,
  6910.         ; a SemaphoreRequest is enqueued on all semaphores which aren't free,
  6911.         ; and all the free ones are grabbed.
  6912.  
  6913.         ; On the second pass, the list is traversed again.  This time, if
  6914.         ; we already have a semaphore, we just pass it, otherwise, we wait
  6915.         ; for it.
  6916.  
  6917.         ; Note:  Whereas ObtainSemaphore() builds its SemaphoreRequest node
  6918.         ; on the task's stack, this one uses the single copy inside the
  6919.         ; semaphore structure.  This means that a crash is sure to result
  6920.         ; if more than one task tries to ObtainSemaphoreList and several
  6921.         ; end up waiting for the same semaphore.  The documentation has
  6922.         ; a bit more to say about this.
  6923.  
  6924. @d
  6925. @40dClear the "need to wait" flag.
  6926. @40dGet pointer to current task.
  6927. @40dForbid()
  6928. @d
  6929. @40dPoint to first semaphore in list.
  6930. @d
  6931. @40dEnd of list reached?
  6932. @40dExit loop if so.
  6933. @40dIncrement current semaphore's count.
  6934. @40dBranch if now zero.
  6935. @40dCheck if the semaphore is ours.
  6936. @40dBranch if true.
  6937. @40dUse the ss_MultipleLink structure
  6938. @40dto enqueue our semaphore request on
  6939. @40dthe semaphore's wait queue.
  6940. @d
  6941. @40dIndicate that we need to wait.
  6942. @40dGo to next semaphore in list.
  6943.  
  6944.         ; We got a semaphore.
  6945.  
  6946. @40dMake us the owner of this semaphore.
  6947. @40dIncrement its nest count.
  6948. @40dTry next semaphore in the list.
  6949.  
  6950.         ; The end of the list was reached.
  6951.  
  6952. @40dDid we get all the semaphores?
  6953. @40dIf so, exit.
  6954.  
  6955.         ; We have to wait for at least one semaphore in the list.
  6956.  
  6957. @40dGo to the start of the list.
  6958. @d
  6959. @40dEnd of list reached?
  6960. @40dIf so, exit.
  6961. @40dDo we own this semaphore?
  6962. @d
  6963. @40dIf we do, and its nest count is not
  6964. @40dzero, go on to the next one.
  6965. @40dIncrement the nest count.
  6966. @40dGo on to the next one.
  6967.  
  6968.         ; Wait for a semaphore.
  6969.  
  6970. @d
  6971. @40dWait for signal #2.
  6972. @40dGo back and check if we have it now.
  6973. @40dPermit()
  6974. @d
  6975. @d
  6976.  
  6977.  
  6978. ---------------------------------------------------------------------------
  6979.   ReleaseSemaphoreList( list )
  6980.                         A0
  6981. ---------------------------------------------------------------------------
  6982.  
  6983. @d
  6984. @40dGo to the start of the list.
  6985. @40dGo to first/next node.
  6986. @40dEnd of list reached?
  6987. @40dIf so, exit.
  6988. @40dReleaseSemaphore()
  6989. @40dLoop until all done.
  6990. @d
  6991. @d
  6992.  
  6993.  
  6994. ---------------------------------------------------------------------------
  6995.   AddSemaphore( signalSemaphore )
  6996.                 A1
  6997. ---------------------------------------------------------------------------
  6998.  
  6999. @40dInitSemaphore()
  7000. @40dPoint to global semaphore list.
  7001. @40dAdd the semaphore to the list.
  7002.  
  7003.  
  7004. ---------------------------------------------------------------------------
  7005.   RemSemaphore( signalSemaphore )
  7006.                 A1
  7007. ---------------------------------------------------------------------------
  7008.  
  7009. @40dUnlink semaphore from whatever
  7010.                                         list it's in.
  7011.  
  7012. ---------------------------------------------------------------------------
  7013.   signalSemaphore = FindSemaphore( name )
  7014.   D0                               A1
  7015. ---------------------------------------------------------------------------
  7016.  
  7017. @40dPoint to global semaphore list.
  7018. @40dFindName()
  7019. @d
  7020.  
  7021.  
  7022. @8p@32wPadding.
  7023.  
  7024.  
  7025. ---------------------------------------------------------------------------
  7026.   CopyMemQuick( source, dest, size )
  7027.                 A0      A1    D0
  7028. ---------------------------------------------------------------------------
  7029.  
  7030.         ; The caller guarantees that the source and destination are even,
  7031.         ; and that the transfer count is a multiple of 4.  This allows us
  7032.         ; to skip some of the strategy below.
  7033.  
  7034. @40d0 bytes left over after longword copy.
  7035. @40dGo copy (at least) as longwords.
  7036.  
  7037.  
  7038. ---------------------------------------------------------------------------
  7039.   CopyMem( source, dest, size )
  7040.            A0      A1    D0
  7041. ---------------------------------------------------------------------------
  7042.  
  7043.         ; This is an interesting tutorial on efficient 68000 memory moving.
  7044.  
  7045.         ; Note that this is not necessarily the best way to move memory on
  7046.         ; a 68010 or 68020, since both of these processors have expanded
  7047.         ; features designed to make memory moving more efficient, and all
  7048.         ; the computational overhead of choosing the right copying method
  7049.         ; might not be worth it.
  7050.  
  7051. @40dLess than 12 bytes to copy?
  7052. @d
  7053. @40dIf so, just copy byte by byte.
  7054.  
  7055.         ; The following bit of code handles odd/even source and destination
  7056.         ; addresses.  The following is done:
  7057.  
  7058.         ; Source and destination even:  Just continue.
  7059.         ; Source and destination odd:   Copy 1 byte.  Both addresses are now
  7060.         ;                               even, so we can continue.
  7061.         ; Source even, dest. odd:       Copy byte by byte.
  7062.         ; Source odd, destination even: Copy one byte, then copy the rest
  7063.         ;                               byte by byte.
  7064.  
  7065.         ; Note that there is nothing we can do if the source and destination
  7066.         ; differ by an odd number, i.e. are "out of phase".  In such a case,
  7067.         ; we must copy byte by byte.
  7068.  
  7069. @d
  7070. @40dIs the source address odd?
  7071. @40dBranch past the following if not.
  7072. @40dCopy one byte.
  7073. @40dDecrement transfer count.
  7074. @d
  7075. @40dIs the destination address odd?
  7076. @40dIf so, transfer byte by byte.
  7077.  
  7078.         ; Both the source and destination addresses are (now) even.
  7079.         ; The worst that can happen now is that we have to move the data
  7080.         ; as individual longwords.  First, compute how many bytes will
  7081.         ; be left over after we move the data as longwords, and save this
  7082.         ; value.
  7083.  
  7084. @40dFind how many bytes will be left
  7085. @40dif data is copied as longwords.
  7086. @40dSave this number.
  7087.  
  7088.         ; The "move multiple" approach below copies 48 bytes of data with
  7089.         ; only two instructions.  But to use it, 48 bytes of registers need
  7090.         ; to be saved and restored, and so it's not worth it unless we have
  7091.         ; at least two 48 byte "batches" to copy.
  7092.  
  7093. @d
  7094. @40d96 or more bytes to move?
  7095. @40dIf not, copy as longwords.
  7096. @40dSave 12 registers on the stack.
  7097. @40dGet 48 bytes with one instruction.
  7098. @40dMove them to the destination.
  7099. @d
  7100. @40dAdd 48 to destination address.
  7101. @40dSubtract 48 from transfer count.
  7102. @40dCopy another batch if 48 or more
  7103. @40dbytes remain to be copied.
  7104. @40dRestore the 12 registers.
  7105.  
  7106.         ; Whatever the case, D0 now contains the number of bytes left over.
  7107.         ; Copy as many of these as possible as longwords.
  7108.  
  7109. @40dSee how many longwords to copy.
  7110. @40dBranch if none.
  7111. @40dAdjust for dbra.
  7112. @40dSplit up into two 16-bit values.
  7113. @d
  7114. @40dCopy the longwords.
  7115. @d
  7116. @d
  7117.  
  7118.         ; Done copying longwords.  Get the number of bytes left over (0-3)
  7119.         ; from the stack and fall into the byte copy routine.
  7120.  
  7121. @40dRestore number of bytes left over.
  7122. @40dExit if none.
  7123. @40dHigh 16 bits of byte count = 0.
  7124. @40dEnter the byte copy loop.
  7125.  
  7126.         ; Copy as individual bytes, either to clean up odds and ends after
  7127.         ; copying in larger chunks, or because copying in larger chunks
  7128.         ; wasn't worth it.
  7129.  
  7130. @40dSplit transfer count up into two
  7131. @40d16-bit sections.
  7132. @40dEnter loop at bottom (for dbra).
  7133. @40dCopy the bytes.
  7134. @d
  7135. @d
  7136. @d
  7137.  
  7138.  
  7139.         ; System exception alert entry point
  7140.         ; ----------------------------------
  7141.  
  7142.         ; If an exception occurs or a TRAP instruction is executed while the
  7143.         ; CPU is in supervisor mode, we jump here, since we have no task to
  7144.         ; blame it on.  If a task was running, we use its tc_TrapCode vector
  7145.         ; instead, but at powerup, the exec default for this vector is also
  7146.         ; initialized to point here.  Later, it is stolen by some other
  7147.         ; part of the system so the "Software error - task held" window can
  7148.         ; be put up before the guru.
  7149.  
  7150.  
  7151. @40dDump the registers.
  7152. @40dPoint at exception data on the stack.
  7153. @40dGet ExecBase.
  7154. @40dIs it even?
  7155. @d
  7156. @40dIf so, point where the current task
  7157. @40dpointer probably is.
  7158. @40dGet the exception number.
  7159. @40dMask out any garbage.
  7160.  
  7161.         ; Fall into Alert().  alertNum is the exception number from the
  7162.         ; stack, and A5 points either to the current task pointer, or to
  7163.         ; the exception data on the stack.
  7164.  
  7165.  
  7166. ---------------------------------------------------------------------------
  7167.   Alert( alertNum, parameters )
  7168.          D7        A5
  7169. ---------------------------------------------------------------------------
  7170.  
  7171.         ; This routine has a relatively failsafe mechanism for getting an
  7172.         ; alert message up on the screen.  I call this the "deferred guru".
  7173.  
  7174.         ; Right away, a signature ("HELP") is installed at location 0, and
  7175.         ; the guru data is stored at location $000100.  If the system hangs
  7176.         ; now, the user will get the guru after he/she reboots manually
  7177.         ; via CTRL-Amiga-Amiga.  If for any reason it decides it's in
  7178.         ; serious trouble, it will reset itself, with the same effect.
  7179.  
  7180. @40dDisable all interrupts.
  7181. @d
  7182.  
  7183.         ; If location 0 ALREADY contains "HELP", something is wrong, and
  7184.         ; no matter what the requested alert was, we reset the computer.
  7185.  
  7186. @40dSee if "HELP" is at location zero.
  7187. @40dIf so, unrecoverable crash.
  7188.  
  7189.         ; Store our own "deferred guru" data at 0 and $000100.  Then see
  7190.         ; if we should use it.  If ExecBase has been clobbered, or the
  7191.         ; stack is not working, or the unrecoverable alert bit is set,
  7192.         ; we blink the power light, and reset the computer.  The guru will
  7193.         ; come up during the reboot.
  7194.  
  7195. @40dMove "HELP" at location 0 now.
  7196. @40dPoint at location $000100.
  7197. @40dStore alert number there.
  7198. @40dStore the parameter.
  7199.  
  7200. @40dGet ExecBase.
  7201. @d
  7202.  
  7203.         ; Without checking, I would assume that this is where the famous
  7204.         ; "Recoverable alert doesn't work with expansion memory" bug is.
  7205.  
  7206.         ; Namely, if the ExecBase structure isn't in the first 64K of
  7207.         ; memory, we assume that it isn't OK.  With $C00000 memory, it
  7208.         ; will be at $C00276, and KABOOM, this fails, and the system
  7209.         ; resets, doing the unrecoverable alert thing via the "deferred
  7210.         ; alert" mechanism discussed earlier.
  7211.  
  7212. @40dIs ExecBase in the first 64K?
  7213. @40dIf not, unrecoverable crash.
  7214. @d
  7215. @40dCheck ExecBase complement pointer.
  7216. @d
  7217. @40dUnrecoverable crash if not valid.
  7218. @40dCheck if the stack is working by
  7219. @40dpushing a signature and trying to
  7220. @40dpop it off again.
  7221. @40dUnrecoverable crash if not working.
  7222. @40dTest high bit of alert number.
  7223. @40dBranch if unrecoverable.
  7224.  
  7225.         ; Processing for recoverable alerts.  If we get this far, we have
  7226.         ; verified that the "dead end alert" flag was not set, that the
  7227.         ; ExecBase pointer and structure are probably OK, and that the
  7228.         ; stack is working (stack pointer pointing to RAM).
  7229.  
  7230. @40dPoint to ExecBase->LastAlert.
  7231. @40dStore alert number.
  7232. @40dStore parameter.
  7233. @40dCall the guru alert routine.
  7234.  
  7235. @40dWas the subsystem ID field zero?
  7236. @40dIf not, return to the caller.
  7237.  
  7238.         ; The alert number was of the form 0000xxxx.  This means that it
  7239.         ; must have been a system exception.  Presumably, the user has had
  7240.         ; the option of pressing the left or right mouse button, reflected
  7241.         ; in D0 as returned from the guru routine.  Accordingly, we
  7242.         ; reset or go to the debugger.
  7243.  
  7244. @40dTest the guru routine's return code.
  7245. @40dRestore the registers.
  7246. @40dReset if zero flag not set.
  7247. @40dElse go to ROM-Wack.
  7248.  
  7249. @40dEnable interrupts if they are
  7250. @40dsupposed to be enabled.
  7251. @d
  7252. @d
  7253.  
  7254.  
  7255.         ; Unrecoverable system crash entry point
  7256.         ; --------------------------------------
  7257.  
  7258.         ; This routine blinks the power light slowly 6 times, and checks
  7259.         ; whether the user presses DEL on a terminal attached to the
  7260.         ; serial port.  If DEL is received, it jumps to ROM-Wack.  If
  7261.         ; DEL is not received, it resets the computer.  This may or may
  7262.         ; not lead to a guru, depending on how locations 0 and $000100 were
  7263.         ; set up before this was called.
  7264.  
  7265.         ; Entry point for when the stack is not working (stack pointer
  7266.         ; clobbered).  Set the stack pointer to 256K, and build a fake
  7267.         ; exception stack frame below it.
  7268.  
  7269. @40dSet stack pointer to 256K
  7270. @40dBuild fake exception stack frame.
  7271. @d
  7272.  
  7273.         ; Entry point for when the stack was working.
  7274.  
  7275. @40dSet CIA data direction register.
  7276. @40dSet power light to bright.
  7277.  
  7278.         ; Force the CPU into supervisor mode.  If the MOVE.W #$2700,SR
  7279.         ; instruction bombs the first time, it will work the second time.
  7280.  
  7281. @40dSet privilege violation vector.
  7282. @a?fc3076
  7283. FC3076  move.w    #$2700,SR             Mask all maskable interrupts.
  7284. @a=fc307a
  7285.  
  7286.         ; Blink the power light slowly 6 times and look for a DEL character
  7287.         ; coming in through the serial port at 9600 bps.  If such a character
  7288.         ; is received, go to the debugger.
  7289.  
  7290. @40dSet loop counter to 5.
  7291. @40dSet serial port for 8 bits, 9600 bps.
  7292. @d
  7293. @40dSet power light to dim.
  7294. @40dDelay.
  7295. @40dSet power light to bright.
  7296. @40dDelay.
  7297. @40dRead the serial port.
  7298. @40dClear serial port interrupt bit.
  7299. @d
  7300. @40dDid we receive a DEL character?
  7301. @40dIf not, keep blinking the light.
  7302. @40dIf DEL not pressed, reset.
  7303.  
  7304.         ; The user pressed DEL.  Push the exception number on the stack
  7305.         ; and enter the debugger.
  7306.  
  7307. @d
  7308. @40dGo to ROM-Wack.
  7309.  
  7310.  
  7311.         ; "Deferred Guru" support routines
  7312.         ; --------------------------------
  7313.  
  7314.         ; The following routine is called early in the startup code.  Since
  7315.         ; there is no stack at that point, it returns via a jump, rather
  7316.         ; than an RTS.  It removes the "HELP" at zero, if present, and
  7317.         ; loads D6 and D7 with the data for ExecBase->LastAlert.
  7318.  
  7319. @40dLoad -1 into D6
  7320. @40dSee if location 0 contains "HELP".
  7321. @40dIf not, go back to init. code.
  7322. @40dClear location 0.
  7323. @40dLoad D6 and D7 from location $0100.
  7324. @40dGo back to init. code.
  7325.  
  7326.         ; The following subroutine is called later, after the ExecBase
  7327.         ; structure has been built.  It writes the data determined above
  7328.         ; (still in D6 and D7) into ExecBase->LastAlert.
  7329.  
  7330. @d
  7331. @d
  7332.  
  7333.  
  7334.         ; Guru Alert Routine
  7335.         ; ------------------
  7336.  
  7337.         ; This routine puts the big red "Guru" message up on the screen,
  7338.         ; waits for the user to click the mouse button, then returns.
  7339.  
  7340.         ; The routine is called with the alert number and parameters stored
  7341.         ; at LastAlert in the ExecBase structure.  This routine reads the
  7342.         ; alert number from there and decides what to do with it.
  7343.  
  7344.         ; An alert number of -1 means that no alert was outstanding, and
  7345.         ; therefore, the routine returns right away.  This means that if
  7346.         ; it is called via the "alert.hook" mechanism, and no alert was
  7347.         ; pending from before the reboot, nothing will happen.
  7348.  
  7349.         ; If the alert number is not -1, an alert will be generated.  The
  7350.         ; following algorithm is used to decide what the first string in
  7351.         ; the alert should say.
  7352.  
  7353.         ; IF the alert number is of the form xxxx01xxxxxxxx THEN
  7354.         ;   Make the alert message "Not enough memory".
  7355.         ; ELSEIF the high bit in the alert number is clear, and the
  7356.         ;        "general error" field is not zero THEN
  7357.         ;   Make the alert message "Recoverable Alert".
  7358.         ; ELSE
  7359.         ;   Make the alert message "Software Failure".
  7360.         ; ENDIF
  7361.  
  7362.         ; When the alert is finished (the user pressed the mouse button),
  7363.         ; the LastAlert field in ExecBase is cleared to -1, and the longword
  7364.         ; at location 0 is cleared to zero.
  7365.  
  7366.  
  7367. @d
  7368.  
  7369. @40dDelay for a while.
  7370. @d
  7371. @d
  7372. @d
  7373.  
  7374. @40dGet the alert number.
  7375. @40dCompare to -1 (indicates no alert).
  7376. @d
  7377. @40dExit if equal.
  7378. @40dReserve 200 bytes of stack space.
  7379. @40dPoint to base of reserved area.
  7380.  
  7381.         ; Decide which alert message to use.
  7382.  
  7383. @40dPoint to "Software Failure" string.
  7384. @40dGet the alert number.
  7385. @40dGet the general error number.
  7386. @40dIs it an AG_NoMemory type of alert?
  7387. @40dIf so, point to "Not enough Memory"
  7388. @40dstring.
  7389. @d
  7390. @40dIf otherwise, check the dead-end
  7391. @40dalert flag.  If it is clear, but
  7392. @40dthe Subsystem/General error fields
  7393. @40dare not zero, then point to the
  7394. @40d"Recoverable Alert" string.
  7395.  
  7396. @40dCopy the string into the buffer.
  7397. @40dPoint to "Press left mouse button..."
  7398. @40dCopy the string into the buffer.
  7399. @40dPut a zero into the buffer.
  7400. @40dPoint to "Guru Meditation..." string.
  7401. @40dPoint to alert data.
  7402. @40dPoint to character output routine.
  7403. @40dRawDoFmt()
  7404.  
  7405. @40dPoint to "intuition.library".
  7406. @40dMinimum version is 0 (any).
  7407. @40dOpenLibrary()
  7408. @40dDid it open OK?
  7409. @40dIf not, skip the following.
  7410. @40dSave ExecBase.
  7411. @40dGet IntuitionBase.
  7412. @40dTell intuition that the alert # is 0.
  7413. @40dPoint to the alert string.
  7414. @40dAlert should be 40 video lines high.
  7415. @40dDisplayAlert()
  7416. @d
  7417. @40dGet IntuitionBase.
  7418. @40dRestore ExecBase.
  7419. @40dCloseLibrary()
  7420.  
  7421. @40dDeallocate string space on stack.
  7422. @40dRemove "HELP" at 0, if present.
  7423. @d
  7424. @40dSet LastAlert to -1.
  7425.  
  7426.         ; Set the return code.  If intuition.library didn't open, A2 contains
  7427.         ; a non-zero address, so a non-zero return value results.  If
  7428.         ; intuition could be called, this is the return code from the
  7429.         ; DisplayAlert() call.
  7430.  
  7431. @40dSet return code.
  7432. @d
  7433. @d
  7434.  
  7435.         ; Character output routine for RawDoFmt() while putting together
  7436.         ; the "Guru Meditation #..." message.
  7437.  
  7438. @40dPut character in buffer.
  7439. @40dZero-terminate the buffer.
  7440. @d
  7441.  
  7442.         ; Routine to copy a given string to the output buffer while
  7443.         ; building the guru message.
  7444.  
  7445. @40dPut a zero into the buffer.
  7446. @40dCopy the given string.
  7447. @d
  7448. @40dTerminate buffer with $FF.
  7449. @d
  7450.  
  7451.         ; Strings used for the guru message.
  7452.  
  7453. @8p@,22s
  7454. @8p@,21s
  7455. @8p@,22s
  7456. @8p@,39s
  7457. @8p@,31s
  7458.  
  7459.         ; Name used to open intuition to put up the alert.
  7460.  
  7461. @8p@,18s
  7462.  
  7463.  
  7464.         ; The "alert.hook" mechanism
  7465.         ; --------------------------
  7466.  
  7467.         ; This is a RomTag.  At system startup, this will be found and added
  7468.         ; to the resident module list.  Since it has the RTW_COLDSTART flag
  7469.         ; set, it will be initialized along with the other libraries,
  7470.         ; devices, etc.  The RTF_AUTOINIT flag is not set, therefore, the
  7471.         ; code at RT_INIT is called.
  7472.  
  7473.         ; The code at RT_INIT is the Guru routine.  This reads the LastAlert
  7474.         ; field in ExecBase.  If this is not -1, then an alert is still
  7475.         ; outstanding (from before the reboot), and this puts it up, lets
  7476.         ; the user click the mouse button, then returns.  The resident
  7477.         ; module initialization then continues, the DOS boots, and the
  7478.         ; system comes up.
  7479.  
  7480.         ; The purpose of all this is to allow the system to defer display
  7481.         ; of a guru message until after the system has been cold-started.
  7482.  
  7483.  
  7484. @8p@,13s
  7485.  
  7486. @a?fc323a
  7487. @8p@24wRTC_MATCHWORD   (start of ROMTAG marker)
  7488. @8p@24lRT_MATCHTAG     (pointer RTC_MATCHWORD)
  7489. @8p@24lRT_ENDSKIP      (pointer to end of code)
  7490. @8p@24bRT_FLAGS        (RTW_COLDSTART)
  7491. @8p@24bRT_VERSION      (33 decimal)
  7492. @8p@24bRT_TYPE         (NT_UNKNOWN)
  7493. @8p@24bRT_PRI          (priority = 5)
  7494. @8p@24lRT_NAME         (pointer to name)
  7495. @8p@24lRT_IDSTRING     (pointer to ID string)
  7496. @8p@24lRT_INIT         (execution address)
  7497.  
  7498.  
  7499.         ; ROM-Wack command dispatch tables ("Key bindings").
  7500.         ; --------------------------------------------------
  7501.  
  7502.         ; ROM-Wack can be in one of two modes when a key is pressed.  It can
  7503.         ; be waiting for a command, or it can be in the process of gathering
  7504.         ; a multi character command.  The two tables below decide what to do
  7505.         ; with the key in each case.
  7506.  
  7507.         ; Each table entry has 4 fields.  These are, address of next table
  7508.         ; entry to try if key doesn't match this one, lowest key value for
  7509.         ; this table entry, highest key value (if several) or zero, address
  7510.         ; to jump to.
  7511.  
  7512.         ; Primary command dispatch table.
  7513.  
  7514. @8p@9l@3b@3b@17l^D
  7515. @8p@9l@3b@3b@17l<Return>
  7516. @8p@9l@3b@3b@17l<Tab>
  7517. @8p@9l@3b@3b@17l?
  7518. @8p@9l@3b@3b@17l.
  7519. @8p@9l@3b@3b@17l,
  7520. @8p@9l@3b@3b@17l>
  7521. @8p@9l@3b@3b@17l<
  7522. @8p@9l@3b@3b@17l<Backspace>
  7523. @8p@9l@3b@3b@17l<Space>
  7524. @8p@9l@3b@3b@17l[
  7525. @8p@9l@3b@3b@17l]
  7526. @8p@9l@3b@3b@17l:
  7527. @8p@9l@3b@3b@17l+
  7528. @8p@9l@3b@3b@17l-
  7529. @8p@9l@3b@3b@17l=
  7530. @8p@9l@3b@3b@17l!
  7531. @8p@9l@3b@3b@17l^
  7532. @8p@9l@3b@3b@17l_
  7533. @8p@9l@3b@3b@17l0 - 9
  7534. @8p@9l@3b@3b@17la - z
  7535. @8p@9l@3b@3b@17lA - Z
  7536.  
  7537. @8p@32lEnd of table marker.
  7538.  
  7539.  
  7540.         ; Secondary command dispatch table (used while a command
  7541.         ; and/or address is being typed).
  7542.  
  7543. @8p@9l@3b@3b@17l<Backspace>
  7544. @8p@9l@3b@3b@17l<Return>
  7545. @8p@9l@3b@3b@17l<CTRL-X>
  7546. @8p@9l@3b@3b@17l<CTRL-U>
  7547. @8p@9l@3b@3b@17l>
  7548. @8p@9l@3b@3b@17l<
  7549. @8p@9l@3b@3b@17l<Space>
  7550. @8p@9l@3b@3b@17l_
  7551. @8p@9l@3b@3b@17l0 - 9
  7552. @8p@9l@3b@3b@17la - z
  7553. @8p@9l@3b@3b@17lA - Z
  7554.  
  7555. @8p@32lEnd of table marker.
  7556.  
  7557.  
  7558.         ; Table of multi-character ROM-Wack commands.
  7559.  
  7560. @8p@,22s
  7561. @8p@,22s
  7562. @8p@,22s
  7563. @8p@,12s
  7564.  
  7565.  
  7566.         ; Dispatch table for multicharacter commands.
  7567.  
  7568.         ; The fields are link to next table entry, address of command string,
  7569.         ; an unused value (presumably from a larger version of Wack), and
  7570.         ; the address to jump to for that command.
  7571.  
  7572. @a?fc33f4
  7573. @8p@9l@9l@5w@13l"alter"
  7574. @8p@9l@9l@5w@13l"boot"
  7575. @8p@9l@9l@5w@13l"clear"
  7576. @8p@9l@9l@5w@13l"fill"
  7577. @8p@9l@9l@5w@13l"find"
  7578. @8p@9l@9l@5w@13l"go"
  7579. @8p@9l@9l@5w@13l"ig"
  7580. @8p@9l@9l@5w@13l"limit"
  7581. @8p@9l@9l@5w@13l"list"
  7582. @8p@9l@9l@5w@13l"regs"
  7583. @8p@9l@9l@5w@13l"reset"
  7584. @8p@9l@9l@5w@13l"resume"
  7585. @8p@9l@9l@5w@13l"set"
  7586. @8p@9l@9l@5w@13l"show"
  7587. @8p@9l@9l@5w@13l"user"
  7588. @8p@l
  7589.  
  7590. @8p@32wPadding.
  7591.  
  7592.         ; That's it.  The next RomTag (for the audio.device) comes right
  7593.         ; after the two bytes of padding shown above.
  7594.