| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565 |
- (* Copyright (C) 1987 Jensen & Partners International *)
- (* This assembler module is mainly concerned with implementing
- the multi-processing features of Modula-2 such as
- NEWPROCESS, TRANSFER and IOTRANSFER.
- There are some hardware dependencies, such as the interrupt
- controller port address. A dynamic check is performed to identify
- AT compatibles, otherwise a standard PC compatible is assumed.
- If you are programming non-standard peripherals on a new IBM
- machine such as the PS/2 model 50,60,80 some changes may be necessary.
- *)
- (*
- The "ROM" string denotes those sections requiring modification when
- creating ROMmable code.
- *)
- (*ROM
- A number of these routines make use of the Int 8 timer tick - they are
- marked with an "(*INT8*)" string. If the target machine does not provide
- a user timer tick via Int 8, then 1) don't use any of the facilities that
- need it; or 2) implement an Int 8.
- *)
- (*ROM
- These two values are used when sending an end-of-interrupt to the interrupt
- controller.
- *)
- eoiport = 20H (* the port to write EOI value to *)
- eoiportB = 0A0H (* the port to write EOI valkue to for AT and high int *)
- eoivalue = 20H (* the EOI value which will be written *)
- (*ROM
- These two values are used for accessing the interrupt controller.
- *)
- icport1 = 21H (* port for lower 8 bits of priority mask *)
- icport2 = 0A1H (* port for upper 8 bits of priority mask on AT *)
- (* Process descriptor offsets *)
- NextProcess = 0 (* Next in chain (-1 = end) *)
- (* of waiting processes *)
- LongCall = 2 (* Long call used to point interrupts *)
- LongCallIP = 4 (* at interrupt handler *)
- LongCallCS = 6
- ProcessSP = 8
- ProcessSS = 10
- ProcessPriority = 12
- ProcessFloat = 14
- ProcessRecordSize = 94 + ProcessFloat
- ProcessRecSize = 1 (* paragraphs *)
- ProcessRecSizeFloat = 7 (* paragraphs *)
- module SYSTEM
- segment INITCODE(CODE,28H);
- segment C_CODE(CODE,28H);
- group G_CODE(INITCODE,C_CODE)
- segment MP_DATA(M_DATA,68H)
- select C_CODE
- extrn @D_DATA
- extrn @MachineId
- extrn @CurrentProcess
- extrn @PrtAddrAbort
- extrn @Save8087
- @GetPri: (* read interrupt controller mask *)
- (* on entry, ds = [@D_DATA] *)
- xor ah,ah
- cmp byte [@MachineId],0FCH (*an AT ? *)
- jne @GetPri2
- in al,icport2
- mov ah,al
- @GetPri2:
- in al,icport1
- ret 0
- @SetPri: (* write interrupt controller mask *)
- (* on entry, ds = [@D_DATA] *)
- out icport1,al
- cmp byte [@MachineId],0FCH (*an AT ? *)
- jne @SetPri2
- xchg al,ah
- out icport2,al
- @SetPri2:
- ret 0
- public @NewPrio : (* compiler generated call *)
- pop bx
- push cs
- push bx
- public $NewPrio : (* compiler generated call *)
- push ax
- push dx
- push ds
- mov ds, cs:[@D_DATA]
- call @GetPri
- mov bx,ax
- mov ax,cx
- call @SetPri
- mov cx,bx
- pop ds
- pop dx
- pop ax
- ret far 0
- public @NewPri2 : (* compiler generated call *)
- pop bx
- push cs
- push bx
- public $NewPri2 : (* compiler generated call *)
- push ax
- push dx
- push ds
- mov ds, cs:[@D_DATA]
- call @GetPri
- mov bx, ax
- or ax, cx
- call @SetPri
- mov cx, bx
- pop ds
- pop dx
- pop ax
- ret far 0
- public SYSTEM$Listen : Mask = 6
- push bp; mov bp,sp; push ds
- mov ds, cs:[@D_DATA]
- call @GetPri
- mov bx,ax
- mov cx,[bp][Mask]
- not cx
- and ax,cx
- call @SetPri
- mov ax,bx
- call @SetPri
- pop ds; pop bp; ret far 2
- extrn FIERQQ
- extrn FIDRQQ
- SwapStack :
- (* Procedure used to change stack *)
- (* Inputs: ds = segment of new process record *)
- (* Out: cx = New priority *)
- (* NB Interrupts must be off *)
- (* The following registers are corrupted AX,CX,SI,DI,ES *)
- (* Out: es = Old (swapped) process *)
- mov es, cs:[@D_DATA]
- cmp byte es:[@Save8087], 0
- mov es, es:[@CurrentProcess]
- jne $dosave
- call @Swap
- $exitswap:
- call far $NewPrio
- ret 0
- $dosave: (* swap 8087 registers *)
- fsave es:[ProcessFloat]
- call @Swap
- frstor ds:[ProcessFloat]
- jmp $exitswap
- @Swap:
- (* local procedure to do the stack swap *)
- (* NB The first time a process gets swapped to, this routine returns to StartProcess *)
- cmp word ds:[LongCall],9A90H (* check word *)
- jne $CorruptProcess
- mov bx, ds
- mov ds, cs:[@D_DATA]
- mov [@CurrentProcess],bx
- mov di,ProcessSP
- mov ax,sp
- stosw
- mov ax,ss
- stosw
- call @GetPri
- mov ds, bx
- stosw
- mov si,ProcessSP
- lodsw
- mov sp,ax
- lodsw
- mov ss,ax
- lodsw
- mov cx,ax
- ret 0
- SwapStack2: (* Same as SwapStack but doesnt call $NewPrio *)
- mov es, cs:[@D_DATA]
- cmp byte es:[@Save8087], 0
- mov es, es:[@CurrentProcess]
- jne $dosave
- call @Swap
- jmp $exitswap2
- $dosave2:
- fsave es:[ProcessFloat]
- call @Swap
- frstor ds:[ProcessFloat]
- $exitswap2:
- xchg ax,cx
- push ds
- mov ds, cs:[@D_DATA]
- call @SetPri
- pop ds
- xchg ax,cx
- ret 0
- $CorruptProcess:
- sti
- mov dx,ipdmsg
- call @PrtAddrAbort
- ipdmsg : db "] Invalid process descriptor$"
- public SYSTEM$TRANSFER : p1seg=12; p1off=10; p2seg=8; p2off=6
- push bp; mov bp,sp
- push ds; push es; push si; push di
- pushf
- cli
- mov ds, cs:[@D_DATA]
- mov ax,[@CurrentProcess]
- (* Take copy of p2 *)
- lds bx, [bp][p2off]
- mov ds, [bx][2]
- (* Return result *)
- les bx, [bp][p1off]
- mov word es:[bx], 0
- mov word es:[bx][2],ax
- push bp
- call SwapStack
- pop bp
- popf
- pop di; pop si; pop es; pop ds
- pop bp; ret far 8
- public SYSTEM$IOTRANSFER : p1seg=14; p1off=12; p2seg=10; p2off=8; IntNo=6
- push bp; mov bp,sp
- push ds; push es; push si; push di
- pushf
- cli
- (* Return first result *)
- mov ds, cs:[@D_DATA]
- mov ax, [@CurrentProcess]
- (* Take copy of p2 *)
- lds bx, [bp][p2off]
- mov di, [bx][2]
- lds bx, [bp][p1off]
- mov word [bx],0
- mov [bx][2],ax
- (* Save old interrupt vector and set up new one *)
- sub bx, bx
- mov ds, bx
- mov bx, [bp][IntNo]
- shl bx, 1
- shl bx, 1
- push [bx]
- push [bx][2]
- mov [bx][2], ax (* current process *)
- mov word [bx],LongCall
- push ds
- push bx
- mov ds,di
- push bp
- call SwapStack
- pop bp
- pop bx
- pop ds
- (* Restore old interrupt vector *)
- pop [bx][2]
- pop [bx]
- (* issue EOI to interrupt controller *)
- cmp bx,20H
- jb skipa0
- cmp bx,40H
- mov al,eoivalue
- jae skip20
- out eoiport,al
- jmp skipa0
- skip20:
- cmp bx,1C0H
- jb skipa0
- cmp bx,1E0H
- jae skipa0
- out eoiportB,al (* assuming it's an AT *)
- out eoiport,al (* fix by Greg O'Nielsen *)
- skipa0:
- (* return second result *)
- lds bx, [bp][p2off]
- mov word [bx], 0
- mov [bx][2], es
- popf
- pop di; pop si; pop es; pop ds
- pop bp; ret far 10
- SYSTEM$IntHandler:
- (* On entry the stack has *)
- (* flags *)
- (* cs *)
- (* ip *)
- (* segment of task record of interrupting task ( used to save ax ) *)
- (* offset of ditto ( used to save bx ) *)
- (* Then registers saved in Registers record order *)
- (* flags = 16 *)
- (* CS = 14 *)
- (* IP = 12 *)
- (* 10 (flags copy) *)
- (* 8 (es) *)
- push ds (* 6 *)
- push di (* 4 *)
- push si (* 2 *)
- push bp (* 0 *)
- mov bp, sp
- push dx
- push cx
- push bx
- push ax
- pushf
- cld
- mov ds,ss:[bp][10] (* load ds with new process rec *)
- pop ss:[bp][10]
- mov [bp][8],es
- $preempt:
- call SwapStack2
- $exit:
- pop ax
- pop bx
- pop cx
- pop dx
- pop bp
- pop si
- pop di
- pop ds
- pop es
- add sp,2 (* flags are be restored by iret *)
- iret
- public SYSTEM$NEWPROCESS : pseg=18; poff=16; aseg=14; aoff=12; wspsize=10; p1seg=8; p1off=6
- push bp; mov bp,sp
- push ds; push es; push si; push di
- les di,[bp][aoff] (* address of process workspace *)
- mov bx,[bp][wspsize]
- mov ax,di
- and di,0FH (* amount lost due to normalizing *)
- jz $NoLoss
- sub di,16
- add bx,di
- $NoLoss:
- lds si,[bp][p1off] (* result *)
- add ax,15
- shr ax,1
- shr ax,1
- shr ax,1
- shr ax,1
- mov di,es
- add ax,di
- mov word ds:[si],0
- mov ds:[si][2],ax
- mov ds,ax
- push es
- mov es, cs:[@D_DATA]
- cmp byte es:[@Save8087],0
- pop es
- je $NoSave8087
- add ax,6 (* 94/16 *)
- sub bx,96
- and bx,0FFFEH (* put stack on even boundrary *)
- $NoSave8087:
- inc ax (* size of process record *)
- sub bx,16+12 (* 1 para + return addresses etc *)
- (* initialize record *)
- mov word ds:[NextProcess],-1
- mov word ds:[LongCall],09A90H
- mov word ds:[LongCallIP],SYSTEM$IntHandler
- mov ds:[LongCallCS],cs
- mov ds:[ProcessSS],ax
- mov ds:[ProcessSP],bx
- mov es,ax
- push ds
- mov ds, cs:[@D_DATA]
- call @GetPri
- pop ds
- mov ds:[ProcessPriority],ax
- (* initialize return stack frame *)
- mov di,bx
- mov ax,StartProcess
- stosw
- mov ax,[bp][poff]
- stosw
- mov ax,[bp][pseg]
- stosw
- mov ax,StopProcess
- stosw
- mov ax,cs
- stosw
- pop di; pop si; pop es; pop ds
- pop bp; ret far 14
- extrn @Abort
- FatalError :
- sti
- pop dx
- push cs
- pop ds
- mov ah, 9
- int 21H
- jmp @Abort
- StopProcess:
- call FatalError
- db "Fatal error: Return from process",7,13,10, "$"
- StartProcess:
- (* This is arrived at by first SwapStack *)
- (* IN cx = priority (from SwapStack) *)
- (* Initialize rounding control *)
- push ds
- mov ds, cs:[@D_DATA]
- cmp byte [@Save8087], 0
- pop ds
- je $No8087
- fstcw ds:[ProcessFloat]
- fwait
- or word ds:[ProcessFloat],0C00H
- fldcw ds:[ProcessFloat]
- $No8087:
- (*Initialise bp to zero, enable interrupts and set priority *)
- sub bp,bp
- cld
- call far $NewPrio
- sti
- ret far 0
- (* Utility procedures *)
- public SYSTEM$NewPriority :
- pop bx
- pop dx
- pop cx
- push dx
- push bx
- jmp far $NewPrio
- public SYSTEM$CurrentPriority :
- push ds
- mov ds, cs:[@D_DATA]
- call @GetPri
- pop ds; ret far 0
- public SYSTEM$InterruptRegisters : pseg=8; pofs=6
- push bp; mov bp,sp
- push ds
- (* called to find the registers of an interrupted process *)
- (* after an IOtransfer *)
- mov ds,[bp][pseg]
- mov dx,ds:[ProcessSS]
- mov ax,ds:[ProcessSP]
- add ax,4
- pop ds
- pop bp; ret far 4
- select MP_DATA
- MainProcess : org ProcessRecordSize
- extrn @D_DATA
- select INITCODE
- mov ax, MP_DATA
- mov ds, ax
- mov word [MainProcess], -1
- mov word [MainProcess][2], 9A90H
- mov word [MainProcess][4], SYSTEM$IntHandler
- mov word [MainProcess][6], C_CODE
- mov ds, cs:[@D_DATA]
- mov word [@CurrentProcess], MP_DATA
- section;
- segment C_CODE(CODE,28H); group G_CODE(C_CODE)
- select C_CODE
- extrn @D_DATA
- extrn @CurrentProcess
- public SYSTEM$CurrentProcess :
- (* returns the current process in DX:AX *)
- push ds
- mov ds, cs:[@D_DATA]
- mov dx, [@CurrentProcess]
- pop ds
- sub ax,ax
- ret far 0
- section;
- segment INITCODE(CODE,28H);
- group G_CODE(INITCODE)
- segment D_DATA(M_DATA,28H);
- segment HEAP(HEAP,68H);
- select D_DATA
- public @MachineId : org 1
- public @CurrentProcess : org 2
- public SYSTEM@HeapBase : org 2
- public @Save8087 : org 2 (* must be non zero *)
- (* if floating point context save required *)
- select INITCODE
- extrn @D_DATA
- public SYSTEM@:
- mov ds, cs:[@D_DATA]
- mov word ds:[SYSTEM@HeapBase],HEAP
- mov word [@Save8087], 0
- mov word [@CurrentProcess], 0
- (*ROM
- Get the machine ID byte. A 0FCH identifies an AT - this value is used
- to determine whether the interrupt controller mask is 8-bit (PC) or 16-bit
- (AT).
- *)
- mov ax,0F000H
- mov es,ax
- mov al,es:[0FFFEH]
- mov [@MachineId],al
- end
|