|
|
1.1 root 1:
2: ;
3: ;
4: ; Copyright (C) Microsoft Corporation, 1987
5: ;
6: ; This Module contains Proprietary Information of Microsoft
7: ; Corporation and should be treated as Confidential.
8: ;
9: title emoem.asm - OEM dependent code for 8087
10:
11: ;--------------------------------------------------------------------
12: ;
13: ; OEM customization routines for 8087/80287 coprocessor
14: ;
15: ; This module is designed to work with the following
16: ; Microsoft language releases:
17: ;
18: ; Microsoft C 3.00 and later
19: ; Microsoft FORTRAN 77 3.30 and later
20: ; Microsoft Pascal 3.30 and later
21: ;
22: ; This module supersedes the OEMR7.ASM module used in earlier
23: ; versions of Microsoft FORTRAN 77 and Pascal. The documentation
24: ; provided with the FORTRAN and Pascal releases refers to the old
25: ; OEMR7.ASM module and is only slightly relevant to this module.
26: ;
27: ; The following routines need to be written to properly handle the
28: ; 8087/808287 installation, termination, and interrupt handler
29: ;
30: ; __FPINSTALL87 install 8087 interrupt handler
31: ; __FPTERMINATE87 deinstall 8087 interrupt handler
32: ; __fpintreset reset OEM hardware if an 8087 interrupt
33: ;
34: ; ***** NEW INSTRUCTIONS *****
35: ;
36: ; If you want a PC clone version, do nothing. The libraries are
37: ; setup for working on IBM PC's and clones.
38: ;
39: ; These instructions only need to be followed if a non-IBM PC
40: ; clone version is desired.
41: ;
42: ; This module should be assembled with the
43: ; Microsoft Macro Assembler Version 4.00 or later as follows:
44: ;
45: ; masm -DOEM -r emoem.asm;
46: ;
47: ; Most hardware handles the 8087/80287 in one of the following
48: ; three ways -
49: ;
50: ; 1. NMI - IBM PC and clones all handle the interrupt this way
51: ; 2. single 8259
52: ; 3. master/slave 8259
53: ;
54: ; Manufacturer specific initialization is supported for these 3
55: ; machine configurations either by modifying this file and replacing
56: ; the existing EMOEM module in the math libraries or by patching
57: ; the .LIB and .EXE files directly.
58: ;
59: ; LIB 87-+EMOEM;
60: ; LIB EM-+EMOEM;
61: ;
62: ;--------------------------------------------------------------------
63:
64: ifdef OEM
65: if1
66: %out OEM version for non-clone support
67: endif
68: endif
69:
70: ;---------------------------------------------------------------------
71: ; Assembly constants.
72: ;---------------------------------------------------------------------
73:
74: ; MS-DOS OS calls
75:
76: OPSYS EQU 21H
77: SETVECOP EQU 25H
78: GETVECOP EQU 35H
79: DOSVERSION EQU 30h
80: CTLCVEC EQU 23h
81:
82: EMULATOR_DATA segment public 'FAR_DATA'
83: assume ds:EMULATOR_DATA
84:
85: ; User may place data here if DS is setup properly.
86: ; Recommend keeping the data items in the code segment.
87:
88: EMULATOR_DATA ends
89:
90:
91:
92: EMULATOR_TEXT segment public 'CODE'
93: assume cs:EMULATOR_TEXT
94:
95: public __FPINSTALL87 ; DO NOT CHANGE THE CASE ON
96: public __FPTERMINATE87 ; THESE PUBLIC DEFINITIONS
97:
98: extrn __FPEXCEPTION87:near ; DO NOT CHANGE CASE
99:
100:
101: ifdef OEM
102:
103: ;***********************************************************************
104: ;
105: ; Hardware dependent parameters in the 8087 exception handler.
106: ;
107: ; For machines using 2 8259's to handle the 8087 exception, be sure that
108: ; the slave 8259 is the 1st below and the master is the 2nd.
109: ;
110: ; The last 4 fields allow you to enable extra interrupt lines into the
111: ; 8259s. It should only be necessary to use these fields if the 8087
112: ; interrupt is being masked out by the 8259 PIC.
113: ;
114: ; The ocw2's (EOI commands) can be either non-specific (20H) or
115: ; specific (6xH where x=0 to 7). If you do not know which interrupt
116: ; request line on the 8259 the 8087 exception uses, then you should issue
117: ; the non-specific EOI (20H). Interrupts are off at this point in the
118: ; interrupt handler so a higher priority interrupt will not be seen.
119:
120: oeminfo struc
121: oemnum db 0 ; MS-DOS OEM number (IBM is 00h)
122: intnum db 2 ; IBM PC clone interrupt number
123: share db 0 ; nonzero if original vector should be taken
124: a8259 dw 0 ; 1st 8259 (A0=0) port #
125: aocw2 db 0 ; 1st 8259 (A0=0) EOI command
126: b8259 dw 0 ; 2nd 8259 (A0=0) port #
127: bocw2 db 0 ; 2nd 8259 (A0=0) EOI command
128: a8259m dw 0 ; 1st 8259 (A0=1) port #
129: aocw1m db 0 ; 1st 8259 (A0=1) value to mask against IMR
130: b8259m dw 0 ; 2nd 8259 (A0=1) port #
131: bocw1m db 0 ; 2nd 8259 (A0=1) value to mask against IMR
132: oeminfo ends
133:
134: ;-----------------------------------------------------------------------
135: ; OEM specific 8087 information
136: ;
137: ; If the OEM number returned from the DOS version call matches,
138: ; this information is automatically moved into the oem struc below.
139:
140: oemtab label byte ; Table of OEM specific values for 8087
141:
142: ; OEM#, int, shr, a59, acw2,b59, bcw2,a59m,acw1,b59m,bcw1
143:
144: ;TI Professional Computer
145: TI_prof oeminfo <028h,047h,000h,018h,020h,0000,0000,0000,0000,0000,0000>
146:
147: db 0 ; end of table
148:
149: ; Unique pattern that can be searched for with the debugger so that
150: ; .LIB or .EXE files can be patched with the correct values.
151: ; If new values are patched into .LIB or .EXE files, care must be
152: ; taken in insure the values are correct. In particular, words and
153: ; bytes are intermixed in oeminfo structure. Remember words are
154: ; stored low byte - high byte in memory on the 8086 family.
155:
156: db '<<8087>>' ; older versions used '<8087>'
157:
158: ; Some manufacturer's machines can not be differentiated by the
159: ; OEM number returned by the MS-DOS version check system call.
160: ; For these machines it is necessary to replace the line below
161:
162: oem1 oeminfo <> ; default values for IBM PC & clones
163:
164: ; with one of the following. If your machine has an 8087 capability
165: ; and it is not in the list below, you should contact your hardware
166: ; manufacturer for the necessary information.
167:
168: ;ACT Apricot
169: ;oem1 oeminfo <000h,055h,000h,000h,020h,000h,000h,000h,000h,000h,000h>
170:
171: ;NEC APC3 and PC-9801 (OEM number returned by NEC MS-DOS's is different)
172: ;oem1 oeminfo <000h,016h,000h,008h,066h,000h,067h,00Ah,0BFh,002h,07Fh>
173:
174: ;---------------------------------------------------------------------
175:
176: aoldIMR db 0 ; 1st 8259 original IMR value
177: boldIMR db 0 ; 2nd 8259 original IMR value
178:
179: endif ;OEM
180:
181: statwd dw 0 ; Temporary for status word
182: oldvec dd 0 ; Old value in 8087 exception interrupt vector
183: ctlc dd 0 ; Old value of Control-C vector (INT 23h)
184:
185: page
186:
187: ;---------------------------------------------------------------------
188: ;
189: ; Perform OEM specific initialization of the 8087.
190: ;
191:
192: __FPINSTALL87:
193: push ds ; DS = EMULATOR_DATA
194:
195: push cs ; Move current CS to DS for opsys calls.
196: pop ds
197: assume ds:EMULATOR_TEXT
198:
199: ifdef OEM
200: push ds
201: pop es ; CS = DS = ES
202: mov ah,DOSVERSION
203: int OPSYS ; bh = OEM#
204: cld
205: mov si,offset oemtab ; start of OEM 8087 info table
206: mov di,offset oem1+1
207: mov cx,(size oem1)-1
208: OEMloop:
209: lodsb ; get OEM#
210: or al,al
211: jz OEMdone ; OEM# = 0 - did not find OEM
212: cmp al,bh ; correct OEM#
213: je OEMfound
214: add si,cx ; skip over OEM information
215: jmp OEMloop
216:
217: OEMfound:
218: rep movsb ; move the information
219:
220: OEMdone: ; done with automatic customization
221: endif ;OEM
222:
223: ; Save old interrupt vector.
224: ; Ask operating system for vector.
225:
226: ifdef OEM
227: mov al,[oem1].intnum ; Interrupt vector number.
228: mov ah,GETVECOP ; Operating system call interrupt.
229: else
230: mov ax,GETVECOP shl 8 + 2 ; get interrupt vector 2
231: endif ;OEM
232: int OPSYS ; Call operating system.
233: mov word ptr [oldvec],bx ; Squirrel away old vector.
234: mov word ptr [oldvec+2],es
235:
236: ; Have operating system install interrupt vectors.
237:
238: mov dx,offset __fpinterrupt87 ; Load DX with 8087 interrupt handler.
239: ifdef OEM
240: mov ah,SETVECOP ; Set interrupt vector code in AH.
241: mov al,[oem1].intnum ; Set vector number.
242: else
243: mov ax,SETVECOP shl 8 + 2 ; set interrupt vector 2
244: endif ;OEM
245: int OPSYS ; Install vector.
246:
247: ; Intercept Control-C vector to guarentee cleanup
248:
249: mov ax,GETVECOP shl 8 + CTLCVEC
250: int OPSYS
251: mov word ptr [ctlc],bx
252: mov word ptr [ctlc+2],es
253: mov dx,offset ctlcexit
254: mov ax,SETVECOP shl 8 + CTLCVEC
255: int OPSYS
256:
257: ifdef OEM
258:
259: ; set up 8259's so that 8087 interrupts are enabled
260:
261: mov ah,[oem1].aocw1m ; get mask for 1st 8259 IMR
262: or ah,ah ; if 0, don't need to do this
263: jz installdone ; and only 1 8259
264: mov dx,[oem1].a8259m ; get port number for 1st 8259 (A0=1)
265: in al,dx ; read old IMR value
266: mov [aoldIMR],al ; save it to restore at termination
267: and al,ah ; mask to enable interrupt
268: jmp short $+2 ; for 286's
269: out dx,al ; write out new mask value
270:
271: mov ah,[oem1].bocw1m ; get mask for 2nd 8259 IMR
272: or ah,ah ; if 0, don't need to do this
273: jz installdone ;
274: mov dx,[oem1].b8259m ; get port number for 2nd 8259 (A0=1)
275: in al,dx ; read old IMR value
276: mov [boldIMR],al ; save it to restore at termination
277: and al,ah ; mask to enable interrupt
278: jmp short $+2 ; for 286's
279: out dx,al ; write out new mask value
280:
281: installdone:
282:
283: endif ;OEM
284:
285: assume ds:EMULATOR_DATA
286: pop ds
287: ret
288:
289:
290: page
291: ; __FPTERMINATE87
292: ;
293: ; This routine should do the OEM 8087 cleanup. This routine is called
294: ; before the program exits.
295: ;
296: ; DS = EMULATOR_DATA
297:
298: __FPTERMINATE87:
299: push ds
300: push ax
301: push dx
302:
303: ifdef OEM
304: mov ah,SETVECOP
305: mov al,[oem1].intnum
306: else
307: mov ax,SETVECOP shl 8 + 2
308: endif ;OEM
309: lds dx,[oldvec]
310: int OPSYS
311:
312: ifdef OEM
313:
314: ; reset 8259 IMR's to original state
315:
316: push cs
317: pop ds ; DS = CS
318: assume ds:EMULATOR_TEXT
319: cmp [oem1].aocw1m,0 ; did we have to change 1st 8259 IMR
320: je term2nd8259 ; no - check 2nd 8259
321: mov al,[aoldIMR] ; get old IMR
322: mov dx,[oem1].a8259m ; get 1st 8259 (A0=1) port #
323: out dx,al ; restore IMR
324:
325: term2nd8259:
326: cmp [oem1].bocw1m,0 ; did we have to change 2nd 8259 IMR
327: je terminatedone ; no
328: mov al,[boldIMR] ; get old IMR
329: mov dx,[oem1].b8259m ; get 2nd 8259 (A0=1) port #
330: out dx,al ; restore IMR
331:
332: terminatedone:
333:
334: endif ;OEM
335:
336: pop dx
337: pop ax
338: pop ds
339: assume ds:EMULATOR_DATA
340: ret
341:
342:
343: ; Forced cleanup of 8087 exception handling on Control-C
344:
345: ctlcexit:
346: push ax
347: push dx
348: push ds
349: call __FPTERMINATE87 ; forced cleanup of exception handler
350: lds dx,[ctlc] ; load old control C vector
351: mov ax,SETVECOP shl 8 + CTLCVEC
352: int OPSYS
353: pop ds
354: pop dx
355: pop ax
356: jmp [ctlc] ; go through old vector
357:
358: page
359: ; __fpinterrupt87
360: ;
361: ; This is the 8087 exception interrupt routine.
362: ;
363: ; All OEM specific interrupt and harware handling should be done in
364: ; __fpintreset because __FPEXCEPTION87 (the OEM independent 8087
365: ; exception handler) may not return. __FPEXCEPTION87 also turns
366: ; interrupts back on.
367: ;
368:
369: PENDINGBIT= 80h ; Bit in status word for interrupt pending
370:
371: __fpinterrupt87:
372: assume ds:nothing
373: nop
374: fnstsw [statwd] ; Store out exceptions
375: push cx ; waste time
376: mov cx,3
377: self:
378: loop self
379: pop cx
380: test byte ptr [statwd],PENDINGBIT ; Test for 8087 interrupt
381: jz not87int ; Not an 8087 interrupt.
382:
383: ifdef OEM
384: call __fpintreset ; OEM interrupt reset routine
385: endif ;OEM
386:
387: call __FPEXCEPTION87 ; 8087 error handling - may not return
388: ; this routine turns interrupts back on
389:
390: ifdef OEM
391: cmp [oem1].share,0 ; Should we execute the old interrupt routine?
392: jnz not87int ; if so then do it
393: ; else return from interrupt
394:
395: ; If you fall through here to do further hardware resetting, things
396: ; may not always work because __FPEXCEPTION87 does not always return
397: ; This only happens when the 8087 handler gets an exception that is
398: ; a fatal error in the language runtimes. I.e., divide by zero
399: ; is a fatal error in all the languages, unless the control word has
400: ; set to mask out divide by zero errors.
401:
402: endif ;OEM
403:
404: done8087:
405: iret
406:
407: not87int:
408: jmp [oldvec] ; We should never return from here.
409:
410:
411: ifdef OEM
412:
413:
414: __fpintreset:
415: push ax
416: push dx
417: mov al,[oem1].aocw2 ; Load up EOI instruction.
418: or al,al ; Is there at least one 8259 to be reset?
419: jz Reset8259ret ; no
420: mov dx,[oem1].a8259
421: out dx,al ; Reset (master) 8259 interrupt controller.
422: mov al,[oem1].bocw2 ; Load up EOI instruction.
423: or al,al ; Is there a slave 8259 to be reset?
424: jz Reset8259ret
425: mov dx,[oem1].b8259
426: out dx,al ; Reset slave 8259 interrupt controller.
427:
428: Reset8259ret:
429: pop dx
430: pop ax
431: ret
432:
433: endif ;OEM
434:
435:
436: EMULATOR_TEXT ends
437:
438: end
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.