prt0comn.asm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  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_start + 2], ax
  200. ; get our MCB size in paragraphs
  201. mov cx, word [__fpc_PrefixSeg]
  202. dec cx
  203. mov es, cx
  204. mov bx, word [es:3]
  205. add bx, cx
  206. inc bx
  207. ; __nearheap_end := end_of_dos_memory_block
  208. mov word [__nearheap_end], 0
  209. mov word [__nearheap_end + 2], bx
  210. %endif
  211. %ifdef __FAR_CODE__
  212. jmp far PASCALMAIN
  213. %else
  214. jmp PASCALMAIN
  215. %endif
  216. %ifdef __NEAR_DATA__
  217. not_enough_mem:
  218. mov dx, not_enough_mem_msg
  219. jmp error_msg
  220. mem_realloc_err:
  221. ; at this point there's still (ds-psp) pushed on the stack, but we won't
  222. ; bother popping it, because we exit to DOS with an error message here
  223. mov dx, mem_realloc_err_msg
  224. error_msg:
  225. mov ah, 9
  226. int 21h
  227. mov ax, 4CFFh
  228. int 21h
  229. %endif
  230. FPC_INT00_HANDLER:
  231. sub sp, 4 ; reserve space on the stack for the retf
  232. push cx
  233. push ds
  234. push bp
  235. ; init ds
  236. %ifdef __TINY__
  237. mov bp, cs
  238. %else
  239. mov bp, dgroup
  240. %endif
  241. mov ds, bp
  242. %ifdef __NEAR_DATA__
  243. ; in memory models, where SS=DS, also
  244. ; check whether we're running on the same stack
  245. mov cx, ss
  246. cmp bp, cx
  247. jne .call_previous_handler
  248. %endif
  249. %ifndef __FAR_CODE__
  250. ; check whether we're coming from the same code segment
  251. mov bp, sp
  252. mov cx, [bp + 3*2 + 6] ; get caller segment
  253. mov bp, cs
  254. cmp bp, cx
  255. jne .call_previous_handler
  256. %endif
  257. ; runerror 200
  258. mov bp, sp
  259. mov cx, [bp + 3*2 + 4] ; get caller offset
  260. %ifdef __FAR_CODE__
  261. mov dx, [bp + 3*2 + 6] ; get caller segment
  262. %endif
  263. pop bp
  264. add sp, 2*2 + 4 + 6
  265. xor ax, ax
  266. push ax
  267. mov ax, 200
  268. push ax
  269. %ifdef __FAR_CODE__
  270. push dx
  271. %endif
  272. push cx
  273. cld
  274. %ifdef __FAR_CODE__
  275. jmp far FPC_HANDLEERROR
  276. %else
  277. jmp FPC_HANDLEERROR
  278. %endif
  279. .call_previous_handler:
  280. mov bp, sp
  281. mov cx, [__SaveInt00]
  282. mov [bp + 3*2], cx
  283. mov cx, [__SaveInt00+2]
  284. mov [bp + 3*2 + 2], cx
  285. pop bp
  286. pop ds
  287. pop cx
  288. retf ; jumps to the previous handler with all registers and stack intact
  289. global FPC_INSTALL_INTERRUPT_HANDLERS
  290. FPC_INSTALL_INTERRUPT_HANDLERS:
  291. push ds
  292. ; save old int 00 handler
  293. mov ax, 3500h
  294. int 21h
  295. mov [__SaveInt00], bx
  296. mov bx, es
  297. mov [__SaveInt00+2], bx
  298. ; install the new int 00 handler
  299. %ifndef __TINY__
  300. push cs
  301. pop ds
  302. %endif
  303. mov dx, FPC_INT00_HANDLER
  304. mov ax, 2500h
  305. int 21h
  306. pop ds
  307. %ifdef __FAR_CODE__
  308. retf
  309. %else
  310. ret
  311. %endif
  312. global FPC_RESTORE_INTERRUPT_HANDLERS
  313. FPC_RESTORE_INTERRUPT_HANDLERS:
  314. push ds
  315. mov ax, 2500h
  316. lds dx, [__SaveInt00]
  317. int 21h
  318. pop ds
  319. %ifdef __FAR_CODE__
  320. retf
  321. %else
  322. ret
  323. %endif
  324. global FPC_MSDOS_CARRY
  325. FPC_MSDOS_CARRY:
  326. stc
  327. global FPC_MSDOS
  328. FPC_MSDOS:
  329. mov al, 21h ; not ax, because only the low byte is used
  330. pop dx
  331. %ifdef __FAR_CODE__
  332. pop bx
  333. %endif
  334. pop cx
  335. %ifdef __FAR_DATA__
  336. pop si
  337. %endif
  338. push ax
  339. %ifdef __FAR_DATA__
  340. push si
  341. %endif
  342. push cx
  343. %ifdef __FAR_CODE__
  344. push bx
  345. %endif
  346. push dx
  347. global FPC_INTR
  348. FPC_INTR:
  349. push bp
  350. mov bp, sp
  351. mov al, byte [bp + 6 + extra_param_offset + extra_data_offset]
  352. mov byte [cs:int_number], al
  353. mov si, [bp + 4 + extra_param_offset]
  354. push ds
  355. %ifdef __FAR_DATA__
  356. mov ax, [bp + 6 + extra_param_offset]
  357. mov ds, ax
  358. %endif
  359. mov ax, word [si + 16]
  360. mov es, ax
  361. mov ax, word [si + 14] ; ds
  362. push ax
  363. mov ax, word [si]
  364. mov bx, word [si + 2]
  365. mov cx, word [si + 4]
  366. mov dx, word [si + 6]
  367. mov bp, word [si + 8]
  368. mov di, word [si + 12]
  369. mov si, word [si + 10]
  370. pop ds
  371. db 0CDh ; opcode of INT xx
  372. int_number:
  373. db 255
  374. pushf
  375. push ds
  376. push si
  377. push bp
  378. mov bp, sp
  379. %ifdef __FAR_DATA__
  380. mov si, [bp + 16 + extra_param_offset]
  381. %else
  382. mov si, word [bp + 8]
  383. %endif
  384. mov ds, si
  385. mov si, word [bp + 14 + extra_param_offset]
  386. mov word [si], ax
  387. mov word [si + 2], bx
  388. mov word [si + 4], cx
  389. mov word [si + 6], dx
  390. mov word [si + 12], di
  391. mov ax, es
  392. mov word [si + 16], ax
  393. pop ax
  394. mov word [si + 8], ax
  395. pop ax
  396. mov word [si + 10], ax
  397. pop ax
  398. mov word [si + 14], ax
  399. pop ax
  400. mov word [si + 18], ax
  401. pop ds
  402. pop bp
  403. %ifdef __FAR_CODE__
  404. retf 4 + extra_data_offset
  405. %else
  406. ret 4 + extra_data_offset
  407. %endif
  408. %ifndef __TINY__
  409. global FPC_CHECK_NULLAREA
  410. FPC_CHECK_NULLAREA:
  411. push ds
  412. pop es
  413. xor di, di
  414. mov cx, 32
  415. mov al, 1
  416. cld
  417. repe scasb
  418. je .skip
  419. dec ax ; 1 byte shorter than dec al
  420. .skip:
  421. %ifdef __FAR_CODE__
  422. retf
  423. %else
  424. ret
  425. %endif
  426. %endif
  427. segment data class=data
  428. %ifdef __NEAR_DATA__
  429. mem_realloc_err_msg:
  430. db 'Memory allocation error', 13, 10, '$'
  431. not_enough_mem_msg:
  432. db 'Not enough memory', 13, 10, '$'
  433. %endif
  434. ; add reference to the beginning of the minimal heap, so the object
  435. ; module, containing the heap segment doesn't get smartlinked away
  436. dd ___heap
  437. segment bss class=bss
  438. %ifndef __TINY__
  439. segment _NULL align=16 class=BEGDATA
  440. global __nullarea
  441. __nullarea:
  442. dd 01010101h, 01010101h, 01010101h, 01010101h
  443. dd 01010101h, 01010101h, 01010101h, 01010101h
  444. segment _AFTERNULL align=2 class=BEGDATA
  445. dw 0
  446. %ifdef __NEAR_DATA__
  447. segment stack stack class=stack
  448. %else
  449. segment data
  450. ; add reference to the beginning of stack, so the object module,
  451. ; containing the stack segment doesn't get smartlinked away
  452. dd ___stack
  453. %endif
  454. %endif
  455. %ifdef __TINY__
  456. group dgroup text data bss
  457. %else
  458. %ifdef __NEAR_DATA__
  459. group dgroup _NULL _AFTERNULL data bss stack
  460. %else
  461. group dgroup _NULL _AFTERNULL data bss
  462. %endif
  463. %endif