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 / p5 / Runtime.s < prev    next >
Text File  |  2007-09-19  |  38KB  |  1,271 lines

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