TSR.MOD 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. (*========================================================
  2. == JPI-TopSpeed Modula-2 V2 ==
  3. == demo program: ==
  4. == ==
  5. == TSR Shell ==
  6. == ==
  7. == Installs a "safe" Pop Up program ==
  8. == ==
  9. ========================================================*)
  10. (*# check(stack=>off,index=>off,range=>off,overflow=>off,nil_ptr=>off) *)
  11. (*# debug(vid=>off)*)
  12. IMPLEMENTATION MODULE TSR ;
  13. (* === *)
  14. IMPORT IO,Window,Lib,Storage,Str,SYSTEM,TSRLow;
  15. CONST
  16. KBFuseful = KBFlagSet { RShift, LShift, Ctrl, Alt } ;
  17. TYPE
  18. TSRmodeType = (Sleeping,Wake,Active,Kill,Dead ) ;
  19. VAR
  20. (*# save, data(volatile=>on) *)
  21. ProgDTA : ADDRESS ;
  22. ProgPSP : CARDINAL ;
  23. ActivateScan : SHORTCARD ;
  24. ActivateFlags : KBFlagSet ;
  25. KBFlags[40H:17H] : KBFlagSet ;
  26. TSRproc : PROC ;
  27. DosNest : POINTER TO SHORTCARD ;
  28. TSRmode : TSRmodeType ;
  29. MainProcess : SYSTEM.PROCESS;
  30. (*# restore *)
  31. PROCEDURE SwapToTSR ;
  32. VAR
  33. op,np : SYSTEM.PROCESS ;
  34. BEGIN
  35. TSRmode := Active ;
  36. np := MainProcess ;
  37. SYSTEM.TRANSFER(op,np) ; (* can't use IOTRANSFER due to chaining problems
  38. with other TSRs (SideKick 1, for example) *)
  39. TSRmode := Sleeping ;
  40. END SwapToTSR ;
  41. (* Interrupt Handlers *)
  42. (* ================== *)
  43. (* pragmas for interrupt handler *)
  44. (*# save,
  45. call(interrupt => on,
  46. reg_param => (),
  47. same_ds => off
  48. )
  49. *)
  50. TYPE
  51. IPROC = PROCEDURE();
  52. VAR
  53. Irpt[0:0], (* Interrupt table *)
  54. SaveIrpt : ARRAY [0..255] OF IPROC ;
  55. PROCEDURE NullInt () ; (* Do nothing interrupt *)
  56. BEGIN
  57. END NullInt;
  58. PROCEDURE Int9 () ; (* Keyboard H/W interrupt *)
  59. VAR
  60. sc : SHORTCARD ;
  61. BEGIN
  62. sc := SYSTEM.In(60H) ;
  63. IF ((sc=ActivateScan)OR(ActivateScan=0))AND
  64. ((KBFlags*KBFuseful)=ActivateFlags) THEN
  65. sc := SYSTEM.In(61H) ;
  66. SYSTEM.Out(61H,SHORTCARD(BITSET(sc)+{7}));
  67. SYSTEM.Out(61H,sc);
  68. SYSTEM.Out(20H,20H);
  69. IF TSRmode=Sleeping THEN
  70. TSRmode := Wake ;
  71. END ;
  72. ELSE
  73. SaveIrpt[09H]() ; (* Chain Int 28 *)
  74. END ;
  75. END Int9 ;
  76. VAR
  77. Save28stack : ARRAY[0..3FFH] OF BYTE ;
  78. PROCEDURE Int28 () ; (* DOS "I'm not doing much" interrupt *)
  79. VAR
  80. base : CARDINAL ;
  81. BEGIN
  82. Lib.Move(ADR(base),ADR(Save28stack),SIZE(Save28stack));
  83. SaveIrpt[28H]() ; (* Chain Int 28 *)
  84. IF (Ofs(base)>100H) AND (TSRmode=Wake) THEN
  85. SwapToTSR ;
  86. END ;
  87. Lib.Move(ADR(Save28stack),ADR(base),SIZE(Save28stack));
  88. END Int28 ;
  89. PROCEDURE Int1C () ; (* Timer Interrupt *)
  90. VAR
  91. base : CARDINAL ;
  92. BEGIN
  93. SaveIrpt[1CH]() ; (* Chain Int 1C *)
  94. IF (Ofs(base)>100H)AND(DosNest^ = 0)AND(TSRmode=Wake) THEN
  95. SYSTEM.Out(20H,20H) ; (* Send EOI to timer *)
  96. SwapToTSR ;
  97. END ;
  98. END Int1C ;
  99. PROCEDURE Int24 () : CARDINAL ; (* Critical Error Interrupt *)
  100. BEGIN
  101. RETURN 0 ;
  102. END Int24;
  103. (*# restore *)
  104. PROCEDURE SetIrpt ( N : CARDINAL ; P : IPROC ) ;
  105. VAR
  106. fl : CARDINAL ;
  107. BEGIN
  108. fl := SYSTEM.GetFlags() ; SYSTEM.DI ;
  109. SaveIrpt[N] := Irpt[N] ;
  110. Irpt[N] := P ;
  111. SYSTEM.SetFlags(fl) ;
  112. END SetIrpt ;
  113. PROCEDURE ResetIrpt ( N : CARDINAL ) ;
  114. VAR
  115. fl : CARDINAL ;
  116. BEGIN
  117. fl := SYSTEM.GetFlags() ; SYSTEM.DI ;
  118. Irpt[N] := SaveIrpt[N] ;
  119. SYSTEM.SetFlags(fl) ;
  120. END ResetIrpt ;
  121. PROCEDURE Resident;
  122. (* ======== *)
  123. VAR I,F : CARDINAL;
  124. R : SYSTEM.Registers;
  125. SaveDTA : ADDRESS ;
  126. SavePSP : CARDINAL ;
  127. SaveBrk : SHORTCARD ;
  128. BEGIN
  129. (* Set Critical Error Handler and break handlers *)
  130. SetIrpt(24H,IPROC(Int24)) ;
  131. SetIrpt(1BH,NullInt);
  132. SetIrpt(23H,NullInt);
  133. (* Change DTA *)
  134. R.AH := 2FH ;
  135. Lib.Dos(R) ;
  136. SaveDTA := [R.ES:R.BX] ;
  137. R.AH := 1AH ;
  138. R.DS := Seg(ProgDTA^) ;
  139. R.DX := Ofs(ProgDTA^) ;
  140. Lib.Dos(R) ;
  141. (* Change PSP *)
  142. R.AX := 5100H ;
  143. Lib.Dos(R) ;
  144. SavePSP := R.BX ;
  145. R.BX := ProgPSP ;
  146. R.AX := 5000H ;
  147. Lib.Dos(R) ;
  148. (* Turn off break flag *)
  149. R.AX := 3300H ;
  150. Lib.Dos(R) ;
  151. SaveBrk := R.DL ;
  152. R.DL := 0 ;
  153. R.AX := 3301H ;
  154. Lib.Dos(R) ;
  155. R.AH := 3;
  156. R.BH := 0;
  157. Lib.Intr(R,010H);
  158. Window.Use(Window.FullScreen);
  159. Window.CursorOff;
  160. Window.SnapShot;
  161. TSRproc() ;
  162. R.AH := 0DH ;
  163. Lib.Dos(R) ;
  164. Window.Use(Window.FullScreen);
  165. Window.CursorOn;
  166. R.AH := 2;
  167. R.BH := 0;
  168. Lib.Intr(R,010H);
  169. (* Restore break flag *)
  170. R.DL := SaveBrk ;
  171. R.AX := 3301H ;
  172. Lib.Dos(R) ;
  173. (* Restore PSP *)
  174. R.BX := SavePSP ;
  175. R.AX := 5000H ;
  176. Lib.Dos(R) ;
  177. (* Restore DTA *)
  178. R.AH := 1AH ;
  179. R.DS := Seg(SaveDTA^) ;
  180. R.DX := Ofs(SaveDTA^) ;
  181. Lib.Dos(R) ;
  182. (* Restore Critical irpt and break handlers *)
  183. ResetIrpt(24H);
  184. ResetIrpt(1BH);
  185. ResetIrpt(23H);
  186. END Resident;
  187. VAR
  188. HeapSize : CARDINAL ;
  189. PROCEDURE TermProc ;
  190. VAR
  191. R : SYSTEM.Registers ;
  192. psize : CARDINAL;
  193. BEGIN
  194. psize := TSRLow.ShrinkHeap(HeapSize);
  195. R.AX := 03100H; (*Terminate and stay resident*)
  196. R.DX := psize ;
  197. Lib.Intr(R,21H); (* Use Intr, so as not to trigger the
  198. Dos re-entry run-time check *)
  199. (* No Return *)
  200. END TermProc ;
  201. PROCEDURE SKinstalled () : BOOLEAN ;
  202. TYPE
  203. AP = POINTER TO ADDRESS ;
  204. VAR
  205. id1 : POINTER TO LONGCARD ;
  206. id2 : POINTER TO CARDINAL ;
  207. BEGIN
  208. id1 := Lib.SubAddr([0:8*4 AP]^,4) ;
  209. id2 := Lib.SubAddr([0:25H*4 AP]^,2) ;
  210. RETURN (id1^=049424B53H)OR(id2^=04B53H) ;
  211. END SKinstalled ;
  212. PROCEDURE InEnv() : BOOLEAN ;
  213. TYPE Str5 = ARRAY[0..4] OF CHAR;
  214. IDP = POINTER TO Str5;
  215. AP = POINTER TO ADDRESS ;
  216. CONST EnvId = 'TSENV';
  217. VAR id1 : IDP;
  218. BEGIN
  219. id1 := Lib.SubAddr([0:4*4 AP]^,8) ;
  220. RETURN id1^=Str5(EnvId);
  221. END InEnv;
  222. PROCEDURE Install ( P : PROC ; (* Procedure to be invoked *)
  223. KBF : KBFlagSet; (* Shift state to invoke *)
  224. Scan : SHORTCARD ; (* Invoking scancode (0=All) *)
  225. heapsize : CARDINAL (* Minimum heap required *)
  226. ) ;
  227. VAR
  228. hp,nhp : Storage.HeapRecPtr ;
  229. R : SYSTEM.Registers ;
  230. stack : ARRAY[0..1023] OF BYTE ;
  231. termp : SYSTEM.PROCESS ;
  232. BEGIN
  233. IF InEnv() THEN
  234. Lib.FatalError('Failed to install TSR: should be installed outside the JPI Environment');
  235. END ;
  236. IF SKinstalled() THEN
  237. Lib.FatalError('Failed to install TSR: should be installed BEFORE SideKick ');
  238. END ;
  239. ActivateScan := Scan ;
  240. ActivateFlags := KBF ;
  241. TSRproc := P ;
  242. R.AH := 52 ;
  243. Lib.Dos(R) ;
  244. DosNest := [R.ES:R.BX] ; (* Dos nesting count *)
  245. R.AH := 2FH ;
  246. Lib.Dos(R) ;
  247. ProgDTA := [R.ES:R.BX] ; (* Current DTA *)
  248. R.AX := 5100H ;
  249. Lib.Dos(R) ;
  250. ProgPSP := R.BX ; (* Current PSP *)
  251. (* Install Interrupt handlers *)
  252. SetIrpt(09H,Int9);
  253. SetIrpt(1CH,Int1C);
  254. SetIrpt(28H,Int28);
  255. SYSTEM.NEWPROCESS( TermProc, ADR(stack), SIZE(stack) , termp );
  256. HeapSize := heapsize ;
  257. TSRmode := Sleeping ;
  258. REPEAT
  259. SYSTEM.TRANSFER(MainProcess,termp) ;
  260. Resident ;
  261. UNTIL TSRmode = Dead ;
  262. END Install ;
  263. PROCEDURE DeInstall ;
  264. TYPE
  265. BP = POINTER TO SHORTCARD ;
  266. CP = POINTER TO CARDINAL ;
  267. VAR
  268. s : CARDINAL ;
  269. R : SYSTEM.Registers ;
  270. BEGIN
  271. IF TSRmode<>Dead THEN
  272. TSRmode := Dead ;
  273. ResetIrpt(09H);
  274. ResetIrpt(1CH);
  275. ResetIrpt(28H);
  276. R.AH := 52H ;
  277. Lib.Dos(R);
  278. s := [R.ES:R.BX-2 CP]^;
  279. WHILE [s:0 BP]^ = 4DH DO
  280. IF [s:1 CP]^ = ProgPSP THEN
  281. R.AH := 49H ;
  282. R.ES := s+1 ;
  283. Lib.Dos(R) ;
  284. END ;
  285. INC(s,[s:3 CP]^+1);
  286. END ;
  287. END ;
  288. END DeInstall ;
  289. VAR
  290. Continue : PROC ;
  291. PROCEDURE Closedown ;
  292. BEGIN
  293. DeInstall ;
  294. Continue() ;
  295. END Closedown ;
  296. BEGIN
  297. TSRmode := Dead ;
  298. Lib.Terminate(Closedown,Continue) ;
  299. END TSR.
  300. (*======================================================*)
  301.