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 / UserRuntime.s < prev    next >
Text File  |  2007-09-19  |  27KB  |  834 lines

  1. ! KPL Programming Language Runtime Support Code
  2. !
  3. ! ==========  THIS VERSION IS TO SUPPORT USER PROGRAMS  ==========
  4. !
  5. ! Harry Porter  -  10/05/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 conventions.
  9. !
  10.     .export    TerminateWithError
  11.     .export    print
  12.     .export    printInt
  13.     .export    printHex
  14.     .export    printChar
  15.     .export    printBool
  16.     .export    printDouble
  17.     .export DoSyscall
  18.     .export    getCatchStack
  19.     .export    MemoryZero
  20.     .export    MemoryCopy
  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 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_UserSystem_UncaughtThrowError
  68. !
  69. ! Routines that should be implemented in KPL and called from here:
  70. !
  71.     .import _P_UserSystem_KPLSystemInitialize
  72.     .import _P_UserSystem_KPLMemoryAlloc
  73.     .import _P_UserSystem_KPLMemoryFree
  74.     .import _P_UserSystem_KPLUncaughtThrow
  75.     .import _P_UserSystem_KPLIsKindOf
  76. !
  77. ! This file invokes the "Exit" kernel syscall.  The following code is
  78. ! used to identify this syscall to the kernel.
  79. !
  80. SYSCALL_EXIT    =     1
  81.  
  82.  
  83.  
  84. !
  85. ! =====================  Program entry point  =====================
  86. !
  87. ! Prepare for KPL program execution.  We assume the stack pointer
  88. ! has been initialized.  Call the "main" function.  If the main routine
  89. ! routine returns, then we invoke the "Exit" syscall with an error code
  90. ! of 0.
  91. !
  92.     .text
  93. _entry:
  94.     call    _mainEntry        ! Call "_mainEntry"
  95.     mov    0,r1            ! Move arg1 = exit code into r1
  96.     syscall    SYSCALL_EXIT        ! Do the syscall
  97.     jmp    ProblemWithExitSyscall    ! The "exit" syscall should not return
  98.  
  99.  
  100.  
  101. !
  102. ! =====================  TerminateWithError  =====================
  103. !
  104. ! Come here after an error.  Invoke the "Exit" syscall with an error
  105. ! code of -2.  There is no return.
  106. !
  107. TerminateWithError:
  108.     mov    -2,r1            ! Move arg1 = exit code into r1
  109.     syscall    SYSCALL_EXIT        ! Do the syscall
  110. ProblemWithExitSyscall:            ! The "exit" syscall should not return
  111.     debug                ! .
  112.     jmp    ProblemWithExitSyscall    ! .
  113.  
  114.  
  115.  
  116. ! =====================  DoSyscall  =====================
  117. ! external DoSyscall (funCode, arg1, arg2, arg3, arg4: int) returns int
  118. !
  119. ! This routine is called by a user-mode program to do a syscall.  It is passed
  120. ! a function code to indicate which kernel function is required and up to 4
  121. ! arguments (of 32-bits each).  The kernel routine can return a 32-bit result.
  122. ! Normally, this routine is called by "wrapper" functions (such as "Sys_Read",
  123. ! "Sys_Write", "Sys_Join", "Sys_Exec", etc.) which are written in KPL.
  124. !
  125. ! [It might be nice to have a different version for each type of syscall;
  126. !  such routines would be slightly more efficient since each routine would
  127. !  only deal with the arguments it actually needed and could include the
  128. !  function code directly in the syscall instruction.]
  129. !
  130. DoSyscall:
  131.         load    [r15+8],r1        ! Move arg1 into r1
  132.         load    [r15+12],r2        ! Move arg2 into r2
  133.         load    [r15+16],r3        ! Move arg3 into r3
  134.         load    [r15+20],r4        ! Move arg4 into r4
  135.         load    [r15+4],r5        ! Move funcCode into r5
  136.         syscall    r5            ! Do the syscall
  137.         store    r1,[r15+4]        ! Move result from r1 onto stack
  138.         ret                ! Return
  139.  
  140.  
  141.  
  142. ! =====================  getCatchStack  =====================
  143. ! external getCatchStack () returns ptr to CATCH_RECORD
  144. !
  145. ! This routine returns the value of r12, which points to the Catch-Stack.
  146. ! The Catch-Stack is a linked list of CATCH_RECORDs, possibly NULL.
  147. !
  148. ! NOTE:  Whenever we leave the body statements in a try (i.e., fall-thru,
  149. !        throw, or return), records from the catch stack will be popped and
  150. !        freed.  "getCatchStack" returns a pointer to a list of CATCH_RECORDs
  151. !        as it is when "getCatchStack" is called, so watch out that the caller
  152. !        does not use records after they are freed.
  153. getCatchStack:
  154.         store    r12,[r15+4]        ! put r12 in the result position
  155.         ret                ! return
  156.  
  157.  
  158.  
  159. ! =====================  MemoryZero  =====================
  160. ! external MemoryZero (p, byteCount: int)
  161. !
  162. ! This function is passed "p" = an address, and "byteCount" = the number
  163. ! of bytes.  It sets that block of memory to all zeros.  The byteCount may
  164. ! be zero or negative, in which case this routine zeroes nothing.  This
  165. ! routine performs no other error checking.
  166. !
  167. ! Here is the algorithm:
  168. !
  169. !      while byteCount > 0 && p % 4 != 0
  170. !        *(p asPtrTo char) = '\x00'
  171. !        p = p + 1
  172. !        byteCount = byteCount - 1
  173. !      endWhile
  174. !      while byteCount > 3
  175. !        *(p asPtrTo int) = 0
  176. !        p = p + 4
  177. !        byteCount = byteCount - 4
  178. !      endWhile
  179. !      if byteCount == 3
  180. !        *(p asPtrTo char) = '\x00'
  181. !        *((p+1) asPtrTo char) = '\x00'
  182. !        *((p+2) asPtrTo char) = '\x00'
  183. !      elseIf byteCount == 2
  184. !        *(p asPtrTo char) = '\x00'
  185. !        *((p+1) asPtrTo char) = '\x00'
  186. !      elseIf byteCount == 1
  187. !        *(p asPtrTo char) = '\x00'
  188. !      endIf
  189. !
  190. ! Register usage:
  191. !   r1 = p
  192. !   r2 = byteCount
  193. !   r3 = work reg
  194. !
  195. MemoryZero:
  196.         load    [r15+4],r1        ! r1 = arg1 (p)
  197.         load    [r15+8],r2        ! r2 = arg2 (byteCount)
  198. mzLoop1:                    ! LOOP:
  199.         cmp    r2,0            !   if byteCount <= 0 exit
  200.         ble    mzLoop2Test        !   .
  201.         and    r1,0x00000003,r3    !   tmp = p % 4
  202.         cmp    r3,0            !   if tmp == 0 exit
  203.         be    mzLoop2Test        !   .
  204.         storeb    r0,[r1]            !   *p = 0x00
  205.         add    r1,1,r1            !   p = p + 1
  206.         sub    r2,1,r2            !   byteCount = byteCount - 1
  207.         jmp    mzLoop1            ! ENDLOOP
  208. !        jmp    mzLoop2Test        ! LOOP
  209. mzLoop2:                    ! .
  210.         store    r0,[r1]            !   *p = 0x00000000
  211.         add    r1,4,r1            !   p = p + 4
  212.         sub    r2,4,r2            !   byteCount = byteCount - 4
  213. mzLoop2Test:
  214.         cmp    r2,3            !   if byteCount > 3 then repeat
  215.         bg    mzLoop2            !   .
  216.  
  217.         cmp    r2,3            ! if byteCount == 3
  218.         bne    mzTry2            ! .
  219.         storeb    r0,[r1]            !   *p = 0x00
  220.         storeb    r0,[r1+1]        !   *(p+1) = 0x00
  221.         storeb    r0,[r1+2]        !   *(p+2) = 0x00
  222.         ret                !   return
  223. mzTry2:        cmp    r2,2            ! else if byteCount == 2
  224.         bne    mzTry1            ! .
  225.         storeb    r0,[r1]            !   *p = 0x00
  226.         storeb    r0,[r1+1]        !   *(p+1) = 0x00
  227.         ret                !   return
  228. mzTry1:        cmp    r2,1            ! else if byteCount == 1
  229.         bne    mzDone            ! .
  230.         storeb    r0,[r1]            !   *p = 0x00
  231. mzDone:                        ! endif
  232.         ret                ! return
  233.  
  234.  
  235.  
  236. ! =====================  MemoryCopy  =====================
  237. ! external MemoryCopy (destAddr, srcAddr, byteCount: int)
  238. !
  239. ! This routine copies "byteCount" bytes of data from the memory area pointed
  240. ! to by "srcPtr" to the area pointed to by "destPtr".  The pointers and the
  241. ! byteCount do not have to be multiples of 4 and the count may be less than
  242. ! zero, in which case, nothing will be copied.  However, the memory areas must
  243. ! not overlap!  (This routine does not test for overlap and if they overlap, the
  244. ! wrong data may be copied.)
  245. !
  246. ! Here is the algorithm:
  247. !
  248. !      if (destPtr asInteger % 4 == 0) && 
  249. !         (srcPtr asInteger % 4 == 0)
  250. !        while byteCount > 3
  251. !          *(destPtr asPtrTo int) = *(srcPtr asPtrTo int)
  252. !          destPtr = destPtr + 4
  253. !          srcPtr = srcPtr + 4
  254. !          byteCount = byteCount - 4
  255. !        endWhile
  256. !      endIf
  257. !      while byteCount > 0
  258. !        *(destPtr asPtrTo char) = *(srcPtr asPtrTo char)
  259. !        destPtr = destPtr + 1
  260. !        srcPtr = srcPtr + 1
  261. !        byteCount = byteCount - 1
  262. !      endWhile
  263. !
  264. ! Register usage:
  265. !   r1 = destPtr
  266. !   r2 = srcPtr
  267. !   r3 = byteCount
  268. !   r4 = work reg
  269. MemoryCopy:
  270.         load    [r15+4],r1        ! r1 = arg1 (destPtr)
  271.         load    [r15+8],r2        ! r2 = arg2 (srcPtr)
  272.         load    [r15+12],r3        ! r3 = arg3 (byteCount)
  273.         and    r1,0x00000003,r4    ! if destPtr % 4 == 0
  274.         bne    mcDoBytes        ! .
  275.         and    r2,0x00000003,r4    ! .   and srcPtr % 4 == 0
  276.         bne    mcDoBytes        ! .
  277. mcWordLoop:                    !   LOOP:
  278.         cmp    r3,3            !     if byteCount <= 3 exit loop
  279.         ble    mcWordLoopExit        !     .
  280.         pop    [r2++],r4        !     *destPtr = *(srcPtr++)
  281.         store    r4,[r1]            !     .
  282.         add    r1,4,r1            !     destPtr = destPtr + 4
  283.         sub    r3,4,r3            !     byteCount = byteCount - 4
  284.         jmp    mcWordLoop        !   ENDLOOP
  285. mcWordLoopExit:                    !   .
  286. mcDoBytes:                    ! endif
  287. mcByteLoop:                    ! LOOP
  288.         cmp    r3,0            !   if byteCount <= 0 exit loop
  289.         ble    mcByteLoopExit        !   .
  290.         loadb    [r2],r4            !   *destPtr = *srcPtr
  291.         storeb    r4,[r1]            !   .
  292.         add    r1,1,r1            !   destPtr = destPtr + 1
  293.         add    r2,1,r2            !   srcPtr = srcPtr + 1
  294.         sub    r3,1,r3            !   byteCount = byteCount - 1
  295.         jmp    mcByteLoop        ! ENDLOOP
  296. mcByteLoopExit:                    ! .
  297.         ret                ! return
  298.  
  299.  
  300.  
  301. ! =====================  print  =====================
  302. ! external print (s: ptr to array of char)
  303. !
  304. ! This routine prints data directly and immediately to the output.  It is
  305. ! intended only for use in debugging the kernel; as such it bypass the serial
  306. ! I/O device entirely and uses the debug2 "back-door" to the virtual machine.
  307. ! It may be called from any code, including from within an interrupt handler.
  308. !
  309. ! This routine will print \n, \t, and any printable ASCII characters.
  310. ! It will print \n as "\r\n".  It will print everything else in the form "\xHH".
  311. print:
  312.         load    [r15+4],r2        ! Move the argument "s" into r2
  313.         pop    [r2++],r3        ! Move the count into r3 and incr ptr
  314.         mov    2,r1            ! Move function code into r1
  315.         debug2                ! Do the upcall
  316.         ret                ! Return
  317.  
  318.  
  319.  
  320. ! =====================  printInt  =====================
  321. ! external printInt (i: int)
  322. !
  323. ! This routine prints data directly and immediately to the output.  It is
  324. ! intended only for use in debugging the kernel.
  325. printInt:
  326.         load    [r15+4],r2        ! Move the argument "i" into r2
  327.         mov    1,r1            ! Move function code into r1
  328.         debug2                ! Do the upcall
  329.         ret                ! Return
  330.  
  331.  
  332.  
  333. ! =====================  printHex  =====================
  334. ! external printHex (i: int)
  335. !
  336. ! This routine prints data directly and immediately to the output.  It is
  337. ! intended only for use in debugging the kernel.
  338. !
  339. ! This routine will print the argument in the form "0x0012ABCD".
  340. printHex:
  341.         load    [r15+4],r2        ! Move the argument "i" into r2
  342.         mov    6,r1            ! Move function code into r1
  343.         debug2                ! Do the upcall
  344.         ret                ! Return
  345.  
  346.  
  347.  
  348. ! =====================  printChar  =====================
  349. ! external printChar (c: char)
  350. !
  351. ! This routine prints data directly and immediately to the output.  It is
  352. ! intended only for use in debugging the kernel.
  353. !
  354. ! This routine will print \n, \t, and any printable ASCII character.
  355. ! It will print \n as "\r\n".  It will print everything else in the form "\xHH".
  356. printChar:
  357.         loadb    [r15+4],r2        ! Move the argument "c" into r2
  358.         mov    3,r1            ! Move function code into r1
  359.         debug2                ! Do the upcall
  360.         ret                ! Return
  361.  
  362.  
  363.  
  364. ! =====================  printBool  =====================
  365. ! external printBool (b: bool)
  366. !
  367. ! This routine prints data directly and immediately to the output.  It is
  368. ! intended only for use in debugging the kernel.
  369. !
  370. ! This routine will print either "TRUE" or "FALSE".
  371. printBool:
  372.         loadb    [r15+4],r2        ! Move the argument "b" into r2
  373.         mov    5,r1            ! Move function code into r1
  374.         debug2                ! Do the upcall
  375.         ret                ! Return
  376.  
  377.  
  378.  
  379. ! =====================  printDouble  =====================
  380. ! external printDouble (d: double)
  381. !
  382. ! This routine prints data directly and immediately to the output.  It is
  383. ! intended only for use in debugging the kernel.
  384. !
  385. ! Thris routine will print the argument in one of these forms:
  386. !       1.23456e+22
  387. !       Not-a-number
  388. !       Positive-Infinity
  389. !       Negative-Infinity
  390. !       0
  391. !       Negative-Zero
  392. printDouble:
  393.         fload    [r15+4],f0        ! Move the argument "d" into f0
  394.         mov    4,r1            ! Move function code into r1
  395.         debug2                ! Do the upcall
  396.         ret                ! Return
  397.  
  398.  
  399.  
  400. ! =====================  _putString  =====================
  401. ! This routine is passed r1 = a pointer to a string of characters, terminated
  402. ! by '\0'.  It prints all of them except the final '\0'.  The string is printed
  403. ! atomically by calling 'debug2'.
  404. !
  405. ! r1: ptr to string
  406. ! r2: ptr to string (saved version)
  407. ! r3: count
  408. ! r4: character 
  409. !
  410. ! Registers modified: none
  411. !
  412. _putString:
  413.     push    r1            ! save registers
  414.     push    r2            ! .
  415.     push    r3            ! .
  416.     push    r4            ! .
  417.     mov    r1,r2            ! r2 := ptr to the string
  418.     mov    0,r3            ! r3 := count of characters
  419. putStLoop:                ! loop
  420.     loadb    [r1],r4            !   r4 := next char
  421.     cmp    r4,0            !   if (r4 == '\0')
  422.     be    putStExit        !     then break
  423.     add    r1,1,r1            !   incr ptr
  424.     add    r3,1,r3            !   incr count
  425.     jmp    putStLoop        ! end
  426. putStExit:                ! .
  427.     mov    2,r1            ! perform upcall to emulator to
  428.     debug2                ! . do the printing
  429.     pop    r4            ! restore regs
  430.     pop    r3            ! .
  431.     pop    r2            ! .
  432.     pop    r1            ! .
  433.     ret                ! return
  434.  
  435.  
  436.  
  437. ! =====================  _heapInitialize  =====================
  438. ! This routine is passed nothing and returns nothing.  It is called during
  439. ! startup to initialize the heap and do other things, as necessary.
  440. !
  441. ! This routine will perform an "upcall" to a routine written in KPL.
  442. !
  443. ! Registers modified: Same as any KPL function.
  444. !
  445. _heapInitialize:
  446.     jmp    _P_UserSystem_KPLSystemInitialize
  447.  
  448.  
  449.  
  450. ! =====================  _heapAlloc  =====================
  451. ! This routine is passed the number of bytes in r1.  It allocates that many bytes
  452. ! and returns a pointer to the area in r1.  It never returns NULL.  If there is
  453. ! insufficient memory, an error will be signalled.
  454. !
  455. ! This routine is called from code generated by the compiler.  It will perform
  456. ! an "upcall" to a routine written in KPL.
  457. !
  458. ! Registers modified: Same as any KPL function.
  459. !
  460. _heapAlloc:
  461.     push    r1                    ! Prepare the argument
  462.     call    _P_UserSystem_KPLMemoryAlloc        ! Perform the upcall
  463.     pop    r1                    ! Retrieve the result
  464.     ret
  465.  
  466.  
  467.  
  468. ! =====================  _heapFree  =====================
  469. ! This routine is passed a pointer in r1.  This should point to a block of
  470. ! memory previously allocated using "malloc" (not "alloc").  It returns
  471. ! this memory to the free pool for subsequent allocation.
  472. !
  473. ! This routine is called from code generated by the compiler.  It will perform
  474. ! an "upcall" to a routine written in KPL.
  475. !
  476. ! Registers modified: Same as any KPL function.
  477. !
  478. _heapFree:
  479.     push    r1                    ! Prepare the argument
  480.     call    _P_UserSystem_KPLMemoryFree        ! Perform the upcall
  481.     pop    r1                    ! Pop the argument
  482.     ret
  483.  
  484.  
  485.  
  486. ! =====================  _IsKindOf  =====================
  487. ! This routine is passed a pointer to an object in r1 and a pointer to
  488. ! a type descriptor in r2.  It determines whether that object "is a kind of"
  489. ! that type.  It returns either TRUE (0x00000001) or FALSE (0x00000000) in r1.
  490. !
  491. ! This routine is called from code generated by the compiler.  It will perform
  492. ! an "upcall" to a routine written in KPL.
  493. !
  494. ! Registers modified: Same as any KPL function.
  495. !
  496. _IsKindOf:
  497.     push    r2                ! Push arg 2
  498.     push    r1                ! Push arg 1
  499.     call    _P_UserSystem_KPLIsKindOf    ! Perform the upcall
  500.     pop    r1                ! Pop result
  501.     pop    r2                ! Pop arg 2
  502.     ret
  503.  
  504.  
  505.  
  506. ! =====================  _RestoreCatchStack  =====================
  507. ! This routine is passed a pointer to a CatchRecord in r4 (possibly NULL).
  508. ! This is the previous value of "CatchStackTop".  This routine pops the
  509. ! CatchStack (calling _heapFree for each record) until the top thing on
  510. ! the CatchStack is the record pointed to by r4.
  511. !
  512. ! Registers modified: Same as any KPL function.
  513. !
  514. ! This routine is called from code generated by the compiler.  It does this:
  515. !
  516. !    <<  load   <temp>, r4    THIS IS DONE IN THE COMPILED CODE >>
  517. !        r1 := r12 (CatchStack top ptr)
  518. !        r12 := r4
  519. !    loop:
  520. !        if r1 == r4 goto done
  521. !        if r1 == NULL goto _runtimeErrorRestoreCatchStackError
  522. !                             This would occur if we are asked to pop
  523. !                             the catch stack back to an earlier
  524. !                             state, but after popping records, we never
  525. !                             can get to the earlier state.  This might
  526. !                             happen if there is a compiler logic error
  527. !                             or if memory has gotten corrupted.
  528. !        load   [r1], r2
  529. !        push   r2
  530. !        push   r4
  531. !        free   (r1)
  532. !        pop    r4
  533. !        pop    r1
  534. !        goto   loop
  535. !    done:
  536. !
  537. _RestoreCatchStack:
  538.     mov    r12,r1                ! r1 = saved value of CatchStack top
  539.     mov    r4,r12                ! Save r4 as new CatchStack top
  540. _RestoreCatchStack_loop:            ! LOOP:
  541.     cmp    r1,r4                !   if r1 == r4 goto DONE
  542.     be    _RestoreCatchStack_done        !   .
  543.     cmp    r1,0                !   if r1 == NULL goto error
  544.     be    _runtimeErrorRestoreCatchStackError  !
  545.     load    [r1], r2            !   r2 = r1->next 
  546.     push    r2                !   save ptr to next record
  547.     push    r4                !   save target ptr (r4)
  548.     call    _heapFree            !   free the record pointed to by r1
  549.     pop    r4                !   restore target ptr (r4)
  550.     pop    r1                !   r1 = ptr to next record
  551.     jmp    _RestoreCatchStack_loop        !   goto LOOP
  552. _RestoreCatchStack_done:            ! DONE:
  553.     ret                    !   return
  554.  
  555.  
  556.  
  557. ! =====================  _PerformThrow  =====================
  558. ! This routine is passed r4 = an ErrorID (just a ptr to an error name string).
  559. ! It looks down the Catch Stack until it finds a CATCH_RECORD with a matching
  560. ! ErrorID.  Then it jumps to the corresponding catch code, using the ptr stored
  561. ! in the CATCH_RECORD.  It also restores the FP and SP to their saved values,
  562. ! which makes it possible to re-enter the suspended routine.
  563. !
  564. ! This routine does not free any CATCH_RECORDS.
  565. !
  566. ! When an error is thown, but not caught, this code will perform an upcall to
  567. ! the routine "KPLUncaughtThrow" in package "System".  That routine
  568. ! should print some info about the situation and then throw "UncaughtError".
  569. ! Thus, we should never be returning from the call.  (The user code may or may
  570. ! not catch "UncaughtError", but if this too is uncaught, this code will goto
  571. ! "_runtimeErrorFatalThrowError".)
  572. !
  573. ! Registers modified: Same as any KPL function.
  574. !
  575. ! This routine is called from code generated by the compiler.  It does this:
  576. !
  577. !     << r4 = errorID    THIS IS DONE IN THE COMPILED CODE >>
  578. !        r1 = r12 (ptr to record on top of CATCH STACK)
  579. !    loop:
  580. !          if r1 == NULL
  581. !            if r4 == "uncaughtException" goto _runtimeErrorFatalThrowError
  582. !            call KPLUncaughtThrow
  583. !            goto _runtimeErrorThrowHandlerHasReturned
  584. !          end
  585. !          if r1->errorID == r4 then break
  586. !          r1 = r1->next
  587. !        goto loop
  588. !        restore FP from r1->oldFP
  589. !        restore SP from r1->oldSP
  590. !        jump to r1->catchCode
  591. !
  592. _PerformThrow:
  593.     mov    r12,r1                ! r1 = r12 (CatchStack top ptr)
  594. _PerformThrow_loop:                ! LOOP:
  595.     cmp    r1,0                !   if r1 == NULL
  596.     bne    _PerformThrow_else        !   .
  597.     set    _Error_P_UserSystem_UncaughtThrowError,r2 ! if r4 == "UncaughtThrowError"
  598.     cmp    r2,r4                !       .                
  599.     be    _runtimeErrorFatalThrowError    !       goto runtime error
  600.     load    [r14+-8],r1            !     Push ptr to current rout. desc.
  601.     push    r1                !     .
  602.     push    r13                !     Push the current line number
  603.     push    r4                !     Push ptr to error name
  604.     call    _P_UserSystem_KPLUncaughtThrow    !     call KPLUncaughtThrow
  605.     pop    r4                !     retore regs
  606.     pop    r13                !     .
  607.     pop    r1                !     .
  608.     jmp    _runtimeErrorThrowHandlerHasReturned  ! goto runtime error
  609. _PerformThrow_else:                !   end
  610.     load    [r1+4],r3            !   r3 = errorID of this record
  611.     cmp    r3,r4                !   if it matches r4
  612.     be    _PerformThrow_found        !     goto FOUND
  613.     load    [r1],r1                !   r1 = r1->next
  614.         jmp     _PerformThrow_loop        !   goto LOOP
  615. _PerformThrow_found:                ! FOUND:
  616.     load    [r1+8],r2            !   r2 = catch code ptr
  617.     load    [r1+12],r14            !   Restore FP
  618.     load    [r1+16],r6            !   Save the new SP in r6
  619.     jmp    r2                !   jump to catch code
  620.  
  621.  
  622.  
  623. ! =====================  KPL Runtime Error Handlers  =====================
  624. _runtimeErrorOverflow:
  625.     set    ErrorMess1,r1        ! Print an error message
  626.     jmp    printRuntimeError    ! .  and terminate all execution
  627.  
  628. _runtimeErrorZeroDivide:
  629.     set    ErrorMess2,r1        ! Print an error message
  630.     jmp    printRuntimeError    ! .  and terminate all execution
  631.  
  632. _runtimeErrorNullPointer:
  633.     set    ErrorMess3,r1        ! Print an error message
  634.     jmp    printRuntimeError    ! .  and terminate all execution
  635.  
  636. _runtimeErrorUninitializedObject:
  637.     set    ErrorMess4,r1        ! Print an error message
  638.     jmp    printRuntimeError    ! .  and terminate all execution
  639.  
  640. _runtimeErrorWrongObject:
  641.     set    ErrorMess5,r1        ! Print an error message
  642.     jmp    printRuntimeError    ! .  and terminate all execution
  643.  
  644. _runtimeErrorWrongObject2:
  645.     set    ErrorMess6,r1        ! Print an error message
  646.     jmp    printRuntimeError    ! .  and terminate all execution
  647.  
  648. _runtimeErrorWrongObject3:
  649.     set    ErrorMess7,r1        ! Print an error message
  650.     jmp    printRuntimeError    ! .  and terminate all execution
  651.  
  652. _runtimeErrorBadObjectSize:
  653.     set    ErrorMess8,r1        ! Print an error message
  654.     jmp    printRuntimeError    ! .  and terminate all execution
  655.  
  656. _runtimeErrorDifferentArraySizes:
  657.     push    r1            ! save r1 and r3
  658.     push    r3            ! .  so the user can look at them
  659.     set    ErrorMess9,r1        ! print the error message
  660.     call    _putString        ! .
  661.     pop    r3            ! restore r1 and r3
  662.     pop    r1            ! .
  663.     jmp    TerminateWithError    ! Can't continue: invoke "debug"
  664.  
  665. _runtimeErrorWrongArraySize:
  666.     push    r1            ! save r1 and r2
  667.     push    r2            ! .  so the user can look at them
  668.     set    ErrorMess10,r1        ! print the error message
  669.     call    _putString        ! .
  670.     pop    r2            ! restore r1 and r2
  671.     pop    r1            ! .
  672.     jmp    TerminateWithError    ! terminate all execution
  673.  
  674. _runtimeErrorUninitializedArray:
  675.     set    ErrorMess11a,r1        ! Print an error message
  676.     jmp    printRuntimeError    ! .  and terminate all execution
  677.  
  678. _runtimeErrorBadArrayIndex:
  679.     push    r2            ! save r2 so the user can look at it
  680.     set    ErrorMess11,r1        ! print the error message
  681.     call    _putString        ! .
  682.     pop    r2            ! restore r2
  683.     jmp    TerminateWithError    ! terminate all execution
  684.  
  685. _runtimeErrorNullPointerDuringCall:
  686.     set    ErrorMess12,r1        ! Print an error message
  687.     jmp    printRuntimeError    ! .  and terminate all execution
  688.  
  689. _runtimeErrorArrayCountNotPositive:
  690.     push    r1            ! save r1 so the user can look at it
  691.     set    ErrorMess13,r1        ! print the error message
  692.     call    _putString        ! .
  693.     pop    r1            ! restore r1
  694.     jmp    TerminateWithError    ! terminate all execution
  695.  
  696. _runtimeErrorRestoreCatchStackError:
  697.     set    ErrorMess14,r1        ! Print an error message
  698.     jmp    printRuntimeError    ! .  and terminate all execution
  699.  
  700. _runtimeErrorThrowHandlerHasReturned:
  701.     set    ErrorMess15,r1        ! Print an error message
  702.     jmp    printRuntimeError    ! .  and terminate all execution
  703.  
  704. _runtimeErrorFatalThrowError:
  705.     set    ErrorMess16,r1        ! Print an error message
  706.     jmp    printRuntimeError    ! .  and terminate all execution
  707.  
  708. _runtimeErrorInterruptsEnabled:
  709.     set    ErrorMess17,r1        ! Print an error message
  710.     jmp    printRuntimeError    ! .  and terminate all execution
  711.  
  712.  
  713. ErrorMess1:
  714.     .ascii    "\nUser Program Error: Arithmetic overflow has occurred!  Type 'st' to see stack.\n\0"
  715. ErrorMess2:
  716.     .ascii    "\nUser Program Error: Divide-by-zero has occurred!  Type 'st' to see stack.\n\0"
  717. ErrorMess3:
  718.     .ascii    "\nUser Program Error: Attempt to use a null pointer!  Type 'st' to see stack.\n\0"
  719. ErrorMess4:
  720.     .ascii    "\nUser Program Error: Attempt to use an uninitialized object!  Type 'st' to see stack.\n\0"
  721. ErrorMess5:
  722.     .ascii    "\nUser Program 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"
  723. ErrorMess6:
  724.     .ascii    "\nUser Program 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"
  725. ErrorMess7:
  726.     .ascii    "\nUser Program 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"
  727. ErrorMess8:
  728.     .ascii    "\nUser Program Error: During an object assignment or object equality test, something is wrong with the dispatch table pointer, the dispatch table, "
  729.     .ascii   "or the class descriptor; the size of the object is less than 4!  Type 'st' to see stack.\n\0"
  730. ErrorMess9:
  731.     .ascii    "\nUser Program Error: User Program Error: During an array copy, the two arrays have different sizes  (r1=target size, r3=source size)!  Type 'st' to see stack.\n\0"
  732. ErrorMess10:
  733.     .ascii    "\nUser Program 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"
  734. ErrorMess11:
  735.     .ascii    "\nUser Program 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"
  736. ErrorMess11a:
  737.     .ascii    "\nUser Program Error: Attempt to use an uninitialized array!  Type 'st' to see stack.\n\0"
  738. ErrorMess12:
  739.     .ascii    "\nUser Program Error: During the invocation of a nameless function, the function pointer was null!  Type 'st' to see stack.\n\0"
  740. ErrorMess13:
  741.     .ascii    "\nUser Program Error: During the initialization of an array, a 'count' expression was zero or less (r1=count)!  Type 'st' to see stack.\n\0"
  742.     .align
  743. ErrorMess14:
  744.     .ascii    "\nUser Program Error: While popping the Catch Stack, an error has occurred!  Type 'st' to see stack.\n\0"
  745. ErrorMess15:
  746.     .ascii    "\nUser Program Error: Attempt to return from KPLUncaughtThrow!  Type 'st' to see stack.\n\0"
  747. ErrorMess16:
  748.     .ascii    "\nUser Program Error: Error 'UncaughtThrowError' has been thrown but not caught!  Type 'st' to see stack.\n\0"
  749. ErrorMess17:
  750.     .ascii    "\nUser Program Error: Attempt to perform serial I/O while interrupts are not disabled!  Type 'st' to see stack.\n\0"
  751.     .align
  752.  
  753.  
  754.  
  755. ! =====================  printRuntimeError  =====================
  756. !
  757. ! Come here to print a runtime error message and die.
  758. ! On entry, r1 points to the message.
  759. !
  760. printRuntimeError:
  761.     call    _putString        ! Print the message
  762.     jmp    TerminateWithError    ! Jump to the termination code
  763.  
  764.  
  765. !
  766. ! Misc Floating-Point Constants
  767. !
  768. _PosInf:
  769.     .word    0x7ff00000
  770.     .word    0x00000000
  771. _NegInf:
  772.     .word    0xfff00000
  773.     .word    0x00000000
  774. _NegZero:
  775.     .word    0x80000000
  776.     .word    0x00000000
  777.  
  778.  
  779.  
  780. !
  781. ! Name of this file
  782. !
  783. SourceFileName:
  784.     .ascii    "UserRuntime.s\0"
  785.     .align
  786.  
  787.  
  788.