Category : Forth Source Code
Archive   : HLINT.ZIP
Filename : HLINT.SEQ

 
Output of file : HLINT.SEQ contained in archive : HLINT.ZIP
\ Words to support interrupt service routines written in high level code Ver1.0
\ Public Domain 09/01/90 by Tim Hendtlass, portions of the interrupt install
\ and un-install by Dr. C.H. Ting

hex
\ ** CONVENIENCE WORDS FOR CHECKING AND INSTALLING INTERRUPT VECTORS **

\ Install the address ISRaddress as the interrupt vector for ISR number Int#
CODE INSTALL-INTERRUPT ( ISRaddress Int# -- )
POP AX \ get interrupt number
POP DX \ get offset in code segment to ISR
PUSH DS \ save as we need it
MOV AH, # 25 \ we require service number 25 hex
PUSH CS \ ISR segment is the current code segment (cs)
POP DS \ DOS expects it in ds
INT 21 \ let DOS do the work
POP DS \ restore original ds we saved
NEXT \ thats it, return no values
END-CODE

\ Read the interrupt vector currently installed for ISR number int#
CODE ?INTERRUPT ( int# -- seg offset )
POP AX \ get interrupt number
PUSH ES \ preserve..
PUSH BX \ .. two registers
MOV AH, # 35 \ DOS service number to AX
INT 21 \ call DOS
MOV DX, ES \ segment returned in ES to DX
MOV AX, BX \ offset returned in BX to AX
POP BX \ restore...
POP ES \ ..those registers
2PUSH \ put answer on stack
END-CODE

\ re-install the original interrupt vector for ISR number int#
CODE RE-INSTALL-INTERRUPT ( seg offset int# -- )
POP AX \ interrupt number to ax
POP DX \ ISR offset address to dx
MOV BX, DS \ save ds in bx
POP DS \ ISR segment address to ds
MOV AH, # 25 \ we want service 25 hex
PUSH BX \ save original ds
INT 21 \ call DOS
POP DS \ restore the saved ds
NEXT
END-CODE

\ Install a noop interrupt service routine (at F000:FF53 in BIOS).
CODE REMOVE-INTERRUPT ( int# -- )
CLI \ we dare not be interrupted while we do this
POP BX
ADD BX, BX
ADD BX, BX \ calculate interrupt vector address, int# * 4
PUSH DS
XOR AX, AX
PUSH AX
POP DS \ clear ds so it points to base of interrupt vector table
MOV AX, # FF53 \ offset of noop service routine
MOV 0 [BX], AX \ put into place
MOV AX, # F000 \ and the correct segment of BIOS ROM
MOV 2 [BX], AX \ also into place
POP DS
STI \ interrupts ok again from now
NEXT
END-CODE

\ *** HIGH LEVEL EQUIVALENTS OF ASSEMBLY LANGUAGE INSTRUCTIONS ***

code INT-ON \ enables further interrupts
sti
next
end-code
code INT-OFF \ disables further interrupts
cli
next
end-code

comment:
REMEMBER to either replace the original vector or remove the Forth vector before
you quit Forth. If you get an interrupt and the ISR code the interrupt vector
points to is not present, you will CRASH!
comment;

\ ***************** END OF CONVENIENCE WORDS ********************

Comment:
Set up a stack of stacks to use during ISR's. The number of stacks available will
deturmine how deep ISR's can be nested. On entry to the ISR a variable STACK-BASE
is read to get the initial value of the data stack pointer and then this is incremented
by STACK-SIZE so it points to the next stack to use. The return stack pointer is
initialized to the data stack pointer minus RSTACK-OFFSET. At the time of exit from
the ISR the value of STACK-BASE is decrmented by STACK-SIZE. In the interests of
speed, no check is made to see that you do not run out of ISR stacks (that is
have interrupts nested too deep)
comment;

100 constant STACK-SIZE \ size of data stack plus return stack
A0 constant RSTACK-OFFSET \ depth of data stack (offset to return stack)
5 constant STACK-NUMBER \ # stacks = nesting depth of ISRs
variable STACK-BASE \ place to keep the top of the current stack
create ISR-STACKS \ pointer to bottom of the stack of stacks
stack-size stack-number * allot \ leave space for the stacks.
isr-stacks stack-size + stack-base ! \ initialize base pointer



LABEL ISRENTRY ( stack on entry = pc cs flags n )
( old stack on exit = pc cs flags n ax di bp bx ds )
( new stack on exit = es si old-sp old-ss cx dx )
\ n is the offset in list space to the list of high level words to do in this ISR.
\ use the stack we are in when the interrupt occurred to save some information
PUSH AX PUSH DI PUSH BP \ save ax di and bp for later restoration
MOV BP, SP \ stack pointer to bp
MOV DI, 6 [BP] \ adr of offset to list to process (n) to di
MOV CS: AX, 0 [DI] \ get the actual offset (from the code segment)
PUSH BX \ we will also need BX
PUSH DS \ and DS
\ old stack is now pc cs flags n ax di bp bx ds.
\ Register ax contains the actual offset into Forth list space
\ switch to new stack
MOV BP, SP MOV DI, SS \ save old stack pointers in bp and di
MOV BX, CS \ new stack segnment is our new code segment
MOV SS, BX
MOV DS, BX \ data seg = stack seg = current code seg
MOV BX, # STACK-BASE \ get new stack pointer
MOV SP, 0 [BX] \ new stack set up
\ now finish setting up the registers for Forth and saving any registers not already saved
ADD 0 [BX], # STACK-SIZE WORD \ adjust stack-base lest this interrupt gets interrupted
PUSH ES PUSH SI \ save registers we are going to use
ADD AX, # XSEG @ MOV ES, AX \ ensure that es points to the correct list segment
SUB IP, IP \ clear IP (si)
PUSH BP PUSH DI PUSH CX PUSH DX

\ set up new return stack pointer for Forth
MOV BP, SP SUB BP, # RSTACK-OFFSET


\ all ready, go do the ISR. New stack now es si old-sp old-ss cx dx
NEXT
END-CODE

\ A special word to clean up and exit the ISR
CODE ISREXIT ( old stack on entry = pc cs flags n ax di bp bx ds )
( new stack on entry = es si old-sp old-ss cx dx )
( both stacks empty on exit )

\ adjust stack-base down one level
MOV BX, # STACK-BASE
SUB 0 [BX], # STACK-SIZE WORD

\ restore the registers we saved on the ISR stack
POP DX POP CX POP AX POP BP POP SI POP ES

\ finished with ISR stack, switch back to the entry stack
MOV SP, BP MOV SS, AX

\ restore all but one of the registers we had on the entry stack
POP DS POP BX POP BP POP DI

\ re-enable the interrupt controller by writing 20hex to port 20hex
MOV AL, # 20 OUT # 20 AL

\ restore last register and lose adr of offset to list we just processed
POP AX ADD SP, # 2

\ finished with this interrupt
IRET
END-CODE

: ISR: \ Interrupt Service Routine defining word
\ build the name and list of things to do
create \ build header (in head seg) & a call to >next in code seg
xhere paragraph + dup \ justify list dictionary pointer to next multiple of 16
xdpseg ! \ save one copy into xdpseg
xseg @ - \ calc offset from xseg to where list will start
, \ save this immediately after the jump in code space
xdp off \ set xdp to 0
] \ compile the colon words that make up the ISR
\ continue until compiler turned off by ISR:
isrentry \ get absolute address of the run time routine we want to use
last @ \ get name field address of last definition (this one)
name> \ move to start of code field
1+ \ move over the call
tuck 2+ - \ calculate relative offset
swap ! \ install offset to isrentry in our run time call
;

: ISR;
state @ 0= abort" Not compiling an ISR!" \ abort if word used out of turn
?csp \ check for any stack errors
compile ISRexit \ add special word to clean up and exit the ISR
[compile] [ ; immediate \ terminate our ISR definition and turn off compiler

decimal



  3 Responses to “Category : Forth Source Code
Archive   : HLINT.ZIP
Filename : HLINT.SEQ

  1. Very nice! Thank you for this wonderful archive. I wonder why I found it only now. Long live the BBS file archives!

  2. This is so awesome! 😀 I’d be cool if you could download an entire archive of this at once, though.

  3. But one thing that puzzles me is the “mtswslnkmcjklsdlsbdmMICROSOFT” string. There is an article about it here. It is definitely worth a read: http://www.os2museum.com/wp/mtswslnk/