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