Decoded: Sopwith (1984) by David L. Clark
Source file: _INTA.ASM
Beginner friendly, line-by-line code walkthrough by MaiZure

_INTA.ASM has utilities for overriding interrupts in DOS.

Original code:
http://davidlclark.com/page/sopwith-source-code

Original code with line numbers
http://www.maizure.org/projects/decoded-sopwith/_INTS_linenum.txt

NOTE ON ASSEMBLY IN SOPWITH
The original intended assembler for Sopwith code is Microsoft Macro Assembler
(MASM), probably version 2 or 3. This is from the days of segmentation so you'll
see segment:offset accesses to support near addresses. Know your DOS i/o ports
and interrupts (Ask Ralf Brown). The good news is that this old enough that
we can work with 20-bit addresses without considering DOS memory extenders (EMS/XMS,
etc).

1     COMMENT
2     COMMENT
3     COMMENT
4     COMMENT
5     COMMENT
6     COMMENT
7     COMMENT
8     COMMENT
9     COMMENT
10    COMMENT
11    COMMENT
12    COMMENT
13    COMMENT
14    COMMENT
15    COMMENT
16    COMMENT
17    COMMENT
18    COMMENT
19    COMMENT
20    COMMENT
21    COMMENT
22    COMMENT
23    COMMENT
24    COMMENT
25    COMMENT
26    COMMENT
27    COMMENT
28    COMMENT
29    COMMENT
30    COMMENT
31    COMMENT
32    COMMENT
33    COMMENT
34    COMMENT
35    COMMENT
36    COMMENT
37    COMMENT
38    COMMENT
39    COMMENT
40    COMMENT
41    COMMENT
42    COMMENT
43    COMMENT
44    COMMENT
45    COMMENT
46    COMMENT
47    COMMENT
48    COMMENT
49    COMMENT
50    COMMENT
51    COMMENT
52    COMMENT
53    COMMENT
54    COMMENT
55    COMMENT
56    COMMENT
57    BLANK
58    BLANK
59    Sets the assembler to use small memory model using C calling conventions.
      These are passed as arguments to the assembler in the makefile (SW.MAK). Small
      memory model implies data and stack are in the same 64kb segment.
60    Includes macros provided with MASM
61    BLANK
62    Creates a local code segment, linker will combine upcoming code with other
      code  
63    BLANK
64    BLANK
65    Sets the variable holding interrupt table size to 10
66    BLANK
67    Imports @AB variable
68    BLANK
69    Defines function _int1vec, returns base interrupt table address
70    Defines function _int2vec, returns offset interrupt table address
71    Defines function set_ivec, overrides interrupt with custom handler
72    Defines function get_ivec, returns assigned interrupt handler
73    BLANK
74    COMMENT
75    COMMENT
76    COMMENT
77    BLANK

RETURNS ADDRESS OF INTERRUPT TABLE AND OFFETS
78    Defines entry for _int1vec, address of table
79    Pushes current code segment address on to the stack
80    Jumps to procedure for all interrupts
81    Defines entry for _int2vec, address of target interrupt
82    Pushes current code segment + 10 address on to the stack
83    Jumps to procedure for all interrupts
84    Pushes current code segment + 20 address on to the stack
85    Jumps to procedure for all interrupts
86    Pushes current code segment + 30 address on to the stack
87    Jumps to procedure for all interrupts
88    Pushes current code segment + 40 address on to the stack
89    Jumps to procedure for all interrupts
90    Pushes current code segment + 50 address on to the stack
91    Jumps to procedure for all interrupts
92    Pushes current code segment + 60 address on to the stack
93    Jumps to procedure for all interrupts
94    Pushes current code segment + 70 address on to the stack
95    Jumps to procedure for all interrupts
96    Pushes current code segment + 80 address on to the stack
97    Jumps to procedure for all interrupts
98    Pushes current code segment + 90 address on to the stack
99    Jumps to procedure for all interrupts
100   BLANK
101   COMMENT
102   COMMENT
103   COMMENT
104   BLANK
105   Common procedure for all interrupt handlers -- find that handler address
106   Skip further down the stack to a safe place to store temporary registers
107   Store BX
108   Store DS
109   Jump back to original place in the stack frame
110   BLANK
111   Move the default data group segment to BX
112   Move the data group segment in to the data segment register
113   Stack pointer is pointing at interrupt table pushed earlier. Pop to BX
114   BLANK
115   Store flags
116   Push items from table struct on to stack - old code segment
117   Push the old instruction pointer
118   Push the new data data segment
119   Push more flags
120   Push the new code segment
121   Push the new instruction pointer
122   BLANK
123   BLANK
124   Jump back down to stored data for this call
125   Restore DS
126   Restore BX
127   Point stack back to new interrupt IP
128   BLANK
129   iret with new procedure at the top of the stack
130   BLANK
131   COMMENT
132   COMMENT
133   COMMENT
134   BLANK
135   Something went wrong, prepare to abandon ship, clear AH
136   Invoke interrupt 21 with null AH (terminate program)
137   BLANK
138   BLANK
139   COMMENT
140   BLANK
141   i0 resolves to 0. This interrupt struct is at offset 0 in the table
142   i1 resolves to 10.
143   i2 resolves to 20.
144   i3 resolves to 30.
145   i4 resolves to 40.
146   i5 resolves to 50.
147   i6 resolves to 60.
148   i6 resolves to 70.
149   i7 resolves to 80.
150   i8 resolves to 90.
151   BLANK
152   BLANK
153   BLANK

GET INTERRUPT HANDLER
154   Define get_ivec, interrupt number is argument 1 on the stack
155   Save current frame
156   Sart new frame
157   Store ES
158   BLANK
159   Set AH to 0x35, which is the int21 code to return ISR pointer
160   Set AL to the interrupt number to find (first argument on the stack)
161   Invoke interrupt 21. Result is now in ES:BX
162   Move ES to DX
163   Move BX to AX, result is now in DX:AX
164   BLANK
165   Restore ES
166   Restore stack frame
167   Return to caller
168   BLANK
169   BLANK

SET INTERRUPT HANDLER
170   Define set_ivec, interrupt number and offset are on the stack
171   Save stack frame
172   Make new stack frame
173   Store DS
174   BLANK
175   Set AH to 0x25, needs int number in AL and DS:DX to hold the *handler
176   Set AL to interrup number as argument 1 on the stack
177   Load the handler routine from the address at argument 2 on the stack
178   Invoke interrupt 21.
179   BLANK
180   Return data segment
181   Restore stack frame.
182   Return
183   BLANK
184   BLANK
185   BLANK
186   Define the data segment
187   BLANK
188   Import _inttab struct from _INTC.C
189   BLANK
190   End of assembly
191   EOF