prt0comn.asm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534
  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 FPC_HANDLEERROR
  60. %ifdef __TINY__
  61. resb 0100h
  62. %endif
  63. ..start:
  64. %ifdef __TINY__
  65. mov bx, cs
  66. %else
  67. mov bx, dgroup
  68. %ifdef __NEAR_DATA__
  69. ; init the stack
  70. mov ss, bx
  71. mov sp, ___stacktop wrt dgroup
  72. %endif
  73. %endif
  74. ; zero fill the BSS section
  75. mov es, bx
  76. mov di, _edata wrt dgroup
  77. mov cx, _end wrt dgroup
  78. sub cx, di
  79. xor al, al
  80. cld
  81. rep stosb
  82. ; save the Program Segment Prefix
  83. push ds
  84. ; init DS
  85. mov ds, bx
  86. ; pop the PSP from stack and store it in the pascal variable PrefixSeg
  87. pop ax
  88. mov word [__fpc_PrefixSeg], ax
  89. ; get DOS version and save it in the pascal variable dos_version
  90. mov ax, 3000h
  91. int 21h
  92. xchg al, ah
  93. mov word [dos_version], ax
  94. ; detect CPU
  95. xor bx, bx ; 0=8086/8088/80186/80188/NEC V20/NEC V30
  96. ; on pre-286 processors, bits 12..15 of the FLAGS registers are always set
  97. pushf
  98. pop ax
  99. and ah, 0fh
  100. push ax
  101. popf
  102. pushf
  103. pop ax
  104. and ah, 0f0h
  105. cmp ah, 0f0h
  106. je cpu_detect_done
  107. ; at this point we have a 286 or higher
  108. inc bx
  109. ; on a true 286 in real mode, bits 12..15 are always clear
  110. pushf
  111. pop ax
  112. or ah, 0f0h
  113. push ax
  114. popf
  115. pushf
  116. pop ax
  117. and ah, 0f0h
  118. jz cpu_detect_done
  119. ; we have a 386+
  120. inc bx
  121. cpu_detect_done:
  122. mov [__Test8086], bl
  123. %ifdef __NEAR_DATA__
  124. ; ****************************************************************************
  125. ; ** near data memory layout setup **
  126. ; ****************************************************************************
  127. ; allocate max heap
  128. ; first we determine in paragraphs ax:=min(64kb, data+bss+stack+maxheap)
  129. mov ax, _end wrt dgroup
  130. add ax, 15
  131. mov cl, 4
  132. shr ax, cl
  133. add ax, word [__fpc_stackplusmaxheap_in_para]
  134. cmp ax, 1000h ; 1000h = 64k in paragraphs
  135. jbe data_with_maxheap_less_than_64k
  136. mov ax, 1000h
  137. data_with_maxheap_less_than_64k:
  138. ; try to resize our main DOS memory block until the end of the data segment (or even smaller, if maxheap is small)
  139. mov cx, word [__fpc_PrefixSeg]
  140. %ifdef __TINY__
  141. mov dx, cs
  142. %else
  143. mov dx, dgroup
  144. %endif
  145. sub dx, cx ; dx = (ds - psp) in paragraphs
  146. push dx ; save (ds - psp)
  147. add dx, 1000h ; 64kb in paragraphs
  148. ; get our MCB size in paragraphs
  149. dec cx
  150. mov es, cx
  151. mov bx, word [es:3]
  152. ; is it smaller than the maximum data segment size?
  153. cmp bx, dx
  154. jbe skip_mem_realloc
  155. mov bx, dx
  156. inc cx
  157. mov es, cx
  158. mov ah, 4Ah
  159. int 21h
  160. jc mem_realloc_err
  161. skip_mem_realloc:
  162. ; bx = the new size in paragraphs
  163. pop cx ; cx = (ds - psp)
  164. sub bx, cx
  165. mov cl, 4
  166. shl bx, cl
  167. sub bx, 2
  168. mov sp, bx
  169. mov word [__stktop], sp
  170. add bx, 2
  171. sub bx, word [__stklen]
  172. and bl, 0FEh
  173. mov word [__stkbottom], bx
  174. mov ax, _end wrt dgroup
  175. cmp bx, ax
  176. jb not_enough_mem
  177. ; heap is between [ds:_end wrt dgroup] and [ds:__stkbottom - 1]
  178. add ax, 3
  179. and al, 0FCh
  180. mov word [__nearheap_start], ax
  181. and bl, 0FCh
  182. mov word [__nearheap_end], bx
  183. ; ****************************************************************************
  184. ; ** near data setup done **
  185. ; ****************************************************************************
  186. %endif
  187. %ifdef __FAR_DATA__
  188. mov word [__stktop], sp
  189. mov word [__stkbottom], 0
  190. mov ax, ss
  191. mov word [__stkbottom + 2], ax
  192. mov word [__stktop + 2], ax
  193. mov dx, sp
  194. add dx, 15
  195. mov cl, 4
  196. shr dx, cl
  197. add ax, dx
  198. mov word [__nearheap_start], 0
  199. mov word [__nearheap_end], 0FFF0h
  200. mov word [__nearheap_start + 2], ax
  201. ; get our MCB size in paragraphs
  202. mov cx, word [__fpc_PrefixSeg]
  203. dec cx
  204. mov es, cx
  205. mov bx, word [es:3]
  206. add bx, cx
  207. inc bx
  208. ; __nearheap_end := end_of_dos_memory_block
  209. mov word [__nearheap_end], 0
  210. mov word [__nearheap_end + 2], bx
  211. %endif
  212. %ifdef __FAR_CODE__
  213. jmp far PASCALMAIN
  214. %else
  215. jmp PASCALMAIN
  216. %endif
  217. %ifdef __NEAR_DATA__
  218. not_enough_mem:
  219. mov dx, not_enough_mem_msg
  220. jmp error_msg
  221. mem_realloc_err:
  222. ; at this point there's still (ds-psp) pushed on the stack, but we won't
  223. ; bother popping it, because we exit to DOS with an error message here
  224. mov dx, mem_realloc_err_msg
  225. error_msg:
  226. mov ah, 9
  227. int 21h
  228. mov ax, 4CFFh
  229. int 21h
  230. %endif
  231. FPC_INT00_HANDLER:
  232. sub sp, 4 ; reserve space on the stack for the retf
  233. push cx
  234. push ds
  235. push bp
  236. ; init ds
  237. %ifdef __TINY__
  238. mov bp, cs
  239. %else
  240. mov bp, dgroup
  241. %endif
  242. mov ds, bp
  243. %ifdef __NEAR_DATA__
  244. ; in memory models, where SS=DS, also
  245. ; check whether we're running on the same stack
  246. mov cx, ss
  247. cmp bp, cx
  248. jne .call_previous_handler
  249. %endif
  250. %ifndef __FAR_CODE__
  251. ; check whether we're coming from the same code segment
  252. mov bp, sp
  253. mov cx, [bp + 3*2 + 6] ; get caller segment
  254. mov bp, cs
  255. cmp bp, cx
  256. jne .call_previous_handler
  257. %endif
  258. ; runerror 200
  259. mov bp, sp
  260. mov cx, [bp + 3*2 + 4] ; get caller offset
  261. %ifdef __FAR_CODE__
  262. mov dx, [bp + 3*2 + 6] ; get caller segment
  263. %endif
  264. pop bp
  265. add sp, 2*2 + 4 + 6
  266. xor ax, ax
  267. push ax
  268. mov ax, 200
  269. push ax
  270. %ifdef __FAR_CODE__
  271. push dx
  272. %endif
  273. push cx
  274. cld
  275. %ifdef __FAR_CODE__
  276. jmp far FPC_HANDLEERROR
  277. %else
  278. jmp FPC_HANDLEERROR
  279. %endif
  280. .call_previous_handler:
  281. mov bp, sp
  282. mov cx, [__SaveInt00]
  283. mov [bp + 3*2], cx
  284. mov cx, [__SaveInt00+2]
  285. mov [bp + 3*2 + 2], cx
  286. pop bp
  287. pop ds
  288. pop cx
  289. retf ; jumps to the previous handler with all registers and stack intact
  290. global FPC_INSTALL_INTERRUPT_HANDLERS
  291. FPC_INSTALL_INTERRUPT_HANDLERS:
  292. push ds
  293. ; save old int 00 handler
  294. mov ax, 3500h
  295. int 21h
  296. mov [__SaveInt00], bx
  297. mov bx, es
  298. mov [__SaveInt00+2], bx
  299. ; install the new int 00 handler
  300. %ifndef __TINY__
  301. push cs
  302. pop ds
  303. %endif
  304. mov dx, FPC_INT00_HANDLER
  305. mov ax, 2500h
  306. int 21h
  307. pop ds
  308. %ifdef __FAR_CODE__
  309. retf
  310. %else
  311. ret
  312. %endif
  313. global FPC_RESTORE_INTERRUPT_HANDLERS
  314. FPC_RESTORE_INTERRUPT_HANDLERS:
  315. push ds
  316. mov ax, 2500h
  317. lds dx, [__SaveInt00]
  318. int 21h
  319. pop ds
  320. %ifdef __FAR_CODE__
  321. retf
  322. %else
  323. ret
  324. %endif
  325. global FPC_MSDOS_CARRY
  326. FPC_MSDOS_CARRY:
  327. stc
  328. global FPC_MSDOS
  329. FPC_MSDOS:
  330. mov al, 21h ; not ax, because only the low byte is used
  331. pop dx
  332. %ifdef __FAR_CODE__
  333. pop bx
  334. %endif
  335. pop cx
  336. %ifdef __FAR_DATA__
  337. pop si
  338. %endif
  339. push ax
  340. %ifdef __FAR_DATA__
  341. push si
  342. %endif
  343. push cx
  344. %ifdef __FAR_CODE__
  345. push bx
  346. %endif
  347. push dx
  348. global FPC_INTR
  349. FPC_INTR:
  350. push bp
  351. mov bp, sp
  352. mov al, byte [bp + 6 + extra_param_offset + extra_data_offset]
  353. mov byte [cs:int_number], al
  354. mov si, [bp + 4 + extra_param_offset]
  355. push ds
  356. %ifdef __FAR_DATA__
  357. mov ax, [bp + 6 + extra_param_offset]
  358. mov ds, ax
  359. %endif
  360. mov ax, word [si + 16]
  361. mov es, ax
  362. mov ax, word [si + 14] ; ds
  363. push ax
  364. mov ax, word [si]
  365. mov bx, word [si + 2]
  366. mov cx, word [si + 4]
  367. mov dx, word [si + 6]
  368. mov bp, word [si + 8]
  369. mov di, word [si + 12]
  370. mov si, word [si + 10]
  371. pop ds
  372. db 0CDh ; opcode of INT xx
  373. int_number:
  374. db 255
  375. pushf
  376. push ds
  377. push si
  378. push bp
  379. mov bp, sp
  380. %ifdef __FAR_DATA__
  381. mov si, [bp + 16 + extra_param_offset]
  382. %else
  383. mov si, word [bp + 8]
  384. %endif
  385. mov ds, si
  386. mov si, word [bp + 14 + extra_param_offset]
  387. mov word [si], ax
  388. mov word [si + 2], bx
  389. mov word [si + 4], cx
  390. mov word [si + 6], dx
  391. mov word [si + 12], di
  392. mov ax, es
  393. mov word [si + 16], ax
  394. pop ax
  395. mov word [si + 8], ax
  396. pop ax
  397. mov word [si + 10], ax
  398. pop ax
  399. mov word [si + 14], ax
  400. pop ax
  401. mov word [si + 18], ax
  402. pop ds
  403. pop bp
  404. %ifdef __FAR_CODE__
  405. retf 4 + extra_data_offset
  406. %else
  407. ret 4 + extra_data_offset
  408. %endif
  409. %ifndef __TINY__
  410. global FPC_CHECK_NULLAREA
  411. FPC_CHECK_NULLAREA:
  412. push ds
  413. pop es
  414. xor di, di
  415. mov cx, 32
  416. mov al, 1
  417. cld
  418. repe scasb
  419. je .skip
  420. dec ax ; 1 byte shorter than dec al
  421. .skip:
  422. %ifdef __FAR_CODE__
  423. retf
  424. %else
  425. ret
  426. %endif
  427. %endif
  428. segment data class=data
  429. %ifdef __NEAR_DATA__
  430. mem_realloc_err_msg:
  431. db 'Memory allocation error', 13, 10, '$'
  432. not_enough_mem_msg:
  433. db 'Not enough memory', 13, 10, '$'
  434. %endif
  435. ; add reference to the beginning of the minimal heap, so the object
  436. ; module, containing the heap segment doesn't get smartlinked away
  437. dd ___heap
  438. segment bss class=bss
  439. %ifndef __TINY__
  440. segment _NULL align=16 class=BEGDATA
  441. global __nullarea
  442. __nullarea:
  443. dd 01010101h, 01010101h, 01010101h, 01010101h
  444. dd 01010101h, 01010101h, 01010101h, 01010101h
  445. segment _AFTERNULL align=2 class=BEGDATA
  446. dw 0
  447. %ifdef __NEAR_DATA__
  448. segment stack stack class=stack
  449. %else
  450. segment data
  451. ; add reference to the beginning of stack, so the object module,
  452. ; containing the stack segment doesn't get smartlinked away
  453. dd ___stack
  454. %endif
  455. %endif
  456. %ifdef __TINY__
  457. group dgroup text data bss
  458. %else
  459. %ifdef __NEAR_DATA__
  460. group dgroup _NULL _AFTERNULL data bss stack
  461. %else
  462. group dgroup _NULL _AFTERNULL data bss
  463. %endif
  464. %endif