prt0comn.asm 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784
  1. ; common startup code for all the memory models
  2. %ifdef __TINY__
  3. %define __NEAR_CODE__
  4. %define __NEAR_DATA__
  5. %elifdef __SMALL__
  6. %define __NEAR_CODE__
  7. %define __NEAR_DATA__
  8. %elifdef __MEDIUM__
  9. %define __FAR_CODE__
  10. %define __NEAR_DATA__
  11. %elifdef __COMPACT__
  12. %define __NEAR_CODE__
  13. %define __FAR_DATA__
  14. %elifdef __LARGE__
  15. %define __FAR_CODE__
  16. %define __FAR_DATA__
  17. %elifdef __HUGE__
  18. %define __FAR_CODE__
  19. %define __FAR_DATA__
  20. %else
  21. %fatal "Memory model not defined."
  22. %endif
  23. %ifdef __FAR_CODE__
  24. extra_param_offset equ 2
  25. %else
  26. extra_param_offset equ 0
  27. %endif
  28. %ifdef __FAR_DATA__
  29. extra_data_offset equ 2
  30. %else
  31. extra_data_offset equ 0
  32. %endif
  33. cpu 8086
  34. segment _TEXT use16 class=CODE
  35. extern PASCALMAIN
  36. extern __fpc_PrefixSeg
  37. extern dos_version
  38. extern __Test8086
  39. extern _edata ; defined by WLINK, indicates start of BSS
  40. extern _end ; defined by WLINK, indicates end of BSS
  41. extern __stklen
  42. extern __stktop
  43. extern __stkbottom
  44. extern __nearheap_start
  45. extern __nearheap_end
  46. extern ___heap
  47. %ifdef __NEAR_DATA__
  48. extern __fpc_stackplusmaxheap_in_para
  49. %endif
  50. %ifndef __TINY__
  51. %ifdef __FAR_DATA__
  52. extern ___stack
  53. %endif
  54. %ifdef __NEAR_DATA__
  55. extern ___stacktop
  56. %endif
  57. %endif
  58. extern __SaveInt00
  59. extern __SaveInt10
  60. extern __SaveInt75
  61. extern __fpu_status
  62. extern FPC_HANDLE_I8086_ERROR
  63. %ifdef __TINY__
  64. resb 0100h
  65. %endif
  66. ..start:
  67. %ifndef __HUGE__
  68. %ifdef __TINY__
  69. mov bx, cs
  70. %else
  71. mov bx, DGROUP
  72. %ifdef __NEAR_DATA__
  73. ; init the stack
  74. mov ss, bx
  75. mov sp, ___stacktop wrt DGROUP
  76. %endif
  77. %endif
  78. ; zero fill the BSS section
  79. mov es, bx
  80. mov di, _edata wrt DGROUP
  81. mov cx, _end wrt DGROUP
  82. sub cx, di
  83. xor al, al
  84. cld
  85. rep stosb
  86. %endif ; not __HUGE__
  87. ; save the Program Segment Prefix
  88. push ds
  89. ; init DS
  90. %ifdef __HUGE__
  91. mov bx, SYSTEM_DATA
  92. mov ds, bx
  93. %else
  94. mov ds, bx
  95. %endif
  96. ; pop the PSP from stack and store it in the pascal variable PrefixSeg
  97. pop ax
  98. mov word [__fpc_PrefixSeg], ax
  99. ; get DOS version and save it in the pascal variable dos_version
  100. mov ax, 3000h
  101. int 21h
  102. xchg al, ah
  103. mov word [dos_version], ax
  104. ; detect CPU
  105. xor bx, bx ; 0=8086/8088/80186/80188/NEC V20/NEC V30
  106. ; on pre-286 processors, bits 12..15 of the FLAGS registers are always set
  107. pushf
  108. pop ax
  109. and ah, 0fh
  110. push ax
  111. popf
  112. pushf
  113. pop ax
  114. and ah, 0f0h
  115. cmp ah, 0f0h
  116. je cpu_detect_done
  117. ; at this point we have a 286 or higher
  118. inc bx
  119. ; on a true 286 in real mode, bits 12..15 are always clear
  120. pushf
  121. pop ax
  122. or ah, 0f0h
  123. push ax
  124. popf
  125. pushf
  126. pop ax
  127. and ah, 0f0h
  128. jz cpu_detect_done
  129. ; we have a 386+
  130. inc bx
  131. cpu_detect_done:
  132. mov [__Test8086], bl
  133. %ifdef __NEAR_DATA__
  134. ; ****************************************************************************
  135. ; ** near data memory layout setup **
  136. ; ****************************************************************************
  137. ; allocate max heap
  138. ; first we determine in paragraphs ax:=min(64kb, data+bss+stack+maxheap)
  139. mov ax, _end wrt DGROUP
  140. add ax, 15
  141. mov cl, 4
  142. shr ax, cl
  143. add ax, word [__fpc_stackplusmaxheap_in_para]
  144. cmp ax, 1000h ; 1000h = 64k in paragraphs
  145. jbe data_with_maxheap_less_than_64k
  146. mov ax, 1000h
  147. data_with_maxheap_less_than_64k:
  148. ; try to resize our main DOS memory block until the end of the data segment (or even smaller, if maxheap is small)
  149. mov cx, word [__fpc_PrefixSeg]
  150. %ifdef __TINY__
  151. mov dx, cs
  152. %else
  153. mov dx, DGROUP
  154. %endif
  155. sub dx, cx ; dx = (ds - psp) in paragraphs
  156. push dx ; save (ds - psp)
  157. add dx, 1000h ; 64kb in paragraphs
  158. ; get our MCB size in paragraphs
  159. dec cx
  160. mov es, cx
  161. mov bx, word [es:3]
  162. ; is it smaller than the maximum data segment size?
  163. cmp bx, dx
  164. jbe skip_mem_realloc
  165. mov bx, dx
  166. inc cx
  167. mov es, cx
  168. mov ah, 4Ah
  169. int 21h
  170. jc mem_realloc_err
  171. skip_mem_realloc:
  172. ; bx = the new size in paragraphs
  173. pop cx ; cx = (ds - psp)
  174. sub bx, cx
  175. mov cl, 4
  176. shl bx, cl
  177. sub bx, 2
  178. mov sp, bx
  179. mov word [__stktop], sp
  180. add bx, 2
  181. sub bx, word [__stklen]
  182. and bl, 0FEh
  183. mov word [__stkbottom], bx
  184. mov ax, _end wrt DGROUP
  185. cmp bx, ax
  186. jb not_enough_mem
  187. ; heap is between [ds:_end wrt DGROUP] and [ds:__stkbottom - 1]
  188. add ax, 3
  189. and al, 0FCh
  190. mov word [__nearheap_start], ax
  191. and bl, 0FCh
  192. mov word [__nearheap_end], bx
  193. ; ****************************************************************************
  194. ; ** near data setup done **
  195. ; ****************************************************************************
  196. %endif
  197. %ifdef __FAR_DATA__
  198. mov word [__stktop], sp
  199. mov word [__stkbottom], 0
  200. mov ax, ss
  201. mov word [__stkbottom + 2], ax
  202. mov word [__stktop + 2], ax
  203. mov dx, sp
  204. add dx, 15
  205. mov cl, 4
  206. shr dx, cl
  207. add ax, dx
  208. mov word [__nearheap_start], 0
  209. mov word [__nearheap_start + 2], ax
  210. ; get our MCB size in paragraphs
  211. mov cx, word [__fpc_PrefixSeg]
  212. dec cx
  213. mov es, cx
  214. mov bx, word [es:3]
  215. add bx, cx
  216. inc bx
  217. ; __nearheap_end := end_of_dos_memory_block
  218. mov word [__nearheap_end], 0
  219. mov word [__nearheap_end + 2], bx
  220. %endif
  221. %ifdef __FAR_CODE__
  222. jmp far PASCALMAIN
  223. %else
  224. jmp PASCALMAIN
  225. %endif
  226. %ifdef __NEAR_DATA__
  227. not_enough_mem:
  228. mov dx, not_enough_mem_msg
  229. jmp error_msg
  230. mem_realloc_err:
  231. ; at this point there's still (ds-psp) pushed on the stack, but we won't
  232. ; bother popping it, because we exit to DOS with an error message here
  233. mov dx, mem_realloc_err_msg
  234. error_msg:
  235. mov ah, 9
  236. int 21h
  237. mov ax, 4CFFh
  238. int 21h
  239. %endif
  240. global FPC_INT00_HANDLER
  241. FPC_INT00_HANDLER:
  242. pushf
  243. sub sp, 4 ; reserve space on the stack for the iret
  244. push cx
  245. push ds
  246. push bp
  247. ; init ds
  248. %ifdef __TINY__
  249. mov bp, cs
  250. %elifdef __HUGE__
  251. mov bp, SYSTEM_DATA
  252. %else
  253. mov bp, DGROUP
  254. %endif
  255. mov ds, bp
  256. %ifdef __NEAR_DATA__
  257. ; in memory models, where SS=DS, also
  258. ; check whether we're running on the same stack
  259. mov cx, ss
  260. cmp bp, cx
  261. jne .call_previous_handler00
  262. %endif
  263. %ifndef __FAR_CODE__
  264. ; check whether we're coming from the same code segment
  265. mov bp, sp
  266. mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
  267. mov bp, cs
  268. cmp bp, cx
  269. jne .call_previous_handler00
  270. %endif
  271. ; Call Fpc_Handle_I8086_Error, with err=0
  272. mov bp, sp
  273. mov cx, [bp + 3*2 + 6] ; get caller offset
  274. %ifdef __FAR_CODE__
  275. mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
  276. %endif
  277. pop bp
  278. add sp, 2*2 + 6 + 6
  279. xor ax, ax
  280. push ax
  281. mov ax, 0
  282. push ax
  283. %ifdef __FAR_CODE__
  284. push dx
  285. %endif
  286. push cx
  287. cld
  288. sti
  289. %ifdef __FAR_CODE__
  290. jmp far FPC_HANDLE_I8086_ERROR
  291. %else
  292. jmp FPC_HANDLE_I8086_ERROR
  293. %endif
  294. .call_previous_handler00:
  295. mov bp, sp
  296. mov cx, [__SaveInt00]
  297. mov [bp + 3*2], cx
  298. mov cx, [__SaveInt00+2]
  299. mov [bp + 3*2 + 2], cx
  300. pop bp
  301. pop ds
  302. pop cx
  303. iret ; jumps to the previous handler with all registers and stack intact
  304. global FPC_INT10_HANDLER
  305. FPC_INT10_HANDLER:
  306. pushf
  307. sub sp, 4 ; reserve space on the stack for the iret
  308. push cx
  309. push ds
  310. push bp
  311. ; init ds
  312. %ifdef __TINY__
  313. mov bp, cs
  314. %elifdef __HUGE__
  315. mov bp, SYSTEM_DATA
  316. %else
  317. mov bp, DGROUP
  318. %endif
  319. mov ds, bp
  320. ; Check that an unmasked exception is indeed set
  321. fnstsw word [__fpu_status]
  322. test byte [__fpu_status], 80h ; really just this bit is enough, see i8087 datasheet
  323. je .call_previous_handler10
  324. %ifdef __NEAR_DATA__
  325. ; in memory models, where SS=DS, also
  326. ; check whether we're running on the same stack
  327. mov cx, ss
  328. cmp bp, cx
  329. jne .call_previous_handler10
  330. %endif
  331. %ifndef __FAR_CODE__
  332. ; check whether we're coming from the same code segment
  333. mov bp, sp
  334. mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
  335. mov bp, cs
  336. cmp bp, cx
  337. jne .call_previous_handler10
  338. %endif
  339. ; Call Fpc_Handle_I8086_Error, with err=$10
  340. mov bp, sp
  341. mov cx, [bp + 3*2 + 6] ; get caller offset
  342. %ifdef __FAR_CODE__
  343. mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
  344. %endif
  345. pop bp
  346. add sp, 2*2 + 6 + 6
  347. xor ax, ax
  348. push ax
  349. mov ax, 10h
  350. push ax
  351. %ifdef __FAR_CODE__
  352. push dx
  353. %endif
  354. push cx
  355. cld
  356. sti
  357. %ifdef __FAR_CODE__
  358. jmp far FPC_HANDLE_I8086_ERROR
  359. %else
  360. jmp FPC_HANDLE_I8086_ERROR
  361. %endif
  362. .call_previous_handler10:
  363. mov bp, sp
  364. mov cx, [__SaveInt10]
  365. mov [bp + 3*2], cx
  366. mov cx, [__SaveInt10+2]
  367. mov [bp + 3*2 + 2], cx
  368. pop bp
  369. pop ds
  370. pop cx
  371. iret ; jumps to the previous handler with all registers and stack intact
  372. global FPC_INT75_HANDLER
  373. FPC_INT75_HANDLER:
  374. pushf
  375. sub sp, 4 ; reserve space on the stack for the iret
  376. push cx
  377. push ds
  378. push bp
  379. ; init ds
  380. %ifdef __TINY__
  381. mov bp, cs
  382. %elifdef __HUGE__
  383. mov bp, SYSTEM_DATA
  384. %else
  385. mov bp, DGROUP
  386. %endif
  387. mov ds, bp
  388. %ifdef __NEAR_DATA__
  389. ; in memory models, where SS=DS, also
  390. ; check whether we're running on the same stack
  391. mov cx, ss
  392. cmp bp, cx
  393. jne .call_previous_handler75
  394. %endif
  395. %ifndef __FAR_CODE__
  396. ; check whether we're coming from the same code segment
  397. mov bp, sp
  398. mov cx, [bp + 3*2 + 6 + 2] ; get caller segment
  399. mov bp, cs
  400. cmp bp, cx
  401. jne .call_previous_handler75
  402. %endif
  403. ; Call Fpc_Handle_I8086_Error, with err=$75
  404. mov bp, sp
  405. mov cx, [bp + 3*2 + 6] ; get caller offset
  406. %ifdef __FAR_CODE__
  407. mov dx, [bp + 3*2 + 6 + 2] ; get caller segment
  408. %endif
  409. pop bp
  410. add sp, 2*2 + 6 + 6
  411. xor ax, ax
  412. push ax
  413. mov ax, 75h
  414. push ax
  415. %ifdef __FAR_CODE__
  416. push dx
  417. %endif
  418. push cx
  419. cld
  420. ; Reset IRQ/#IGNNE latch; signal EOI; enable interrupts
  421. mov al,20h
  422. out 0F0h,al ; al=any
  423. out 0A0h,al
  424. out 020h,al
  425. sti
  426. %ifdef __FAR_CODE__
  427. jmp far FPC_HANDLE_I8086_ERROR
  428. %else
  429. jmp FPC_HANDLE_I8086_ERROR
  430. %endif
  431. .call_previous_handler75:
  432. mov bp, sp
  433. mov cx, [__SaveInt75]
  434. mov [bp + 3*2], cx
  435. mov cx, [__SaveInt75+2]
  436. mov [bp + 3*2 + 2], cx
  437. pop bp
  438. pop ds
  439. pop cx
  440. retf ; jumps to the previous handler with all registers and stack intact
  441. global FPC_INSTALL_INTERRUPT_HANDLERS
  442. FPC_INSTALL_INTERRUPT_HANDLERS:
  443. %ifdef __HUGE__
  444. push ds
  445. mov ax, SYSTEM_DATA
  446. mov ds, ax
  447. %endif
  448. ; save old int 00 handler
  449. mov ax, 3500h
  450. int 21h
  451. mov [__SaveInt00], bx
  452. mov bx, es
  453. mov [__SaveInt00+2], bx
  454. ; install the new int 00 handler
  455. %ifndef __TINY__
  456. push ds
  457. push cs
  458. pop ds
  459. %endif
  460. mov dx, FPC_INT00_HANDLER
  461. mov ax, 2500h
  462. int 21h
  463. %ifndef __TINY__
  464. pop ds
  465. %endif
  466. ; save old int $10 handler
  467. mov ax, 3510h
  468. int 21h
  469. mov [__SaveInt10], bx
  470. mov bx, es
  471. mov [__SaveInt10+2], bx
  472. ; install the new int $10 handler
  473. %ifndef __TINY__
  474. push ds
  475. push cs
  476. pop ds
  477. %endif
  478. mov dx, FPC_INT10_HANDLER
  479. mov ax, 2510h
  480. int 21h
  481. %ifndef __TINY__
  482. pop ds
  483. %endif
  484. ; save old int $75 handler
  485. mov ax, 3575h
  486. int 21h
  487. mov [__SaveInt75], bx
  488. mov bx, es
  489. mov [__SaveInt75+2], bx
  490. ; install the new int $75 handler
  491. %ifndef __TINY__
  492. push ds
  493. push cs
  494. pop ds
  495. %endif
  496. mov dx, FPC_INT75_HANDLER
  497. mov ax, 2575h
  498. int 21h
  499. %ifndef __TINY__
  500. pop ds
  501. %endif
  502. %ifdef __HUGE__
  503. pop ds
  504. %endif
  505. %ifdef __FAR_CODE__
  506. retf
  507. %else
  508. ret
  509. %endif
  510. global FPC_RESTORE_INTERRUPT_HANDLERS
  511. FPC_RESTORE_INTERRUPT_HANDLERS:
  512. %ifdef __HUGE__
  513. push ds
  514. mov ax, SYSTEM_DATA
  515. mov ds, ax
  516. %endif
  517. push ds
  518. mov ax, 2500h
  519. lds dx, [__SaveInt00]
  520. int 21h
  521. pop ds
  522. push ds
  523. mov ax, 2510h
  524. lds dx, [__SaveInt10]
  525. int 21h
  526. pop ds
  527. push ds
  528. mov ax, 2575h
  529. lds dx, [__SaveInt75]
  530. int 21h
  531. pop ds
  532. %ifdef __HUGE__
  533. pop ds
  534. %endif
  535. %ifdef __FAR_CODE__
  536. retf
  537. %else
  538. ret
  539. %endif
  540. global FPC_MSDOS_CARRY
  541. FPC_MSDOS_CARRY:
  542. stc
  543. global FPC_MSDOS
  544. FPC_MSDOS:
  545. mov al, 21h ; not ax, because only the low byte is used
  546. pop dx
  547. %ifdef __FAR_CODE__
  548. pop bx
  549. %endif
  550. pop cx
  551. %ifdef __FAR_DATA__
  552. pop si
  553. %endif
  554. push ax
  555. %ifdef __FAR_DATA__
  556. push si
  557. %endif
  558. push cx
  559. %ifdef __FAR_CODE__
  560. push bx
  561. %endif
  562. push dx
  563. global FPC_INTR
  564. FPC_INTR:
  565. push bp
  566. mov bp, sp
  567. mov al, byte [bp + 6 + extra_param_offset + extra_data_offset]
  568. mov byte [cs:int_number], al
  569. mov si, [bp + 4 + extra_param_offset]
  570. push ds
  571. %ifdef __FAR_DATA__
  572. mov ax, [bp + 6 + extra_param_offset]
  573. mov ds, ax
  574. %endif
  575. mov ax, word [si + 16]
  576. mov es, ax
  577. mov ax, word [si + 14] ; ds
  578. push ax
  579. mov ax, word [si]
  580. mov bx, word [si + 2]
  581. mov cx, word [si + 4]
  582. mov dx, word [si + 6]
  583. mov bp, word [si + 8]
  584. mov di, word [si + 12]
  585. mov si, word [si + 10]
  586. pop ds
  587. db 0CDh ; opcode of INT xx
  588. int_number:
  589. db 255
  590. pushf
  591. push ds
  592. push si
  593. push bp
  594. mov bp, sp
  595. %ifdef __FAR_DATA__
  596. mov si, [bp + 16 + extra_param_offset]
  597. %else
  598. mov si, word [bp + 8]
  599. %endif
  600. mov ds, si
  601. mov si, word [bp + 14 + extra_param_offset]
  602. mov word [si], ax
  603. mov word [si + 2], bx
  604. mov word [si + 4], cx
  605. mov word [si + 6], dx
  606. mov word [si + 12], di
  607. mov ax, es
  608. mov word [si + 16], ax
  609. pop ax
  610. mov word [si + 8], ax
  611. pop ax
  612. mov word [si + 10], ax
  613. pop ax
  614. mov word [si + 14], ax
  615. pop ax
  616. mov word [si + 18], ax
  617. pop ds
  618. pop bp
  619. %ifdef __FAR_CODE__
  620. retf 4 + extra_data_offset
  621. %else
  622. ret 4 + extra_data_offset
  623. %endif
  624. %ifndef __TINY__
  625. global FPC_CHECK_NULLAREA
  626. FPC_CHECK_NULLAREA:
  627. %ifdef __HUGE__
  628. mov ax, DGROUP
  629. mov es, ax
  630. %else
  631. push ds
  632. pop es
  633. %endif
  634. xor di, di
  635. mov cx, 32
  636. mov al, 1
  637. cld
  638. repe scasb
  639. je .skip
  640. dec ax ; 1 byte shorter than dec al
  641. .skip:
  642. %ifdef __FAR_CODE__
  643. retf
  644. %else
  645. ret
  646. %endif
  647. %endif
  648. %ifdef __HUGE__
  649. ; reference the system unit's data segment
  650. segment SYSTEM_DATA use16 class=FAR_DATA align=2
  651. %endif
  652. segment data class=DATA align=2
  653. %ifdef __NEAR_DATA__
  654. mem_realloc_err_msg:
  655. db 'Memory allocation error', 13, 10, '$'
  656. not_enough_mem_msg:
  657. db 'Not enough memory', 13, 10, '$'
  658. %endif
  659. ; add reference to the beginning of the minimal heap, so the object
  660. ; module, containing the heap segment doesn't get smartlinked away
  661. dw ___heap
  662. segment bss class=BSS align=2
  663. %ifndef __TINY__
  664. segment _NULL align=16 class=BEGDATA
  665. global __nullarea
  666. __nullarea:
  667. dd 01010101h, 01010101h, 01010101h, 01010101h
  668. dd 01010101h, 01010101h, 01010101h, 01010101h
  669. segment _AFTERNULL align=2 class=BEGDATA
  670. dw 0
  671. %ifdef __NEAR_DATA__
  672. segment stack stack class=STACK align=16
  673. %else
  674. segment data
  675. ; add reference to the beginning of stack, so the object module,
  676. ; containing the stack segment doesn't get smartlinked away
  677. dw ___stack
  678. %endif
  679. %endif
  680. %ifdef __TINY__
  681. group DGROUP _TEXT data bss
  682. %else
  683. %ifdef __NEAR_DATA__
  684. group DGROUP _NULL _AFTERNULL data bss stack
  685. %else
  686. group DGROUP _NULL _AFTERNULL data bss
  687. %endif
  688. %endif