prt0comn.asm 12 KB

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