rtdrv.s 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626
  1. # rtdrv.s -- call runtime entries, with known arguments, and report what
  2. # happened. Assembled by tests/rt_exec.py into a complete .COM image.
  3. #
  4. # This replaces the Unicorn harness. The expectations did not change; only the
  5. # machine did. Everything here exists because qemu, unlike an emulator with a
  6. # Python API, gives you one thing: a serial port. So a check has to be
  7. # expressed as a program that reports on itself.
  8. #
  9. # The report is a framed record on the serial port:
  10. #
  11. # 01 <case index, 2 hex digits> 02 <whatever the entries printed> 03
  12. # <dumplen bytes at dumpaddr, 2 hex digits each> 04
  13. #
  14. # The four control bytes occur in no expected output, and rt_exec.py REFUSES to
  15. # run a case whose expectation contains one -- so a marker can never be mistaken
  16. # for output, and a driver that emitted nothing is a parse failure rather than
  17. # a silent pass.
  18. #
  19. # Why one qemu boot per check instead of one boot for all of them: the runtime
  20. # keeps state that outlives a call -- the one-character pushback slot, and the
  21. # input cursor the boot sector's INT 21h shim owns. One boot for everything
  22. # would make each check depend on the ones before it, so a check could fail
  23. # because of its neighbour and a green run would prove less than it appears to.
  24. # A boot costs about a tenth of a second and 35 of them cost under four, which
  25. # buys every check a machine that has provably never executed anything. (The
  26. # input descriptor is still re-armed on every boot, because it lives in the
  27. # image and the image is the same bytes each time.)
  28. #
  29. # Two things about the 8086 shape the code below, and both were found by
  30. # running it rather than by reading it:
  31. #
  32. # * Every entry preserves BP and SP and NO other register. So the cursor
  33. # into the case record is BP: a loop counter in CX or DI would be destroyed
  34. # by the first call. The entry's own BP frame is pushed and restored, so
  35. # our BP comes back.
  36. #
  37. # * `movb n(%bp), %cl' leaves the HIGH byte of CX exactly as it was. Reading
  38. # the input length that way and then writing CX to INLEN handed the boot
  39. # sector's INT 21h shim a 16-bit length with an undefined top half. The
  40. # 8086 has no memory-to-memory move and no zero-extending byte load, so the
  41. # high half has to be cleared by hand, every time.
  42. #
  43. # * `dec' sets the sign flag from the RESULT, so `decw cnt / js done' runs the
  44. # body for cnt = 1 (1 -> 0, SF clear) and stops on the wrap (0 -> FFFF).
  45. # It reads like an off-by-one and is not; the comment at the loop says so
  46. # again because the next person will wonder.
  47. #
  48. # The image is assembled in ONE piece, here, so every address is a label or an
  49. # .org and nothing has to be agreed with Python in two places. What Python does
  50. # have to agree about -- the runtime's base, and the input descriptor -- is
  51. # checked rather than trusted: it assembles this file and then asserts that the
  52. # blob it got from RtProbe really is at RT_BASE in the bytes that came out.
  53. .set LOAD_BIAS, 0x0100 # a .COM lives at CS:0100 (that is the PSP)
  54. .set SOH, 0x01
  55. .set STX, 0x02
  56. .set ETX, 0x03
  57. .set EOT, 0x04
  58. # Restated from tests/exec/bootcom.s's layout block ON PURPOSE. A harness that
  59. # asks the boot sector where its input buffer is proves only that the two agree
  60. # with each other; two independent statements of the same layout have to be
  61. # written down, and a disagreement is a loud failure rather than a program that
  62. # is fed nothing. (Same reasoning, and the same lesson, as the hard-coded
  63. # RT_SZ that run_com_tests.sh used to carry: the descriptor has to be where the
  64. # shim looks, and the only way to be sure is to have written both down and
  65. # checked.)
  66. .set INLEN, 0x7000 # word: how many input bytes follow
  67. .set INCUR, 0x7002 # word: index into INBUF, NOT an address
  68. .set INBUF, 0x7004 # the bytes themselves
  69. # The case record, as rt_exec.py writes it. These offsets are the contract; the
  70. # two places that read them (this file, and case_bytes() over there) are
  71. # separate statements of it on purpose, and the cases only pass if both are
  72. # right. SLOT0 is the one that was wrong the first time round.
  73. .set OFF_DUMPLEN, 0 # word how many bytes to report
  74. .set OFF_DUMPADR, 2 # word image offset to report them from
  75. .set OFF_INLEN, 4 # byte bytes of input to hand the shim
  76. .set OFF_INBUF, 5 # byte inbuf[8]
  77. .set OFF_CASE, 13 # word the index printed in the header (4 hex digits)
  78. .set OFF_NCALLS, 15 # byte how many call slots follow
  79. .set SLOT0, 16 # call slots, 12 bytes each:
  80. # +0 word entry, +2 word arg A,
  81. # +4 byte flags, +5 pad,
  82. # +6 word arg B, +8 word CX,
  83. # +10 pad
  84. .set SLOT_SZ, 12
  85. .set CASE_SZ, 64 # 16 + 4 slots
  86. # The image layout. RT_BASE is where the runtime blob goes; everything else is
  87. # above 0x0800 so that a runtime which grew by a few hundred bytes would not
  88. # silently run into the test scaffolding. rt_exec.py asserts
  89. # RT_BASE + blob size <= HDR, so the bound is a checked one.
  90. .set RT_BASE, 0x0190
  91. .set HDR, 0x4000
  92. .set FMTDEST, DSHIFT+0x2430 # 64-byte destination for real_fmt
  93. .set ASCSRC, DSHIFT+0x2470 # ASCIIZ sources for real_val
  94. .set DATA, 0x5000
  95. .set DSHIFT, 0x2EF0
  96. .set DLEN, 32 # bytes of data area for initmem to clear
  97. .set STORE, DSHIFT+0x2140 # where a read entry's result is stored
  98. .set WSTR, DSHIFT+0x2150 # a string for the wrstr case: length + chars
  99. .set WSTR_EMPTY, DSHIFT+0x2158 # the same, with a length of 0
  100. .set CASE, DSHIFT+0x2160 # the case record
  101. .set D_DUMPLEN, DSHIFT+0x21a0 # the driver's own three words
  102. .set D_DUMPADR, DSHIFT+0x21a2
  103. .set D_CNT, DSHIFT+0x21a4
  104. .set D_AX, DSHIFT+0x21a6 # last call's AX, for the comparison cases
  105. .set RDSTR_DST, DSHIFT+0x21b0 # destination for the rdstr cases
  106. .set SST_HELLO, DSHIFT+0x21c0 # a short source string for strstore
  107. .set SST_LONG, DSHIFT+0x21d0 # a source longer than a small max
  108. .set SST_EMPTY, DSHIFT+0x21e0 # an empty source string
  109. .set SST_DST, DSHIFT+0x21f0 # destination for the strstore cases
  110. .set SST_CAT, DSHIFT+0x2200 # destination for the strcat cases, with a
  111. # length to append to -- unlike SST_DST,
  112. # which strstore overwrites
  113. .set SST_CAT0, DSHIFT+0x2210 # ...and one that starts empty
  114. .set SST_WORLD, DSHIFT+0x2220 # a source distinct from SST_HELLO
  115. .set R_BLK1, DSHIFT+0x2230
  116. .set R_BLK2, DSHIFT+0x2240
  117. .set R_BLK3, DSHIFT+0x2250
  118. .set R_BLK4, DSHIFT+0x2260
  119. .set R_BLK5, DSHIFT+0x2270
  120. .set R_BLK6, DSHIFT+0x2280
  121. .set R_BLK7, DSHIFT+0x2290
  122. .set R_BLK8, DSHIFT+0x22a0
  123. .set R_BLK9, DSHIFT+0x22b0
  124. .set R_BLK10, DSHIFT+0x22c0
  125. .set R_BLK11, DSHIFT+0x22d0
  126. .set R_BLK12, DSHIFT+0x22e0
  127. .set R_BLK13, DSHIFT+0x22f0
  128. .set R_BLK14, DSHIFT+0x2300
  129. .set R_BLK15, DSHIFT+0x2310
  130. .set R_BLK16, DSHIFT+0x2320
  131. .set R_BLK17, DSHIFT+0x2330
  132. .set R_BLK18, DSHIFT+0x2340
  133. .set R_BLK19, DSHIFT+0x2350
  134. .set R_BLK20, DSHIFT+0x2360
  135. .set R_BLK21, DSHIFT+0x2370
  136. .set R_BLK22, DSHIFT+0x2380
  137. .set R_BLK23, DSHIFT+0x2390
  138. .set R_BLK24, DSHIFT+0x23a0
  139. .set R_BLK25, DSHIFT+0x23b0
  140. .set R_BLK26, DSHIFT+0x23c0
  141. .set R_BLK27, DSHIFT+0x23d0
  142. .set R_BLK28, DSHIFT+0x23e0
  143. .set R_BLK29, DSHIFT+0x23f0
  144. .set R_BLK30, DSHIFT+0x2400
  145. .set R_BLK31, DSHIFT+0x2410
  146. .set R_BLK32, DSHIFT+0x2500
  147. .set R_BLK33, DSHIFT+0x2510
  148. .set R_BLK34, DSHIFT+0x2520
  149. .set R_BLK35, DSHIFT+0x2530
  150. .set R_BLK36, DSHIFT+0x2540
  151. .set FILEBLK, DSHIFT+0x2a00 # the 132-byte file control block
  152. .set SETA, DSHIFT+0x2580
  153. .set SETB, DSHIFT+0x2590
  154. .set SETC, DSHIFT+0x25a0
  155. .set SETD, DSHIFT+0x25b0
  156. .set SET2A, DSHIFT+0x25c0
  157. .set SET2B, DSHIFT+0x25d0
  158. .set SET2D, DSHIFT+0x25e0
  159. .code16
  160. .text
  161. .globl _start
  162. # The entry JMP -- the same three bytes every image this compiler writes opens
  163. # with. bootcom.s jumps to 0000:0100, which is this instruction. It is
  164. # written as raw bytes rather than `jmp drive' because gas would shorten that to
  165. # a two-byte EB 00 short jump, and the byte it dropped would then be executed as
  166. # the first instruction of the driver.
  167. _start:
  168. .byte 0xE9 # JMP rel16
  169. .word drive - _start - 3
  170. # --------------------------------------------------------------- the driver
  171. drive:
  172. cld
  173. # 1. Poison the two places a check is allowed to look. STORE gets EEEH so
  174. # a read entry that stores nothing is visible as such, and the data
  175. # area gets AAH so initmem has something to clear. The storage below
  176. # is zeroed; the poison is what turns a zero into a RESULT.
  177. movw $STORE + LOAD_BIAS, %si
  178. movw $0xEEEE, %ax
  179. movw %ax, (%si)
  180. movw $DATA + LOAD_BIAS, %si
  181. movw $DLEN, %cx
  182. movb $0xAA, %al
  183. .Lpoison:
  184. movb %al, (%si)
  185. incw %si
  186. loop .Lpoison
  187. # BP is the case-record cursor, and it is the only register that survives a
  188. # call into the runtime, so everything the loop needs is read through it
  189. # or parked in the driver's own words first.
  190. movw $CASE + LOAD_BIAS, %bp
  191. # 2. Open the record: SOH, the case index as two hex digits, STX.
  192. movb $SOH, %al
  193. call putc
  194. movw OFF_CASE(%bp), %ax
  195. movw %ax, %bx
  196. movb %bh, %al
  197. call hexb
  198. movb %bl, %al
  199. call hexb
  200. movb $STX, %al
  201. call putc
  202. # 3. Arm the input. INCUR is an INDEX into INBUF, and zeroing it is what
  203. # makes this boot's input start at its first byte. CX is cleared
  204. # first: see the note at the top about the high byte of CX.
  205. xorw %cx, %cx
  206. movb OFF_INLEN(%bp), %cl
  207. movw %cx, INLEN
  208. movw $0, INCUR
  209. movw $CASE + OFF_INBUF + LOAD_BIAS, %si
  210. movw $INBUF, %di
  211. xorw %ax, %ax
  212. repe cmpsb
  213. # 4. The calls. dumplen and the report address are needed after the loop,
  214. # by which time BP has moved, so they are parked now; so is the count,
  215. # because CX is gone by the second iteration.
  216. movw OFF_DUMPLEN(%bp), %ax
  217. movw %ax, D_DUMPLEN + LOAD_BIAS
  218. movw OFF_DUMPADR(%bp), %ax
  219. movw %ax, D_DUMPADR + LOAD_BIAS
  220. xorw %ax, %ax
  221. movb OFF_NCALLS(%bp), %al
  222. movw %ax, D_CNT + LOAD_BIAS
  223. addw $SLOT0, %bp # BP now points AT the first call slot
  224. .Lcall:
  225. decw D_CNT + LOAD_BIAS # 1 -> 0 has SF clear, so the body runs once;
  226. jns .Lgo # 0 -> FFFF is what ends the loop
  227. jmp .Lcalldone
  228. .Lgo:
  229. call doslot
  230. addw $SLOT_SZ, %bp
  231. jmp .Lcall
  232. .Lcalldone:
  233. # 5. Close the output half and report the memory. A store that never
  234. # happened is the EEEH left in step 1, which is why it is there.
  235. movb $ETX, %al
  236. call putc
  237. movw D_DUMPLEN + LOAD_BIAS, %cx
  238. jcxz .Lnodump
  239. movw D_DUMPADR + LOAD_BIAS, %si
  240. addw $LOAD_BIAS, %si
  241. .Ldump:
  242. lodsb
  243. call hexb
  244. loop .Ldump
  245. .Lnodump:
  246. movb $EOT, %al
  247. call putc
  248. # 6. Exit. Reaching here IS the assertion that every entry returned: an
  249. # entry that hung produces no EOT, and the harness says so.
  250. movw $0x4C00, %ax # INT 21h AH=4Ch, AL=0
  251. int $0x21
  252. # doslot: call the entry described by the 12 bytes at BP, with the same
  253. # conventions Compiler.IoCall uses -- 16-bit argument(s) on the stack, popped
  254. # by the caller -- except for initmem, which takes the header in AX.
  255. #
  256. # Flags (the byte at +4):
  257. # 1 F_STACK push the word at +2; the caller pops one word.
  258. # 2 F_AX take the word at +2 in AX instead.
  259. # 4 F_INL the argument follows the call, not on the stack.
  260. # 8 F_STACK2 push the word at +6 FIRST and the word at +2 second, so +2
  261. # lands at [BP+4] and +6 at [BP+6]; the caller pops two words.
  262. # strstore wants exactly that: dest at [BP+4], source at [BP+6].
  263. # 16 F_CX load CX from the word at +8 before the call. rdstr and
  264. # strstore both take their maximum length in CX, a register the
  265. # record has no other way to reach, and neither may borrow it
  266. # from whatever the previous case left behind.
  267. #
  268. # The flags are re-read after the call because the entry has just used AX.
  269. doslot:
  270. movb 4(%bp), %al
  271. testb $64, %al
  272. jnz .Lfourstack
  273. testb $32, %al
  274. jnz .Lthreestack
  275. testb $8, %al
  276. jnz .Ltwostack
  277. testb $1, %al
  278. jz .Lnostack
  279. pushw 2(%bp)
  280. jmp .Lnostack
  281. .Ltwostack:
  282. pushw 6(%bp) # arg B: the source, ends at [BP+6]
  283. pushw 2(%bp) # arg A: the destination, ends at [BP+4]
  284. jmp .Lnostack
  285. .Lthreestack:
  286. pushw 8(%bp) # [BP+8]
  287. pushw 6(%bp) # [BP+6]
  288. pushw 2(%bp) # [BP+4]
  289. jmp .Lnostack
  290. .Lfourstack:
  291. pushw 10(%bp) # [BP+10]
  292. pushw 8(%bp) # [BP+8]
  293. pushw 6(%bp) # [BP+6]
  294. pushw 2(%bp) # [BP+4]
  295. .Lnostack:
  296. testb $2, %al
  297. jz .Lnoax
  298. movw 2(%bp), %ax
  299. .Lnoax:
  300. testb $16, %al
  301. jz .Lnocx
  302. movw 8(%bp), %cx
  303. .Lnocx:
  304. movw (%bp), %si # image-absolute, as RT_Entry reports it
  305. addw $LOAD_BIAS, %si # so the load bias is added here, not baked in
  306. testb $4, %al
  307. jnz .Linl
  308. call *%si
  309. movw %ax, D_AX + LOAD_BIAS # observable return value
  310. movb 4(%bp), %al
  311. testb $64, %al
  312. jnz .Lcleanfour
  313. testb $32, %al
  314. jnz .Lcleanthree
  315. testb $8, %al
  316. jnz .Lcleantwo
  317. testb $1, %al
  318. jz .Lnoclean
  319. addw $2, %sp # caller-cleaned
  320. .Lnoclean:
  321. ret
  322. .Lcleantwo:
  323. addw $4, %sp
  324. ret
  325. .Lcleanthree:
  326. addw $6, %sp
  327. ret
  328. .Lcleanfour:
  329. addw $8, %sp
  330. ret
  331. # wrtinl's argument is NOT a stack word: the entry reads a length byte and that
  332. # many characters from its own return address. That is the caller's half of
  333. # the contract, so it is written literally here -- the length byte and the
  334. # characters must be the bytes immediately after the call, which is why this is
  335. # a second copy of the instruction rather than a jump. The compiler's own
  336. # placement of the same three things is what the string-literal fixtures in
  337. # run_com_exec.py check; duplicating a variable one here would be a second
  338. # thing to keep right, and a check that cannot fail is not a check.
  339. .Linl:
  340. call *%si
  341. .byte 5
  342. .byte 'h', 'e', 'l', 'l', 'o'
  343. ret
  344. # putc: AL to the serial port. No status polling -- qemu's 16550 always accepts,
  345. # and a poll that never went ready would hang the harness instead of failing it.
  346. putc:
  347. pushw %ax
  348. movw $0x03f8, %dx
  349. outb %al, %dx
  350. popw %ax
  351. ret
  352. # hexb: AL as two uppercase hex digits, high nibble first.
  353. #
  354. # The 8086 has no `SHR r/m16, imm8' and no shift-by-four, so the high nibble
  355. # comes from four one-bit shifts through CL. Both facts have to be written
  356. # down: gas assembles `shr $4, %ah' without complaint and rejects `shrw $1, %ah'
  357. # outright, so the only thing standing between this file and an image that
  358. # assembles cleanly and dies on a real 8086 is refusing the modern encodings.
  359. hexb:
  360. pushw %ax
  361. pushw %cx
  362. movb %al, %ah
  363. movb $1, %cl
  364. shrw %cl, %ax
  365. shrw %cl, %ax
  366. shrw %cl, %ax
  367. shrw %cl, %ax
  368. popw %cx
  369. call putdig
  370. popw %ax
  371. andb $0x0f, %al
  372. movb %al, %ah
  373. call putdig
  374. ret
  375. # putdig: the nibble in AH as one character, moved into AL so that setting AH for
  376. # INT 21h AH=02h cannot overwrite the digit it is about to print.
  377. putdig:
  378. movb %ah, %al
  379. cmpb $10, %al
  380. jb .Ldigit
  381. addb $0x37, %al # 0Ah + 37h = 'A'
  382. jmp .Lemit
  383. .Ldigit:
  384. addb $0x30, %al # '0'
  385. .Lemit:
  386. movb %al, %dl # DOS AH=02h takes the character in DL
  387. movb $2, %ah
  388. int $0x21
  389. ret
  390. # --------------------------------------------------------------- the image
  391. # The runtime blob, from tests/RtProbe.mod built at RT_BASE. The gap is the
  392. # checked bound: rt_exec.py asserts that 0x0180..RT_BASE is still all zeros, so
  393. # a driver that outgrew its space fails the suite instead of overwriting the
  394. # library it is testing.
  395. .org RT_BASE
  396. .incbin "rtblob.bin"
  397. # The program header initmem is handed: +0 flag, +2 code, +4 data base, +6 data
  398. # end. Built HERE, from the same DATA and DLEN the poison loop uses, because
  399. # the compiler's own header layout is a separate claim with its own check and
  400. # this harness is not that check. The two fields initmem READS are memory
  401. # addresses, so they carry the bias; the caller passes AX the header's memory
  402. # address too, which is the one thing rt_exec.py gets right only by saying so
  403. # here and in case_bytes().
  404. .org HDR
  405. HDR:
  406. .word 1 # hdrFlag
  407. .word 0 # hdrCS, unused by initmem
  408. .word DATA + LOAD_BIAS # hdrDS = data base
  409. .word DATA + DLEN + LOAD_BIAS # hdrHeap = data end
  410. .org DATA
  411. .zero DLEN # poisoned to AAH by the driver
  412. .org STORE
  413. .zero 2 # poisoned to EEEH by the driver
  414. # A string for the wrstr case: a length byte and that many characters, which is
  415. # the layout a compiled `string [n]' variable has. It sits above the poisoned
  416. # area so the poison never touches it, and rt_exec.py restates its address - the
  417. # two must agree or the case reads whatever bytes are there and prints them.
  418. .org WSTR
  419. .byte 5
  420. .byte 'h', 'e', 'l', 'l', 'o'
  421. .org WSTR_EMPTY
  422. .byte 0 # a length of 0: an empty string
  423. .org CASE
  424. .incbin "rtcase.bin"
  425. .org D_DUMPLEN
  426. .zero 6 # D_DUMPLEN, D_DUMPADR, D_CNT
  427. # --- strings for the string entries ----------------------------------------
  428. # A compiled `string [n]' variable is a length byte and n characters, and that
  429. # is the layout rdstr writes and strstore reads. Each DESTINATION is
  430. # pre-filled with 0xEE so a byte the entry does NOT write is visibly still
  431. # there -- that is how "the tail past the new length is left untouched" becomes
  432. # a checked claim rather than a comment. The sources are distinct addresses so
  433. # one image can offer a short string, one longer than a small max, and an empty
  434. # one, without any case depending on a previous case's leftovers.
  435. .org RDSTR_DST
  436. .fill 16, 1, 0xEE
  437. .org SST_HELLO
  438. .byte 5, 'h', 'e', 'l', 'l', 'o'
  439. .org SST_LONG
  440. .byte 8, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'
  441. .org SST_EMPTY
  442. .byte 0 # a length of 0: an empty string
  443. .org SST_DST
  444. .fill 16, 1, 0xEE
  445. # strcat reads the DESTINATION's length, so its destinations are seeded with a
  446. # real string rather than 0xEE -- and 0xEE would in fact be a 238-character
  447. # length, which is exactly the "string too long" error the entry has to raise.
  448. # SST_CAT holds `hello', SST_CAT0 is empty, and SST_WORLD is a source that is
  449. # not SST_HELLO so an append is visible as an append and not as a coincidence.
  450. .org SST_CAT
  451. .byte 5, 'h', 'e', 'l', 'l', 'o'
  452. .fill 10, 1, 0xEE
  453. .org SST_CAT0
  454. .byte 0 # a length of 0: nothing to append to
  455. .fill 15, 1, 0xEE
  456. .org SST_WORLD
  457. .byte 5, 'w', 'o', 'r', 'l', 'd'
  458. # 12-byte MBF blocks for real_add/real_sub: a at +0, b at +6.
  459. .org R_BLK1
  460. .byte 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
  461. .org R_BLK2
  462. .byte 0x82, 0x00, 0x00, 0x00, 0x00, 0x40, 0x83, 0x00, 0x00, 0x00, 0x00, 0x20
  463. .org R_BLK3
  464. .byte 0x83, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x00, 0x00, 0x40
  465. .org R_BLK4
  466. .byte 0x81, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
  467. .org R_BLK5
  468. .byte 0x8A, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
  469. .org R_BLK6
  470. .byte 0x82, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
  471. .org R_BLK7
  472. .byte 0x86, 0x00, 0x00, 0x00, 0x00, 0x28, 0x8A, 0x00, 0x00, 0x00, 0x00, 0x7A
  473. .org R_BLK8
  474. .byte 0x8F, 0x00, 0x00, 0x00, 0xFE, 0x7F, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
  475. .org R_BLK9
  476. .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x20
  477. .org R_BLK10
  478. .byte 0x82, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x80
  479. # Division pairs for real_div.
  480. .org R_BLK11
  481. .byte 0x83, 0x00, 0x00, 0x00, 0x00, 0x40, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
  482. .org R_BLK12
  483. .byte 0x84, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
  484. .org R_BLK13
  485. .byte 0x84, 0x00, 0x00, 0x00, 0x00, 0x70, 0x82, 0x00, 0x00, 0x00, 0x00, 0x40
  486. .org R_BLK14
  487. .byte 0x8A, 0x00, 0x00, 0x00, 0x00, 0x7A, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
  488. .org R_BLK15
  489. .byte 0x83, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
  490. .org R_BLK16
  491. .byte 0x83, 0x00, 0x00, 0x00, 0x00, 0x40, 0x82, 0x00, 0x00, 0x00, 0x00, 0x80
  492. .org R_BLK17
  493. .byte 0x83, 0x00, 0x00, 0x00, 0x00, 0xC0, 0x82, 0x00, 0x00, 0x00, 0x00, 0x80
  494. .org R_BLK18
  495. .byte 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x00, 0x00, 0x00, 0x00, 0x20
  496. .org R_BLK19
  497. .byte 0x83, 0x00, 0x00, 0x00, 0x00, 0x20, 0x82, 0x00, 0x00, 0x00, 0x00, 0x00
  498. .org R_BLK20
  499. .byte 0x86, 0x00, 0x00, 0x00, 0x00, 0x28, 0x83, 0x00, 0x00, 0x00, 0x00, 0x40
  500. # Fractional blocks: real_int truncates `a'; real_cmp compares the pair.
  501. .org R_BLK21
  502. .byte 0x82, 0xCD, 0xCC, 0xCC, 0xCC, 0x6C, 0x82, 0xCD, 0xCC, 0xCC, 0xCC, 0x6C
  503. .org R_BLK22
  504. .byte 0x82, 0x9A, 0x99, 0x99, 0x99, 0x79, 0x82, 0xCD, 0xCC, 0xCC, 0xCC, 0x6C
  505. .org R_BLK23
  506. .byte 0x82, 0xCD, 0xCC, 0xCC, 0xCC, 0xEC, 0x82, 0x9A, 0x99, 0x99, 0x99, 0xF9
  507. .org R_BLK24
  508. .byte 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00
  509. .org R_BLK25
  510. .byte 0x80, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00
  511. .org R_BLK26
  512. .byte 0x8E, 0x00, 0x00, 0x00, 0xE7, 0x40, 0x8E, 0x00, 0x00, 0x00, 0xE6, 0x40
  513. .org R_BLK27
  514. .byte 0x82, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  515. .org R_BLK28
  516. .byte 0x82, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  517. .org R_BLK29
  518. .byte 0x80, 0x0A, 0xD7, 0xA3, 0x70, 0x7D, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  519. .org R_BLK30
  520. .byte 0x81, 0x33, 0x33, 0x33, 0x33, 0x73, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  521. # 2^40: above reint's 0A8h early return, so it must come back unchanged.
  522. .org R_BLK31
  523. .byte 0xA9, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
  524. # ASCIIZ sources for real_val.
  525. .org ASCSRC
  526. .ascii "3.5\x00"
  527. .ascii "-2.25\x00"
  528. .ascii "1E3\x00"
  529. .ascii "0.5\x00"
  530. .ascii "12345.75\x00"
  531. .ascii "3.5x\x00"
  532. .ascii "1E\x00"
  533. .ascii "1E40\x00"
  534. .ascii "\x00"
  535. .ascii ".5\x00"
  536. .ascii "1.2.3\x00"
  537. .ascii "35\x00"
  538. .ascii "5E-1\x00"
  539. .ascii "5.\x00"
  540. .ascii "5.0\x00"
  541. .ascii "12345\x00"
  542. .ascii "1234575\x00"
  543. .ascii "1234.5\x00"
  544. .ascii "1000\x00"
  545. .ascii "123\x00"
  546. .ascii "1234\x00"
  547. .ascii "12340\x00"
  548. .ascii "12341\x00"
  549. .ascii "12341E0\x00"
  550. .ascii "12345E0\x00"
  551. # add-core probes
  552. .org R_BLK32
  553. .byte 0x8E, 0x00, 0x00, 0x00, 0xD0, 0x40, 0x83, 0x00, 0x00, 0x00, 0x00, 0x20
  554. .org R_BLK33
  555. .byte 0x8E, 0x00, 0x00, 0x00, 0xD0, 0x40, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
  556. # multiplication-by-one probes
  557. .org R_BLK34
  558. .byte 0x8E, 0x00, 0x00, 0x00, 0xD4, 0x40, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
  559. .org R_BLK35
  560. .byte 0x8E, 0x00, 0x00, 0x00, 0xE4, 0x40, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
  561. .org R_BLK36
  562. .byte 0x8E, 0x00, 0x00, 0x00, 0xD0, 0x40, 0x81, 0x00, 0x00, 0x00, 0x00, 0x00
  563. # Set buffers for set_op/set_cmp/set_copy.
  564. .org SETA
  565. .byte 0x0A, 0x00, 0x00, 0x00
  566. .org SETB
  567. .byte 0x18, 0x00, 0x00, 0x00
  568. .org SETC
  569. .byte 0x02, 0x00, 0x00, 0x00
  570. .org SETD
  571. .byte 0x00, 0x00, 0x00, 0x00
  572. .org SET2A
  573. .byte 0x0A, 0x0F
  574. .org SET2B
  575. .byte 0x18, 0x03
  576. .org SET2D
  577. .byte 0x00, 0x00
  578. # File control block for the file_assign case.
  579. .org FILEBLK
  580. .zero 132