home *** CD-ROM | disk | FTP | other *** search
/ ftp.ee.pdx.edu / 2014.02.ftp.ee.pdx.edu.tar / ftp.ee.pdx.edu / pub / users / Harry / Blitz / OSProject / p1 / Runtime.s < prev    next >
Text File  |  2007-09-19  |  32KB  |  1,013 lines

  1. ! KPL Programming Language Runtime Support Code
  2. !
  3. ! ==========  THIS VERSION IS TO SUPPORT PROJECT 1  ==========
  4. !
  5. ! Harry Porter  -  09/26/04
  6. !
  7. ! The following functions are implemented in this file and may be used by
  8. ! the KPL programmer.  They follow the standard KPL calling
  9. ! conventions.
  10. !
  11.     .export    print
  12.     .export    printInt
  13.     .export    printHex
  14.     .export    printChar
  15.     .export    printBool
  16.     .export    printDouble
  17.     .export    MemoryZero
  18.     .export    MemoryCopy
  19.     .export    getCatchStack
  20.     .export    RuntimeExit
  21. !
  22. ! The following functions are implemented in this file and
  23. ! are used by the code generated by the KPL compiler:
  24. !
  25.     .export _putString
  26.     .export    _heapInitialize
  27.     .export    _heapAlloc
  28.     .export    _heapFree
  29.     .export    _RestoreCatchStack
  30.     .export    _PerformThrow
  31.     .export    _IsKindOf
  32.     .export    _PosInf
  33.     .export    _NegInf
  34.     .export    _NegZero
  35. !
  36. ! Jumps to the following labels may be generated by the KPL compiler.
  37. ! Each will print an error message and halt program execution.
  38. !
  39.     .export    _runtimeErrorOverflow
  40.     .export    _runtimeErrorZeroDivide
  41.     .export    _runtimeErrorNullPointer
  42.     .export    _runtimeErrorUninitializedObject
  43.     .export    _runtimeErrorWrongObject
  44.     .export    _runtimeErrorWrongObject2
  45.     .export    _runtimeErrorWrongObject3
  46.     .export    _runtimeErrorBadObjectSize
  47.     .export    _runtimeErrorDifferentArraySizes
  48.     .export    _runtimeErrorWrongArraySize
  49.     .export    _runtimeErrorUninitializedArray
  50.     .export    _runtimeErrorBadArrayIndex
  51.     .export    _runtimeErrorNullPointerDuringCall
  52.     .export    _runtimeErrorArrayCountNotPositive
  53.     .export    _runtimeErrorRestoreCatchStackError
  54. !
  55. ! Jumps to the following labels may be generated occur only in this file.
  56. !
  57. !    _runtimeErrorThrowHandlerHasReturned
  58. !    _runtimeErrorFatalThrowError
  59. !    _runtimeErrorInterruptsEnabled
  60. !
  61. ! Routines that are created by the KPL Compiler and called from here:
  62. !
  63.     .import _mainEntry
  64. !
  65. ! Symbols that are created by the KPL compiler and used in this file:
  66. !
  67.     .import _Error_P_System_UncaughtThrowError
  68. !
  69. ! Routines that should be implemented in KPL and called from here:
  70. !
  71.     .import _P_System_KPLMemoryInitialize
  72.     .import _P_System_KPLMemoryAlloc
  73.     .import _P_System_KPLMemoryFree
  74.     .import _P_System_KPLUncaughtThrow
  75.     .import _P_System_KPLIsKindOf
  76. !
  77. ! The initial stack will start at high memory and grow downward:
  78. !
  79. STACK_START    =    0x00ffff00
  80.  
  81.  
  82.  
  83. !
  84. ! =====================  Program entry point  =====================
  85. !
  86.     .text
  87. _entry:
  88.  
  89.  
  90.  
  91. !
  92. ! =====================  Interrupt Trap Vector (in low memory)  =====================
  93. !
  94. ! Here is the interrupt vector, which will be loaded at address 0x00000000.
  95. ! Each entry is 4 bytes.  They are located at fixed, pre-defined addresses.
  96. ! Each entry contains a jump to the handler routine.
  97. !
  98. ! Timer interrupts will occur, but this code will ignore them be returning.
  99. ! None of the other interrupts should occur; if they do, we will print an error
  100. ! message and halt.
  101. !
  102. PowerOnReset:
  103.         jmp     RuntimeStartup
  104. TimerInterrupt:
  105.         reti
  106. DiskInterrupt:
  107.         jmp     DiskInterruptHandler
  108. SerialInterrupt:
  109.         jmp     SerialInterruptHandler
  110. HardwareFault:
  111.         jmp     HardwareFaultHandler
  112. IllegalInstruction:
  113.         jmp     IllegalInstructionHandler
  114. ArithmeticException:
  115.         jmp     ArithmeticExceptionHandler
  116. AddressException:
  117.         jmp     AddressExceptionHandler
  118. PageInvalidException:
  119.         jmp     PageInvalidExceptionHandler
  120. PageReadonlyException:
  121.         jmp     PageReadonlyExceptionHandler
  122. PrivilegedInstruction:
  123.         jmp     PrivilegedInstructionHandler
  124. AlignmentException:
  125.         jmp     AlignmentExceptionHandler
  126. ExceptionDuringInterrupt:
  127.         jmp     ExceptionDuringInterruptHandler
  128. SyscallTrap:
  129.         jmp     SyscallTrapHandler
  130.  
  131.  
  132.  
  133.  
  134. ! =====================  Interrupt Handlers  =====================
  135. DiskInterruptHandler:
  136.     set    ExceptMess1,r10            ! Print an error message
  137.     jmp    printRuntimeError        ! .  and terminate all execution
  138.  
  139. SerialInterruptHandler:
  140.     set    ExceptMess1,r11            ! Print an error message
  141.     jmp    printRuntimeError        ! .  and terminate all execution
  142.  
  143. SyscallTrapHandler:
  144.     set    ExceptMess1,r12            ! Print an error message
  145.     jmp    printRuntimeError        ! .  and terminate all execution
  146.  
  147. HardwareFaultHandler:
  148.     set    ExceptMess1,r1            ! Print an error message
  149.     jmp    printRuntimeError        ! .  and terminate all execution
  150.  
  151. IllegalInstructionHandler:
  152.     set    ExceptMess2,r1            ! Print an error message
  153.     jmp    printRuntimeError        ! .  and terminate all execution
  154.  
  155. ArithmeticExceptionHandler:
  156.     set    ExceptMess3,r1            ! Print an error message
  157.     jmp    printRuntimeError        ! .  and terminate all execution
  158.  
  159. AddressExceptionHandler:
  160.     set    ExceptMess4,r1            ! Print an error message
  161.     jmp    printRuntimeError        ! .  and terminate all execution
  162.  
  163. PageInvalidExceptionHandler:
  164.     set    ExceptMess5,r1            ! Print an error message
  165.     jmp    printRuntimeError        ! .  and terminate all execution
  166.  
  167. PageReadonlyExceptionHandler:
  168.     set    ExceptMess6,r1            ! Print an error message
  169.     jmp    printRuntimeError        ! .  and terminate all execution
  170.  
  171. PrivilegedInstructionHandler:
  172.     set    ExceptMess7,r1            ! Print an error message
  173.     jmp    printRuntimeError        ! .  and terminate all execution
  174.  
  175. AlignmentExceptionHandler:
  176.     set    ExceptMess8,r1            ! Print an error message
  177.     jmp    printRuntimeError        ! .  and terminate all execution
  178.  
  179. ExceptionDuringInterruptHandler:
  180.     set    STACK_START,r15            ! Reset stack so printing works
  181.     set    ExceptMess9,r1            ! Print an error message
  182.     jmp    printRuntimeError        ! .  and terminate all execution
  183.  
  184. ExceptMess1:
  185.     .ascii    "\nA HardwareFaultException has occurred!  Type 'st' to see stack.\n\0"
  186. ExceptMess2:
  187.     .ascii    "\nAn IllegalInstructionException has occurred!  Type 'st' to see stack.\n\0"
  188. ExceptMess3:
  189.     .ascii    "\nAn ArithmeticException has occurred!  Type 'st' to see stack.\n\0"
  190. ExceptMess4:
  191.     .ascii    "\nAn AddressException has occurred!  Type 'st' to see stack.\n\0"
  192. ExceptMess5:
  193.     .ascii    "\nA PageInvalidException has occurred!  Type 'st' to see stack.\n\0"
  194. ExceptMess6:
  195.     .ascii    "\nA PageReadonlyException has occurred!  Type 'st' to see stack.\n\0"
  196. ExceptMess7:
  197.     .ascii    "\nA PrivilegedInstruction has occurred!  Type 'st' to see stack.\n\0"
  198. ExceptMess8:
  199.     .ascii    "\nAn AlignmentException has occurred!  Type 'st' to see stack.\n\0"
  200. ExceptMess9:
  201.     .ascii    "\nA ExceptionDuringInterrupt has occurred!  Type 'st' to see stack.\n\0"
  202. ExceptMess10:
  203.     .ascii    "\nA DiskInterrupt has occurred!  Type 'st' to see stack.\n\0"
  204. ExceptMess11:
  205.     .ascii    "\nA SerialInterrupt has occurred!  Type 'st' to see stack.\n\0"
  206. ExceptMess12:
  207.     .ascii    "\nA SyscallTrap has occurred!  Type 'st' to see stack.\n\0"
  208.     .align
  209.  
  210.  
  211.  
  212. ! =====================  KPL Runtime Error Handlers  =====================
  213. _runtimeErrorOverflow:
  214.     set    ErrorMess1,r1        ! Print an error message
  215.     jmp    printRuntimeError    ! .  and terminate all execution
  216.  
  217. _runtimeErrorZeroDivide:
  218.     set    ErrorMess2,r1        ! Print an error message
  219.     jmp    printRuntimeError    ! .  and terminate all execution
  220.  
  221. _runtimeErrorNullPointer:
  222.     set    ErrorMess3,r1        ! Print an error message
  223.     jmp    printRuntimeError    ! .  and terminate all execution
  224.  
  225. _runtimeErrorUninitializedObject:
  226.     set    ErrorMess4,r1        ! Print an error message
  227.     jmp    printRuntimeError    ! .  and terminate all execution
  228.  
  229. _runtimeErrorWrongObject:
  230.     set    ErrorMess5,r1        ! Print an error message
  231.     jmp    printRuntimeError    ! .  and terminate all execution
  232.  
  233. _runtimeErrorWrongObject2:
  234.     set    ErrorMess6,r1        ! Print an error message
  235.     jmp    printRuntimeError    ! .  and terminate all execution
  236.  
  237. _runtimeErrorWrongObject3:
  238.     set    ErrorMess7,r1        ! Print an error message
  239.     jmp    printRuntimeError    ! .  and terminate all execution
  240.  
  241. _runtimeErrorBadObjectSize:
  242.     set    ErrorMess8,r1        ! Print an error message
  243.     jmp    printRuntimeError    ! .  and terminate all execution
  244.  
  245. _runtimeErrorDifferentArraySizes:
  246.     call    stopInterrupts        ! suspend any thread switching
  247.     push    r1            ! save r1 and r3
  248.     push    r3            ! .  so the user can look at them
  249.     set    ErrorMess9,r1        ! print the error message
  250.     call    _putString        ! .
  251.     pop    r3            ! restore r1 and r3
  252.     pop    r1            ! .
  253.     jmp    TerminateRuntime    ! Can't continue: invoke "debug"
  254.  
  255. _runtimeErrorWrongArraySize:
  256.     call    stopInterrupts        ! suspend any thread switching
  257.     push    r1            ! save r1 and r2
  258.     push    r2            ! .  so the user can look at them
  259.     set    ErrorMess10,r1        ! print the error message
  260.     call    _putString        ! .
  261.     pop    r2            ! restore r1 and r2
  262.     pop    r1            ! .
  263.     jmp    TerminateRuntime    ! terminate all execution
  264.  
  265. _runtimeErrorUninitializedArray:
  266.     set    ErrorMess11a,r1        ! Print an error message
  267.     jmp    printRuntimeError    ! .  and terminate all execution
  268.  
  269. _runtimeErrorBadArrayIndex:
  270.     call    stopInterrupts        ! suspend any thread switching
  271.     push    r2            ! save r2 so the user can look at it
  272.     set    ErrorMess11,r1        ! print the error message
  273.     call    _putString        ! .
  274.     pop    r2            ! restore r2
  275.     jmp    TerminateRuntime    ! terminate all execution
  276.  
  277. _runtimeErrorNullPointerDuringCall:
  278.     set    ErrorMess12,r1        ! Print an error message
  279.     jmp    printRuntimeError    ! .  and terminate all execution
  280.  
  281. _runtimeErrorArrayCountNotPositive:
  282.     call    stopInterrupts        ! suspend any thread switching
  283.     push    r1            ! save r1 so the user can look at it
  284.     set    ErrorMess13,r1        ! print the error message
  285.     call    _putString        ! .
  286.     pop    r1            ! restore r1
  287.     jmp    TerminateRuntime    ! terminate all execution
  288.  
  289. _runtimeErrorRestoreCatchStackError:
  290.     set    ErrorMess14,r1        ! Print an error message
  291.     jmp    printRuntimeError    ! .  and terminate all execution
  292.  
  293. _runtimeErrorThrowHandlerHasReturned:
  294.     set    ErrorMess15,r1        ! Print an error message
  295.     jmp    printRuntimeError    ! .  and terminate all execution
  296.  
  297. _runtimeErrorFatalThrowError:
  298.     set    ErrorMess16,r1        ! Print an error message
  299.     jmp    printRuntimeError    ! .  and terminate all execution
  300.  
  301. _runtimeErrorInterruptsEnabled:
  302.     set    ErrorMess17,r1        ! Print an error message
  303.     jmp    printRuntimeError    ! .  and terminate all execution
  304.  
  305.  
  306. ErrorMess1:
  307.     .ascii    "\nArithmetic overflow has occurred!  Type 'st' to see stack.\n\0"
  308. ErrorMess2:
  309.     .ascii    "\nDivide-by-zero has occurred!  Type 'st' to see stack.\n\0"
  310. ErrorMess3:
  311.     .ascii    "\nAttempt to use a null pointer!  Type 'st' to see stack.\n\0"
  312. ErrorMess4:
  313.     .ascii    "\nAttempt to use an uninitialized object!  Type 'st' to see stack.\n\0"
  314. ErrorMess5:
  315.     .ascii    "\nDuring an assignment of the form '*ptr = x', the ptr does not already point to an instance of the same class as x!  Type 'st' to see stack.\n\0"
  316. ErrorMess6:
  317.     .ascii    "\nDuring an assignment of the form 'x = *ptr', the ptr does not already point to an instance of the same class as x!  Type 'st' to see stack.\n\0"
  318. ErrorMess7:
  319.     .ascii    "\nDuring an object assignment of the form '*ptr1 = *ptr2', the two objects are not instances of the same class!  Type 'st' to see stack.\n\0"
  320. ErrorMess8:
  321.     .ascii    "\nDuring an object assignment or object equality test, something is wrong with the dispatch table pointer, the dispatch table, "
  322.     .ascii   "or the class descriptor; the size of the object is less than 4!  Type 'st' to see stack.\n\0"
  323. ErrorMess9:
  324.     .ascii    "\nDuring an array copy, the two arrays have different sizes  (r1=target size, r3=source size)!  Type 'st' to see stack.\n\0"
  325. ErrorMess10:
  326.     .ascii    "\nDuring an array copy, a dynamic array does not have the correct size (r1=actual size, r2=expected size)!  Type 'st' to see stack.\n\0"
  327. ErrorMess11:
  328.     .ascii    "\nDuring an array index calculation, the index is either less than 0 or greater than or equal to the array size (r2=index)!  Type 'st' to see stack.\n\0"
  329. ErrorMess11a:
  330.     .ascii    "\nAttempt to use an uninitialized array!  Type 'st' to see stack.\n\0"
  331. ErrorMess12:
  332.     .ascii    "\nDuring the invocation of a nameless function, the function pointer was null!  Type 'st' to see stack.\n\0"
  333. ErrorMess13:
  334.     .ascii    "\nDuring the initialization of an array, a 'count' expression was zero or less (r1=count)!  Type 'st' to see stack.\n\0"
  335.     .align
  336. ErrorMess14:
  337.     .ascii    "\nWhile popping the Catch Stack, an error has occurred!  Type 'st' to see stack.\n\0"
  338. ErrorMess15:
  339.     .ascii    "\nAttempt to return from KPLUncaughtThrow!  Type 'st' to see stack.\n\0"
  340. ErrorMess16:
  341.     .ascii    "\nError 'UncaughtThrowError' has been thrown but not caught!  Type 'st' to see stack.\n\0"
  342. ErrorMess17:
  343.     .ascii    "\nAttempt to perform serial I/O while interrupts are not disabled!  Type 'st' to see stack.\n\0"
  344.     .align
  345.  
  346.  
  347.  
  348. ! =====================  printRuntimeError  =====================
  349. !
  350. ! Come here to print a runtime error message and die.
  351. ! On entry, r1 points to the message.
  352. !
  353. printRuntimeError:
  354.     call    stopInterrupts        ! suspend any thread switching
  355.     call    _putString        ! .
  356.     jmp    TerminateRuntime    ! Can't continue: invoke "debug"
  357.  
  358.  
  359.  
  360. ! =====================  stopInterrupts  =====================
  361. ! This routine is called when a runtime error occurs; we are planning to
  362. ! print a final error message and suspend execution.  The problem is that
  363. ! the running program may be an operating system with multiple threads.
  364. ! An interrupt could occur during the printing of the error message, causing
  365. ! a thread switch, which might result in incomplete or incorrect execution of
  366. ! the code to print the message.
  367. !
  368. ! This routine disables interrutps, so that the message can be printed safely.
  369. ! When this routine is called, interrupts may or may not be enabled.  Also we
  370. ! may or may not be in System mode, we cannot simply execute a "cleari" instruction.
  371. !
  372. ! This routine overwrites the syscall interrupt vector and then executes a
  373. ! syscall instruction.  This will have the effect of clearing the "I" bit and
  374. ! setting the "S" bit, achieving the desired effect.
  375. !
  376. ! Registers modified: none.
  377. !
  378. stopInterrupts:
  379.     bis    needToClear        ! If interrupts are disabled  &&
  380.     bsc    needToClear        ! .  we are in System mode
  381.     ret                !   return
  382. needToClear:                ! EndIf
  383.     push    r1            ! Save r1 and r2
  384.     push    r2            ! .
  385.     set    relAddr,r1        ! Move a rel addr of keepGoing into r1
  386.     load    [r1],r1            ! .
  387.     set    0xa1000000,r2        ! Add in "jmp" op code
  388.     or    r1,r2,r1        ! .
  389.     store    r1,[r0+0x00000034]    ! Store that jmp in the syscall vector
  390.     syscall    0            ! Execute a syscall trap
  391.  
  392. relAddr:
  393.     .word    (keepGoing-0x00000034)
  394.  
  395. keepGoing:
  396.     pop    r0            ! The interrupt pushed 3 words onto
  397.     pop    r0            ! .  the stack; get rid of them.
  398.     pop    r0            ! .
  399.     pop    r2            ! Restore r1 and r2
  400.     pop    r1            ! .
  401.     ret                ! return to caller
  402.  
  403.  
  404.  
  405. !
  406. ! Misc Floating-Point Constants
  407. !
  408. _PosInf:
  409.     .word    0x7ff00000
  410.     .word    0x00000000
  411. _NegInf:
  412.     .word    0xfff00000
  413.     .word    0x00000000
  414. _NegZero:
  415.     .word    0x80000000
  416.     .word    0x00000000
  417.  
  418.  
  419.  
  420. !
  421. ! Name of this file
  422. !
  423. SourceFileName:
  424.     .ascii    "Runtime.s\0"
  425.     .align
  426.  
  427.  
  428.  
  429. ! =====================  RuntimeStartup  =====================
  430. !
  431. ! Prepare for KPL program execution.  Initialize the stack pointer,
  432. ! print the "PROGRAM STARTING" message, and call the "main" function.
  433. !
  434. RuntimeStartup:
  435.     set    STACK_START,r15        ! Initialize the stack pointer
  436.     set    startupMessage,r1    ! Print start-up message
  437.     call    _putString        ! .
  438.                     ! Interrupts are initially disabled
  439.     call    _mainEntry        ! Call "_mainEntry"
  440.     jmp    RuntimeExit        ! Perform normal termination
  441. startupMessage:
  442.     .ascii    "====================  KPL PROGRAM STARTING  ====================\n\0"
  443.     .align
  444.  
  445.  
  446.  
  447. ! =====================  RuntimeExit  =====================
  448. ! external RuntimeExit ()
  449. !
  450. ! This routine prints the normal program termination message and
  451. ! never returns.  This routine is also callable from KPL code.
  452. !
  453. RuntimeExit:
  454.     call    stopInterrupts        ! suspend any thread switching
  455.     set    goodbyeMessage,r1    ! print message
  456.     call    _putString        ! .
  457.     jmp    TerminateRuntime    ! goto TerminateRuntime
  458. goodbyeMessage:
  459.     .ascii    "\n====================  KPL PROGRAM TERMINATION  ====================\n\0"
  460.     .align
  461.  
  462.  
  463.  
  464. !
  465. ! =====================  TerminateRuntime  =====================
  466. !
  467. ! Come here when there is nothing more that can be done.
  468. ! NOTE: Interrupts must be disabled before calling this routine, to
  469. ! prevent any further thread switching.
  470. !
  471. TerminateRuntime:
  472.     debug                ! Pop up to BLITZ Emulator command mode
  473.     set    noGoMessage,r1        ! Print "You may not continue"
  474.     call    _putString        ! .
  475.     jmp    TerminateRuntime    ! ... and repeat, if "go" is entered
  476. noGoMessage:
  477.     .ascii    "\nThe KPL program has terminated; you may not continue!\n\0"
  478.     .align
  479.  
  480.  
  481.  
  482. ! =====================  _putString  =====================
  483. ! This routine is passed r1 = a pointer to a string of characters, terminated
  484. ! by '\0'.  It prints all of them except the final '\0'.  The string is printed
  485. ! atomically by calling 'debug2'.
  486. !
  487. ! r1: ptr to string
  488. ! r2: ptr to string (saved version)
  489. ! r3: count
  490. ! r4: character 
  491. !
  492. ! Registers modified: none
  493. !
  494. _putString:
  495.     push    r1            ! save registers
  496.     push    r2            ! .
  497.     push    r3            ! .
  498.     push    r4            ! .
  499.     mov    r1,r2            ! r2 := ptr to the string
  500.     mov    0,r3            ! r3 := count of characters
  501. putStLoop:                ! loop
  502.     loadb    [r1],r4            !   r4 := next char
  503.     cmp    r4,0            !   if (r4 == '\0')
  504.     be    putStExit        !     then break
  505.     add    r1,1,r1            !   incr ptr
  506.     add    r3,1,r3            !   incr count
  507.     jmp    putStLoop        ! end
  508. putStExit:                ! .
  509.     mov    2,r1            ! perform upcall to emulator to
  510.     debug2                ! . do the printing
  511.     pop    r4            ! restore regs
  512.     pop    r3            ! .
  513.     pop    r2            ! .
  514.     pop    r1            ! .
  515.     ret                ! return
  516.  
  517.  
  518.  
  519. ! =====================  getCatchStack  =====================
  520. ! external getCatchStack () returns ptr to CATCH_RECORD
  521. !
  522. ! This routine returns the value of r12, which points to the Catch-Stack.
  523. ! The Catch-Stack is a linked list of CATCH_RECORDs, possibly NULL.
  524. !
  525. ! NOTE:  Whenever we leave the body statements in a try (i.e., fall-thru,
  526. !        throw, or return), records from the catch stack will be popped and
  527. !        freed.  "getCatchStack" returns a pointer to a list of CATCH_RECORDs
  528. !        as it is when "getCatchStack" is called, so watch out that the caller
  529. !        does not use records after they are freed.
  530. getCatchStack:
  531.         store    r12,[r15+4]        ! put r12 in the result position
  532.         ret                ! return
  533.  
  534.  
  535.  
  536.  
  537. ! =====================  MemoryZero  =====================
  538. ! external MemoryZero (p: ptr to void, byteCount: int)
  539. !
  540. ! This function is passed "p" = a pointer, and "byteCount" = the number
  541. ! of bytes.  It sets that block of memory to all zeros.  The byteCount may
  542. ! be zero or negative, in which case this routine zeroes nothing.  This
  543. ! routine performs no other error checking.
  544. !
  545. ! Here is the algorithm:
  546. !
  547. !      while byteCount > 0 && p asInteger % 4 != 0
  548. !        *(p asPtrTo char) = '\x00'
  549. !        p = p + 1
  550. !        byteCount = byteCount - 1
  551. !      endWhile
  552. !      while byteCount > 3
  553. !        *(p asPtrTo int) = 0
  554. !        p = p + 4
  555. !        byteCount = byteCount - 4
  556. !      endWhile
  557. !      if byteCount == 3
  558. !        *(p asPtrTo char) = '\x00'
  559. !        *((p+1) asPtrTo char) = '\x00'
  560. !        *((p+2) asPtrTo char) = '\x00'
  561. !      elseIf byteCount == 2
  562. !        *(p asPtrTo char) = '\x00'
  563. !        *((p+1) asPtrTo char) = '\x00'
  564. !      elseIf byteCount == 1
  565. !        *(p asPtrTo char) = '\x00'
  566. !      endIf
  567. !
  568. ! Register usage:
  569. !   r1 = p
  570. !   r2 = byteCount
  571. !   r3 = work reg
  572. !
  573. MemoryZero:
  574.         load    [r15+4],r1        ! r1 = arg1 (p)
  575.         load    [r15+8],r2        ! r2 = arg2 (byteCount)
  576. mzLoop1:                    ! LOOP:
  577.         cmp    r2,0            !   if byteCount <= 0 exit
  578.         ble    mzLoop2Test        !   .
  579.         and    r1,0x00000003,r3    !   tmp = p % 4
  580.         cmp    r3,0            !   if tmp == 0 exit
  581.         be    mzLoop2Test        !   .
  582.         storeb    r0,[r1]            !   *p = 0x00
  583.         add    r1,1,r1            !   p = p + 1
  584.         sub    r2,1,r2            !   byteCount = byteCount - 1
  585.         jmp    mzLoop1            ! ENDLOOP
  586. !        jmp    mzLoop2Test        ! LOOP
  587. mzLoop2:                    ! .
  588.         store    r0,[r1]            !   *p = 0x00000000
  589.         add    r1,4,r1            !   p = p + 4
  590.         sub    r2,4,r2            !   byteCount = byteCount - 4
  591. mzLoop2Test:
  592.         cmp    r2,3            !   if byteCount > 3 then repeat
  593.         bg    mzLoop2            !   .
  594.  
  595.         cmp    r2,3            ! if byteCount == 3
  596.         bne    mzTry2            ! .
  597.         storeb    r0,[r1]            !   *p = 0x00
  598.         storeb    r0,[r1+1]        !   *(p+1) = 0x00
  599.         storeb    r0,[r1+2]        !   *(p+2) = 0x00
  600.         ret                !   return
  601. mzTry2:        cmp    r2,2            ! else if byteCount == 2
  602.         bne    mzTry1            ! .
  603.         storeb    r0,[r1]            !   *p = 0x00
  604.         storeb    r0,[r1+1]        !   *(p+1) = 0x00
  605.         ret                !   return
  606. mzTry1:        cmp    r2,1            ! else if byteCount == 1
  607.         bne    mzDone            ! .
  608.         storeb    r0,[r1]            !   *p = 0x00
  609. mzDone:                        ! endif
  610.         ret                ! return
  611.  
  612.  
  613.  
  614. ! =====================  MemoryCopy  =====================
  615. ! external MemoryCopy (destPtr: ptr to void, srcPtr: ptr to void, byteCount: int)
  616. !
  617. ! This routine copies "byteCount" bytes of data from the memory area pointed
  618. ! to by "srcPtr" to the area pointed to by "destPtr".  The pointers and the
  619. ! byteCount do not have to be multiples of 4 and the count may be less than
  620. ! zero, in which case, nothing will be copied.  However, the memory areas must
  621. ! not overlap!  (This routine does not test for overlap and if they overlap, the
  622. ! wrong data may be copied.)
  623. !
  624. ! Here is the algorithm:
  625. !
  626. !      if (destPtr asInteger % 4 == 0) && 
  627. !         (srcPtr asInteger % 4 == 0)
  628. !        while byteCount > 3
  629. !          *(destPtr asPtrTo int) = *(srcPtr asPtrTo int)
  630. !          destPtr = destPtr + 4
  631. !          srcPtr = srcPtr + 4
  632. !          byteCount = byteCount - 4
  633. !        endWhile
  634. !      endIf
  635. !      while byteCount > 0
  636. !        *(destPtr asPtrTo char) = *(srcPtr asPtrTo char)
  637. !        destPtr = destPtr + 1
  638. !        srcPtr = srcPtr + 1
  639. !        byteCount = byteCount - 1
  640. !      endWhile
  641. !
  642. ! Register usage:
  643. !   r1 = destPtr
  644. !   r2 = srcPtr
  645. !   r3 = byteCount
  646. !   r4 = work reg
  647. MemoryCopy:
  648.         load    [r15+4],r1        ! r1 = arg1 (destPtr)
  649.         load    [r15+8],r2        ! r2 = arg2 (srcPtr)
  650.         load    [r15+12],r3        ! r3 = arg3 (byteCount)
  651.         and    r1,0x00000003,r4    ! if destPtr % 4 == 0
  652.         bne    mcDoBytes        ! .
  653.         and    r2,0x00000003,r4    ! .   and srcPtr % 4 == 0
  654.         bne    mcDoBytes        ! .
  655. mcWordLoop:                    !   LOOP:
  656.         cmp    r3,3            !     if byteCount <= 3 exit loop
  657.         ble    mcWordLoopExit        !     .
  658.         pop    [r2++],r4        !     *destPtr = *(srcPtr++)
  659.         store    r4,[r1]            !     .
  660.         add    r1,4,r1            !     destPtr = destPtr + 4
  661.         sub    r3,4,r3            !     byteCount = byteCount - 4
  662.         jmp    mcWordLoop        !   ENDLOOP
  663. mcWordLoopExit:                    !   .
  664. mcDoBytes:                    ! endif
  665. mcByteLoop:                    ! LOOP
  666.         cmp    r3,0            !   if byteCount <= 0 exit loop
  667.         ble    mcByteLoopExit        !   .
  668.         loadb    [r2],r4            !   *destPtr = *srcPtr
  669.         storeb    r4,[r1]            !   .
  670.         add    r1,1,r1            !   destPtr = destPtr + 1
  671.         add    r2,1,r2            !   srcPtr = srcPtr + 1
  672.         sub    r3,1,r3            !   byteCount = byteCount - 1
  673.         jmp    mcByteLoop        ! ENDLOOP
  674. mcByteLoopExit:                    ! .
  675.         ret                ! return
  676.  
  677.  
  678.  
  679. ! =====================  print  =====================
  680. ! external print (s: ptr to array of char)
  681. !
  682. ! This routine prints data directly and immediately to the output.  It is
  683. ! intended only for use in debugging the kernel; as such it bypass the serial
  684. ! I/O device entirely and uses the debug2 "back-door" to the virtual machine.
  685. ! It may be called from any code, including from within an interrupt handler.
  686. !
  687. ! This routine will print \n, \t, and any printable ASCII characters.
  688. ! It will print \n as "\r\n".  It will print everything else in the form "\xHH".
  689. print:
  690.         load    [r15+4],r2        ! Move the argument "s" into r2
  691.         pop    [r2++],r3        ! Move the count into r3 and incr ptr
  692.         mov    2,r1            ! Move function code into r1
  693.         debug2                ! Do the upcall
  694.         ret                ! Return
  695.  
  696.  
  697.  
  698. ! =====================  printInt  =====================
  699. ! external printInt (i: int)
  700. !
  701. ! This routine prints data directly and immediately to the output.  It is
  702. ! intended only for use in debugging the kernel.
  703. printInt:
  704.         load    [r15+4],r2        ! Move the argument "i" into r2
  705.         mov    1,r1            ! Move function code into r1
  706.         debug2                ! Do the upcall
  707.         ret                ! Return
  708.  
  709.  
  710.  
  711. ! =====================  printHex  =====================
  712. ! external printHex (i: int)
  713. !
  714. ! This routine prints data directly and immediately to the output.  It is
  715. ! intended only for use in debugging the kernel.
  716. !
  717. ! This routine will print the argument in the form "0x0012ABCD".
  718. printHex:
  719.         load    [r15+4],r2        ! Move the argument "i" into r2
  720.         mov    6,r1            ! Move function code into r1
  721.         debug2                ! Do the upcall
  722.         ret                ! Return
  723.  
  724.  
  725.  
  726. ! =====================  printChar  =====================
  727. ! external printChar (c: char)
  728. !
  729. ! This routine prints data directly and immediately to the output.  It is
  730. ! intended only for use in debugging the kernel.
  731. !
  732. ! This routine will print \n, \t, and any printable ASCII character.
  733. ! It will print \n as "\r\n".  It will print everything else in the form "\xHH".
  734. printChar:
  735.         loadb    [r15+4],r2        ! Move the argument "c" into r2
  736.         mov    3,r1            ! Move function code into r1
  737.         debug2                ! Do the upcall
  738.         ret                ! Return
  739.  
  740.  
  741.  
  742. ! =====================  printBool  =====================
  743. ! external printBool (b: bool)
  744. !
  745. ! This routine prints data directly and immediately to the output.  It is
  746. ! intended only for use in debugging the kernel.
  747. !
  748. ! This routine will print either "TRUE" or "FALSE".
  749. printBool:
  750.         loadb    [r15+4],r2        ! Move the argument "b" into r2
  751.         mov    5,r1            ! Move function code into r1
  752.         debug2                ! Do the upcall
  753.         ret                ! Return
  754.  
  755.  
  756.  
  757. ! =====================  printDouble  =====================
  758. ! external printDouble (d: double)
  759. !
  760. ! This routine prints data directly and immediately to the output.  It is
  761. ! intended only for use in debugging the kernel.
  762. !
  763. ! Thris routine will print the argument in one of these forms:
  764. !       1.23456e+22
  765. !       Not-a-number
  766. !       Positive-Infinity
  767. !       Negative-Infinity
  768. !       0
  769. !       Negative-Zero
  770. printDouble:
  771.         fload    [r15+4],f0        ! Move the argument "d" into f0
  772.         mov    4,r1            ! Move function code into r1
  773.         debug2                ! Do the upcall
  774.         ret                ! Return
  775.  
  776.  
  777.  
  778. ! =====================  _heapInitialize  =====================
  779. ! This routine is passed nothing and returns nothing.  It is called during
  780. ! startup to initialize the heap, as necessary.
  781. !
  782. ! This routine will perform an "upcall" to a routine written in KPL.
  783. !
  784. ! Registers modified: Same as any KPL function.
  785. !
  786. _heapInitialize:
  787.     jmp    _P_System_KPLMemoryInitialize
  788.  
  789.  
  790.  
  791. ! =====================  _heapAlloc  =====================
  792. ! This routine is passed the number of bytes in r1.  It allocates that many bytes
  793. ! and returns a pointer to the area in r1.  It never returns NULL.  If there is
  794. ! insufficient memory, an error will be signalled.
  795. !
  796. ! This routine is called from code generated by the compiler.  It will perform
  797. ! an "upcall" to a routine written in KPL.
  798. !
  799. ! Registers modified: Same as any KPL function.
  800. !
  801. _heapAlloc:
  802.     push    r1                ! Prepare the argument
  803.     call    _P_System_KPLMemoryAlloc    ! Perform the upcall
  804.     pop    r1                ! Retrieve the result
  805.     ret
  806.  
  807.  
  808.  
  809. ! =====================  _heapFree  =====================
  810. ! This routine is passed a pointer in r1.  This should point to a block of
  811. ! memory previously allocated using "malloc" (not "alloc").  It returns
  812. ! this memory to the free pool for subsequent allocation.
  813. !
  814. ! This routine is called from code generated by the compiler.  It will perform
  815. ! an "upcall" to a routine written in KPL.
  816. !
  817. ! Registers modified: Same as any KPL function.
  818. !
  819. _heapFree:
  820.     push    r1                ! Prepare the argument
  821.     call    _P_System_KPLMemoryFree        ! Perform the upcall
  822.     pop    r1                ! Pop the argument
  823.     ret
  824.  
  825.  
  826.  
  827. ! =====================  _IsKindOf  =====================
  828. ! This routine is passed a pointer to an object in r1 and a pointer to
  829. ! a type descriptor in r2.  It determines whether that object "is a kind of"
  830. ! that type.  It returns either TRUE (0x00000001) or FALSE (0x00000000) in r1.
  831. !
  832. ! This routine is called from code generated by the compiler.  It will perform
  833. ! an "upcall" to a routine written in KPL.
  834. !
  835. ! Registers modified: Same as any KPL function.
  836. !
  837. _IsKindOf:
  838.     push    r2                ! Push arg 2
  839.     push    r1                ! Push arg 1
  840.     call    _P_System_KPLIsKindOf        ! Perform the upcall
  841.     pop    r1                ! Pop result
  842.     pop    r2                ! Pop arg 2
  843.     ret
  844.  
  845.  
  846.  
  847. ! =====================  _RestoreCatchStack  =====================
  848. ! This routine is passed a pointer to a CatchRecord in r4 (possibly NULL).
  849. ! This is the previous value of "CatchStackTop".  This routine pops the
  850. ! CatchStack (calling _heapFree for each record) until the top thing on
  851. ! the CatchStack is the record pointed to by r4.
  852. !
  853. ! Registers modified: Same as any KPL function.
  854. !
  855. ! This routine is called from code generated by the compiler.  It does this:
  856. !
  857. !    <<  load   <temp>, r4    THIS IS DONE IN THE COMPILED CODE >>
  858. !        r1 := r12 (CatchStack top ptr)
  859. !        r12 := r4
  860. !    loop:
  861. !        if r1 == r4 goto done
  862. !        if r1 == NULL goto _runtimeErrorRestoreCatchStackError
  863. !                             This would occur if we are asked to pop
  864. !                             the catch stack back to an earlier
  865. !                             state, but after popping records, we never
  866. !                             can get to the earlier state.  This might
  867. !                             happen if there is a compiler logic error
  868. !                             or if memory has gotten corrupted.
  869. !        load   [r1], r2
  870. !        push   r2
  871. !        push   r4
  872. !        free   (r1)
  873. !        pop    r4
  874. !        pop    r1
  875. !        goto   loop
  876. !    done:
  877. !
  878. _RestoreCatchStack:
  879.     mov    r12,r1                ! r1 = saved value of CatchStack top
  880.     mov    r4,r12                ! Save r4 as new CatchStack top
  881. _RestoreCatchStack_loop:            ! LOOP:
  882.     cmp    r1,r4                !   if r1 == r4 goto DONE
  883.     be    _RestoreCatchStack_done        !   .
  884.     cmp    r1,0                !   if r1 == NULL goto error
  885.     be    _runtimeErrorRestoreCatchStackError  !
  886.     load    [r1], r2            !   r2 = r1->next 
  887.     push    r2                !   save ptr to next record
  888.     push    r4                !   save target ptr (r4)
  889.     call    _heapFree            !   free the record pointed to by r1
  890.     pop    r4                !   restore target ptr (r4)
  891.     pop    r1                !   r1 = ptr to next record
  892.     jmp    _RestoreCatchStack_loop        !   goto LOOP
  893. _RestoreCatchStack_done:            ! DONE:
  894.     ret                    !   return
  895.  
  896.  
  897.  
  898. ! =====================  _PerformThrow  =====================
  899. ! This routine is passed r4 = an ErrorID (just a ptr to an error name string).
  900. ! It looks down the Catch Stack until it finds a CATCH_RECORD with a matching
  901. ! ErrorID.  Then it jumps to the corresponding catch code, using the ptr stored
  902. ! in the CATCH_RECORD.  It also restores the FP and SP to their saved values,
  903. ! which makes it possible to re-enter the suspended routine.
  904. !
  905. ! This routine does not free any CATCH_RECORDS.
  906. !
  907. ! When an error is thown, but not caught, this code will perform an upcall to
  908. ! the routine "KPLUncaughtThrow" in package "System".  That routine
  909. ! should print some info about the situation and then throw "UncaughtError".
  910. ! Thus, we should never be returning from the call.  (The user code may or may
  911. ! not catch "UncaughtError", but if this too is uncaught, this code will goto
  912. ! "_runtimeErrorFatalThrowError".)
  913. !
  914. ! Registers modified: Same as any KPL function.
  915. !
  916. ! This routine is called from code generated by the compiler.  It does this:
  917. !
  918. !     << r4 = errorID    THIS IS DONE IN THE COMPILED CODE >>
  919. !        r1 = r12 (ptr to record on top of CATCH STACK)
  920. !    loop:
  921. !          if r1 == NULL
  922. !            if r4 == "uncaughtException" goto _runtimeErrorFatalThrowError
  923. !            call KPLUncaughtThrow
  924. !            goto _runtimeErrorThrowHandlerHasReturned
  925. !          end
  926. !          if r1->errorID == r4 then break
  927. !          r1 = r1->next
  928. !        goto loop
  929. !        restore FP from r1->oldFP
  930. !        restore SP from r1->oldSP
  931. !        jump to r1->catchCode
  932. !
  933. _PerformThrow:
  934.     mov    r12,r1                ! r1 = r12 (CatchStack top ptr)
  935. _PerformThrow_loop:                ! LOOP:
  936.     cmp    r1,0                !   if r1 == NULL
  937.     bne    _PerformThrow_else        !   .
  938.     set    _Error_P_System_UncaughtThrowError,r2 ! if r4 == "UncaughtThrowError"
  939.     cmp    r2,r4                !       .                
  940.     be    _runtimeErrorFatalThrowError    !       goto runtime error
  941.     load    [r14+-8],r1            !     Push ptr to current rout. desc.
  942.     push    r1                !     .
  943.     push    r13                !     Push the current line number
  944.     push    r4                !     Push ptr to error name
  945.     call    _P_System_KPLUncaughtThrow    !     call KPLUncaughtThrow
  946.     pop    r4                !     retore regs
  947.     pop    r13                !     .
  948.     pop    r1                !     .
  949.     jmp    _runtimeErrorThrowHandlerHasReturned  ! goto runtime error
  950. _PerformThrow_else:                !   end
  951.     load    [r1+4],r3            !   r3 = errorID of this record
  952.     cmp    r3,r4                !   if it matches r4
  953.     be    _PerformThrow_found        !     goto FOUND
  954.     load    [r1],r1                !   r1 = r1->next
  955.         jmp     _PerformThrow_loop        !   goto LOOP
  956. _PerformThrow_found:                ! FOUND:
  957.     load    [r1+8],r2            !   r2 = catch code ptr
  958.     load    [r1+12],r14            !   Restore FP
  959.     load    [r1+16],r6            !   Save the new SP in r6
  960.     jmp    r2                !   jump to catch code
  961.  
  962.