prt0comn.asm 10 KB

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