home *** CD-ROM | disk | FTP | other *** search
/ Millennium Time Capsule / AC2000.BIN / disks / ac7_disk / fix_fpu / fix_fpu.txt < prev   
Text File  |  1997-09-19  |  10KB  |  254 lines

  1. Pure C isn't
  2.  
  3. If you have an Atari ST which has been upgraded with a 68882 maths 
  4. co-processor (FPU) you may have run into problems using programs 
  5. compiled with Pure C or Pure Pascal.
  6. The Pure C/Pascal compilers insert code in a program to detect the 
  7. presence of an FPU and to use it if it is there.
  8. On 68020/68030 equipped machines it calls subroutines written in FPU 
  9. machine code but on a 68000 equipped machine it has to use subroutines 
  10. which emulate the CPU/FPU communication protocol built into the 68020 
  11. and later chips.
  12.  
  13. The problem is that the code in Pure C/Pascal is not a true emulation 
  14. of that protocol. The CPU should read a response from the FPU and react 
  15. as requested, but the emulation code waits for an expected response and 
  16. does nothing until it gets it. The 68882 in many cases gives a 
  17. different response from that given by the 68881. This is because the 
  18. 68882 is 'pipelined'. It divides the execution of an floating point 
  19. instruction into an interpretation/addressing phase and a calculation 
  20. phase and is prepared to release the CPU to process in parallel with it 
  21. at the end of the first phase.
  22.  
  23. The following programs have been tested and appear to work OK:
  24.  
  25. - Pre v1.5 versions of CAB. CAB was doing floating point calculations, 
  26.   (although Alexander denies it).
  27. - Kandinsky: Contains 5 subroutines to be patched.
  28. - HDDriver Utility program (partitioning won't work without the patch)
  29. - DAVector (demo version)
  30. - Zorg registered version (the un-registered version appears to unpack
  31.   itself at run-time - in any case this patching program won't fix it)
  32. - Five-to-Five
  33. - Gemview v2.24 (and maybe other versions).
  34. - Atari CD Master from Homa Systems House (INFOPEDI.PRG and 
  35.   PLAYSND.PRG)
  36.  
  37. The patch program may well work on other problem programs but neither I 
  38. nor Atari Computing accept any liability or responsibility for any 
  39. direct or indirect damage that may arise, either financial, material or 
  40. any other kind from either the use or misuse of this software and 
  41. associated documentation. All trademarks used are recognised and 
  42. acknowledged.
  43.  
  44. The following is a dissassembly of the standard Pure C FPU subroutine 
  45. for operations between two floating point inputs. The entry to the code 
  46. is at line 3. On entry a0 and a1 point to two floating point operands 
  47. in memory and d2 contains the opcode for the FPU instruction to be 
  48. executed.
  49.  
  50. 1   l0  move.w #3,-14(a2)   ; reset FPU (doesn't clear interrupts on
  51.                                         68882)
  52. 2       movea.l d1,a2       ; restore saved a2 - see line 4
  53.  
  54. 3       moveq #$7F,d0       ; set time-out value
  55.                             ; **** entry point of subroutine ****
  56. 4       move.l a2,d1        ; save a2
  57. 5       lea -$5B0,a2        ; address of FPU operand register
  58. 6   l1  cmpi.w #$802,-16(a2) ; read FPU status - $802 means FPU idle
  59. 7       dbeq d0,l1          ; wait for idle
  60. 8       move.w #$4800,-6(a2) ; opcode - CPU tells FPU to accept an 
  61.                              ; floating point number
  62. 9   l2  cmpi.w #$960C,-16(a2) ; FPU asks CPU to pass it 12 bytes
  63. 10      dbeq d0,l2          ; wait for response
  64. 11      move.l (a0),(a2)    ; a0 points to first floating point number 
  65.                             ; in memory
  66. 12      move.l 2(a0),(a2)   ; Pure C packs floating point number into 
  67.                             ; 10 bytes
  68. 13      move.l 6(a0),(a2)   ; last 4 bytes of floating point number
  69. 14  l3  cmpi.w #$802,-16(a2) ; read FPU status again
  70. 15      dbeq d0,l1          ; wait for idle
  71. 16      move.w d2,-6(a2)    ; pass opcode to FPU
  72. 17  l4  cmpi.w #$960C,-16(a2) ; FPU asks CPU to pass it 12 bytes
  73. 18      dbeq d0,l4          ; wait for response
  74. 19      move.l (a1),(a2)    ; a1 points to second floating point number 
  75.                             ; in memory
  76. 20      move.l 2(a1),(a2)
  77. 21      move.l 6(a1),(a2)   ; last 4 bytes of floating point number
  78. 22  l5  cmpi.w #$802,-16(a2) ; read FPU status again
  79. 23      dbeq d0,l5          ; wait for idle
  80. 24      move.w #$6800,-6(a2) ; CPU asks FPU to hand over result
  81. 25  l6  cmpi.w #$B20C,-16(a2) ; FPU asks CPU to store 12 bytes
  82. 26      dbeq d0,l6          ; wait for response
  83. 27      BNE.S l0            ; try again if failed
  84. 28      move.l (a2),(a0)    ; store result
  85. 29      move.l (a2),2(a0)
  86. 30      move.l (a2),6(a0)
  87. 31      movea.l d1,a2       ; restore a2
  88. 32      rts                 ; and exit
  89.  
  90. The responses looked for at lines 9, 17 and 25 have meanings bit by 
  91. bit. For example, the C at the end of $960C does ask for 12 bytes. 
  92. However, the bit of interest is the msb, called the 'come again' bit.
  93. The 68881 wants the CPU to check with it again so it has that bit set, 
  94. giving $960C, whereas the 68882 responds with $160C at both lines 9 and 
  95. 17.  At line 25 the 68882 will respond with $320C EXCEPT when the 
  96. operation creates an exception, such as division by zero, when it 
  97. responds with $B20C, as does the 68881 at all times.
  98.  
  99. Note that checking for the incorrect response does not of itself 
  100. prevent the program from working on the 68882. The DBEQ loops at l2, l4 
  101. and l6 will terminate and the program will run, although slowly. It is 
  102. the test at line 27 that is the killer. Because the preceeding dbeq has 
  103. cleared the zero bit, the branch will be taken and the code goes into 
  104. an infinite loop, which is how the program dies.
  105.  
  106. The code can be made to work on both a 68881 and 68882 simply by 
  107. replacing the BNE.S l0 ($668E) with an NOP ($4E71) but it will run 
  108. considerably faster on a 68881. If the two occurrences of $960C are 
  109. changed to $160C and the $B20C to $320C the 68882 will have the 
  110. advantage.
  111.  
  112. Most Pure C or Pascal programs contain several similar subroutines, one 
  113. for each type of calculation that floating point numbers are involved 
  114. in, in those programs. Each requires patching.
  115.  
  116. Ideally, programmers doing floating point calculations in Pure C or
  117. Pure Pascal should modify the library code so that the FPU response is 
  118. read into a CPU register and the msb masked off or set before testing.
  119. Then the code would run reasonably quickly on either chip.
  120.  
  121. Fix FPU
  122. -------
  123. Here's a HiSoft BASIC listing for FIX_FPU.PRG a program which patches 
  124. another program complied using either PURE C or PURE PASCAL so it will 
  125. run on an Atari equipped with a 68000 and 68882 FPU.
  126. The FPU support code in both Pure C and Pure Pascal appears identical 
  127. in both compilers.
  128.  
  129. No guarantee is offered that the information in this distribution is 
  130. correct but if you do find any mistakes let me know and I'll do my best 
  131. to put them right!
  132.  
  133. Contact
  134. -------
  135. David Leaver
  136. 10 Goodparla St,
  137. Hawker, ACT 2614
  138. Australia
  139.  
  140. Email: leaver@netinfo.com.au
  141.  
  142. Notes concerning the program listing
  143. ------------------------------------
  144. The odd bit of code around the call to dgetpath is there because, as 
  145. far as I can tell, the library routine doesn't work as documented.  It 
  146. wants the buffer address and returns a TOS/C style string rather than a 
  147. BASIC string.
  148.  
  149. ---
  150. LIBRARY "gemdos", "gemaes"
  151.  
  152.  
  153. ? "PurePatch patches programs complied using either"
  154. ? "PURE C or PURE PASCAL so that it will run on an"
  155. ? "Atari equipped with a 68000 and 68882"
  156. ? : ?
  157. ? "     ******** WARNING *********"
  158. ?
  159. ? "The input file is overwritten - if you have not"
  160. ? "backed it up, choose CANCEL at the file selector"
  161. ? : ?
  162. ? "Press a key to continue"
  163. while inkey$ = ""
  164. wend
  165. drive$ = CHR$(FNdgetdrv% + 65)
  166. path$ = "" : filename$ = ""
  167. for i% = 1 to 128 : path$ = path$ + CHR$(0) : next i%
  168. dgetpath sadd(path$) , 0
  169. fullpath$ = drive$ + ":"
  170. i% = 1
  171. temp$ = mid$(path$,i%,1)
  172. while ASC(temp$) <> 0
  173.   fullpath$ = fullpath$ + temp$
  174.   i% = i% +1
  175.   temp$ = MID$(path$,i%,1)
  176. wend
  177. fullpath$ = fullpath$ + "\*.*"
  178. fsel_input  fullpath$,  filename$,  ok%
  179. if ok% = 0 then end
  180. clearw 2
  181. ? "Patching ";filename$
  182. ? : ? "could take a minute ot two........"
  183. drive$ = LEFT$(fullpath$,1)
  184. fullpath$ = MID$(fullpath$,3,128)
  185. i% = LEN(fullpath$)
  186. while RIGHT$(fullpath$,1) <> "\"
  187.    i% = i%-1
  188.    fullpath$ = LEFT$(fullpath$, i%)
  189. wend
  190. drivemap% = FNdsetdrv%(ASC(drive$)-65)
  191. if FNdsetpath%(fullpath$)<>0 THEN
  192.    ? " Error in setting path : "; fullpath$
  193.    end
  194. end if
  195. handle% = FNfopen%(filename$,2)
  196. if handle% < 0 then
  197.    ? " Error opening file - # "; handle%
  198.    end
  199. end if
  200. buffer$ = CHR$(0)
  201. repeat readloop
  202.   readbyte read&, byte%
  203.   if read& = 0 then exit readloop
  204.   if byte% = 12 then call patch
  205. end repeat readloop
  206. ok% = FNfclose%(handle%)
  207. end
  208.  
  209. SUB readbyte(n&, byte%)
  210. SHARED handle%
  211. buffer$ = CHR$(0)
  212. n& = FNfread&(handle%,1,sadd(buffer$))
  213. byte% = ASC(buffer$)
  214. end SUB
  215.  
  216. SUB writebyte(byte%)
  217. SHARED handle%
  218. buffer$ = CHR$(byte%)
  219. n& = FNfwrite&(handle%,1,sadd(buffer$))
  220. end SUB
  221.  
  222. SUB patch
  223. SHARED handle%
  224. readbyte n&, byte%
  225. if n& = 1 then
  226.    if byte% = 106 or byte% = 105 then
  227.       readbyte n&, byte1%
  228.       if n& = 1 then readbyte n&, byte2%
  229.       if n& = 1 then readbyte n&, byte3%
  230.       if n& = 1 then readbyte n&, byte4%
  231.       if n& = 1 and byte3% = 255 and byte4% = 240 then
  232.          if byte1% = 150 and byte2% = 12 then
  233.             ok& = FNfseek&(-4, handle%, 1)
  234.             writebyte 22
  235.          elseif byte1% = 178 and byte2% = 12 then
  236.             ok& = FNfseek&(-4, handle%, 1)
  237.             writebyte 50
  238.             ok& = FNfseek&(7, handle%, 1)
  239.             if ok& >= 0 then
  240.                readbyte n&, byte%
  241.                if byte% = 102 then
  242.                   ok& = FNfseek&(-1, handle%, 1)
  243.                   writebyte 78
  244.                   writebyte 113
  245.                end if
  246.             end if
  247.          end if
  248.       end if
  249.    end if
  250. end if
  251. end sub
  252. ---
  253. EOF
  254.