Aanroepen van TSR's door middel van MemMan 2
============================================

TSR programma's worden door MemMan 2 in aparte geheugen segmenten 
geplaatst. Het aanroepen van de TSR's gebeurt dan ook altijd via 
MemMan. De aanroepen naar TSR's kunnen in twee categorien worden 
onderverdeeld: Aanroepen vanaf hooks en aanroepen door 
toepassingsprogramma's.

In de hook-tabel van de TSR-file wordt opgegeven naar welke 
routines in de TSR de hooks moeten worden afgebogen. Op het 
moment dat n van de afgebogen hooks wordt aangeroepen, zal 
MemMan het segment waarin de TSR zich bevindt aanschakelen. 
Vervolgens wordt de routine aangeroepen die de hook-aanroep 
verwerkt.


Verwerking van hook-aanroepen
-----------------------------

Bij het schrijven van routines die een hook-aanroep verwerken 
dient met het volgende rekening gehouden te worden.

TSR's worden altijd aangeroepen met de interrupts uit. De 
interruptstand dient bij voorkeur direct na een hook-aanroep weer 
aangeschakeld te worden, door middel van een EI instructie. Zie 
voor meer informatie hierover het hoofdstuk over interrupts.

Alleen de registers AF, HL, DE en BC worden door MemMan 
ongewijzigd aan de TSR doorgegeven.

De segment-stand van de geheugen-pagina's 0, 2 en 3 blijft 
ongewijzigd bij het aanroepen van de TSR. In pagina 1 wordt het 
segment aangeschakeld waarin de TSR zich bevindt. TSR's mogen 
door gebruik te maken van de CurSeg en Use functies tijdelijk een 
segment in pagina 2 aanschakelen.

Op het moment dat de TSR wordt aangeroepen, bevindt zich alleen 
het terugkeeradres naar de TSR-Manager zich boven op de stack die 
die actief was op het moment dat de hook werd aangeroepen.

Een TSR mag alleen worden verlaten door terug te springen naar de 
TSR-Manager. Bij het terugkeren naar de manager na een 
hook-aanroep dient in het schaduw-register A' een vlag-waarde te 
worden geplaatst. Deze functie hiervan is als volgt.

+------+-------------------------------------+
| Bit  |  Naam	     Functie		     |
+------+-------------------------------------+
|  0   |  quitHook   1=Stop hook-verwerking  |
| 1..7 |  reserved   Altijd 0		     |
+------+-------------------------------------+

- quitHook: Dit bit dient te worden gezet om aan te geven dat 
  MemMan de volgende TSR's en routines die aan de hook zijn 
  gekoppeld niet meer mag aanroepen. Hierdoor is het mogelijk om 
  vanuit de TSR direct terug te springen naar het programma dat 
  de hook heeft aangeroepen.
  Dit kan bijvoorbeeld van toepassing zijn voor een TSR die Basic 
  statements verwerkt via de CMD-hook. Indien de TSR het 
  statement niet herkent, zal het de originele data-registers 
  weer moeten herstellen en terugkeren met de quitHook vlag 
  ge-reset. MemMan zal dan ook de overige TSR's die aan de 
  CMD-hook zijn gekoppeld aanroepen.
  Wanneer de TSR het statement echter wel heeft herkend en 
  verwerkt, zal de text-pointer naar het begin van volgende 
  statement wijzen. De overige TSR's mogen dan aangeroepen worden 
  en er dient direct terug te worden gesprongen naar de 
  Basic-interpreter. Het zetten van de quitHook-vlag is hiertoe 
  voldoende.

- De overige bits zijn gereserveerd en dienen altijd 0 te zijn.


Voorbeeld 1
-----------

Stel dat een TSR-routine aan de interrupt hook H.TIMI is 
gekoppeld. Deze routine heeft tot functie bij iedere interrupt 
een teller te verhogen. Deze routine zou er volgt uit kunnen 
zien:

INTTSR: EI		;Dit is de routine die een teller
	LD HL,COUNT	; verhoogd
	INC (HL)   

	EX AF,AF'       ;Bewaar register AF
	SUB A		;Maak quitHook vlag nul
	EX AF,AF'       ;Vlag naar A', herstel AF
	RET		;Keer terug naar TSR-Manager


Voorbeeld 2
-----------

Stel dat een TSR aan de hook H.CHPU hangt. De BIOS routine CHPUT 
- die de hook H.CHPU aanroept - ziet er als volgt uit:

CHPUT:	PUSH HL 	;Bewaar data-registers
	PUSH DE
	PUSH BC
	PUSH AF
	CALL H.CHPU	;Roep de CHPUT-Hook aan
	...		;Vervolg van de routine


Wanneer de hook H.CHPU aangeroepen wordt, zal de stack die MemMan 
aan de TSR doorgeeft er als volgt uitzien:

	(SP+0) = Terugkeer adres naar de TsrManager
	(SP+2) = Terugkeer adres naar het BIOS
	(SP+4) = AF
	(SP+6) = BC
	(SP+8) = DE
	(SP+10)= HL
	(SP+12)= Terugkeer adres naar de applicatie routine
	(SP+14)= ...

Wanneer er na uitvoer van de TSR direct teruggesprongen moet 
worden naar het toepassingsprogramma dat de CHPUT routine heeft 
aangeroepen, moeten de op de stack geplaatste registers en het 
return-adres naar de BIOS van de stack verwijderd worden. Het 
terugkeer adres naar MemMan dient echter bewaard te blijven. 
Hiertoe kan de volgende routine in de TSR worden opgenomen:

CHARTSR:  EI	    ;Dit is de routine die de H.CHPU aanroep
	  ...	    ; verwerkt
	  ...
	  ...
	  POP IX    ;Haal terugkeer adres naar de TsrManager
	  POP HL    ;Weg: Terugkeer adres naar het BIOS
	  POP AF    ;Register AF herstellen
	  POP BC    ;Register BC herstellen
	  POP DE    ;Register DE herstellen
	  POP HL    ;Reguster HL herstellen

	  EX AF,AF' ;Bewaar register AF
	  LD A,1    ;Zet QuitHook vlag: Stop hook-verwerking
	  EX AF,AF' ;Vlag in A', herstel register AF

	  JP (IX)   ;Keer terug via de TsrManager


Merk op dat de index- en schaduwregisters door TSR's vrij 
gebruikt mogen worden, ze hoeven niet ongewijzigd te blijven. Bij 
het aanroepen en verlaten van TSR's geeft MemMan namelijk alleen 
de registers AF, HL, DE en BC ongewijzigd door. Dit vanwege het 
feit dat de TSR's worden aangeroepen door middel van een inter 
slot call, deze routine behoudt alleen AF, HL, DE en BC.


Verwerking van TSR-aanroepen via TsrCall
========================================

De tweede manier waarop TSR-programma's aangeroepen kunnen worden 
is door middel van de MemMan functie TsrCall (63). Door middel 
van deze functie kunnen toepassingsprogramma's de TSR bepaalde 
acties laten uitvoeren en gevens met de TSR uitwisselen.

In de header-tabel van de TSR-file moet worden vastgelegd welke 
routine de TsrCall-aanroepen verwerkt. Zie voor meer informatie 
hiervoor het hoofdstuk over de indeling van TSR bestanden. Indien 
de TSR niet door middel van TsrCall wordt aangesproken, kan de 
routine uit een simpele "RET" instructie bestaan.

Bij het schrijven van routines die door middel van de MemMan 
functie TsrCall worden aangeroepen, dient met de volgende punten 
rekening te worden gehouden.

TSR's worden altijd aangeroepen met de interrupts uit. De 
interruptstand dient bij voorkeur direct na een aanroep weer 
aangeschakeld te worden, door middel van een EI instructie. Zie 
voor meer informatie hierover het hoofdstuk over interrupts.

Alleen de registers AF, HL, DE en BC worden door MemMan 
ongewijzigd aan de TSR doorgegeven. Merk hierbij op dat register 
BC gebruikt wordt om het TsrID van de TSR in aan te geven, 
register BC kan derhalve niet als invoer-register gebruikt 
worden.

De segment-stand van de geheugen-pagina's 0, 2 en 3 blijft 
ongewijzigd bij het aanroepen van de TSR. In pagina 1 wordt het 
segment aangeschakeld waarin de TSR zich bevindt. TSR's mogen, 
wanneer ze middels TsrCall zijn aangeroepen, van alle beschikbare 
CurSeg en Use functies gebruik maken om tijdelijk andere 
segmenten in te schakelen.

Op het moment dat de TSR wordt aangeroepen is een interne stack 
van MemMan actief. Deze stack bevindt zich in pagina 3 en is 160 
bytes groot. Dit zal voor de meeste toepassingen voldoende zijn. 
Merk echter op dat deze stack ook gebruikt wordt tijdens het 
uitvoeren van MemMan functies en eventueel optredende interrupts, 
de beschikbare stackruimte is dus altijd minder dan de maximale 
160 bytes.

De TSR mag alleen worden verlaten door terug te springen naar de 
TSR-Manager. Het returnadres naar de manager bevindt zich boven 
op de stack, het uitvoeren van een "RET" instructie zal dus in de 
meeste gevallen voldoen. Er hoeven geen vlag-waardes aan de 
manager te worden terug gegeven. Alleen de registers AF, HL, DE 
en BC worden ongewijzigd doorgegeven het programma dat de TsrCall 
heeft uitgevoerd.


Functieaanroepen door TSR's
===========================

Bij voorkeur zo weinig mogelijk functieaanroepen via 
de EXTBIO hook te laten verlopen. Volgens de MSX-standaard dient 
bij een aanroep van EXTBIO de stack in pagina 3 te staan. Hoewel 
MemMan



Planning:

- Situatie bij aanroepen van een TSR vanaf de hook
  (stack, registers, interrupts, segmentstand etc.)
- Functieaanroepen door een TSR
  (Geen IniChk, Geen EXTBIO maar rechtstreeks)
- Verlaten van een TSR na een hook-aanroep
  (Vlaggen in register A', wanneer moet "quitHook" gezet worden)

- Situatie bij aanroepen van een TSR via "TsrCall"
  (segmentstand, interrupts, stack, registers etc.)
- Functieaanroepen door een TSR (zie boven)
- Verlaten van een TSR na een TsrCall-aanroep
  (welke registers worden teruggeven, interrupts etc.)

- Beschrijven van nadelen van functieaanroepen via EXTBIO,      
  voordelen van rechtstreekse aanroep via het "MemManEntry"


---------

Het eerste idee bij het ontwikkelen van de TsrManager was dat de
TSR's zou weinig mogelijk `last' zouden moeten hebben van de
TsrManager. Zo moet bijvoorbeeld de stack er bijna precies
hetzelfde uitzien als wanneer de TSR gewoon een programma zou
zijn dat direct aan de hook hangt.

Dit principe is bereikt.
 Als de TSR door de TsrManager wordt
aangeroepen, dan staat alleen het terugkeer adres naar de
TsrManager op de stack. Daaronder bevindt zich de stack zoals die
actief was tentijde van de hook-aanroep.  Daarom moeten MemMan
applicatie programma's de stack in pagina 2 of 3 hebben staan.

Als een TSR bijvoorbeeld aan de hook ChPut hook van het BIOS
hangt en de BIOS routine moet niet meer uitgevoerd worden, dan
moet het terugkeer adres van de BIOS naar het applicatie
programma worden verwijderd. Helaas heeft de ChPut routine van
het BIOS ook nog vier registers op de stack gezet, maar die zijn
natuurlijk ook te verwijderen.

   De routine in het BIOS ziet er als volgt uit:

     PUSH HL
     PUSH DE
     PUSH BC
     PUSH AF
     CALL 0FDA4h
     ..

Als de TSR aangeroepen wordt, dan ziet de stack er dus als volgt
uit:

     SP: 
         <TsrManager terugkeer adres>
         <Terugkeer adres naar het BIOS>
         <AF>
         <BC>
         <DE>
         <HL>
         <Terugkeer adres naar de applicatie routine>

Om de stack nu zo om te bouwen dat de TSR na de uitvoer van zijn
eigen routine, die het BIOS vervangt, weer direct naar de
applicatie routine terugkeert, kan de volgende routine in de TSR
worden opgenomen:

          ..
          POP IX    ;Terugkeer adres naar de TsrManager
          POP HL    ;Weg: Terugkeer adres naar het BIOS
          POP AF    ;Register AF herstellen
          POP BC    ;Register BC herstellen
          POP DE    ;Register DE herstellen
          POP HL    ;Reguster HL herstellen
          PUSH IX   ;Terugkeer naar de TsrManager herstellen
          ..

Zoals te zien is, geen probleem. Stel je eens voor dat er nog een
niet te bepalen aantal andere adressen op de stack zou staan. Of
dat er wel een te bepalen aantal op zou staan, maar dat dat bij
een nieuwe versie van MemMan weer anders zou zijn, dan zou het
echt ondoenlijk worden om dit op te lossen.

Een ander voordeel is dat de stack van het applicatie programma
niet groot hoeft te zijn voor de TSR. De TsrManager heeft intern
een eigen stack die gebruikt wordt om van de hook tot de TSR te
komen. Er wordt dus niet iets op de applicatie programma stack
gezet dat er voordat de TSR wordt aangeroepen al weer af is.
Normaal zou het terugkeer adres naar de hook op de stack staan,
nu is dat het terugkeer adres naar de TsrManger. Dit adres moet
er natuurlijk wel altijd op blijven staan. Dat gebeurt ook in het
voorbeeldje hierboven.


Wat gebeurt er intern?

Intern moet er bepaald worden van welke hook de aanroep komt. Bij
de installatie van een hook wordt er een CALL uitgevoerd naar een
routine van MemMan in pagina 3. De call instructie neemt drie
bytes in beslag. In iedere hook zijn vijf bytes beschikbaar, dus
zijn er nog twee bytes over. In die twee bytes wordt een
verwijzing naar een tabel van de TsrManager gezet. Met behulp van
die tabel wordt bepaald welke TSR's aan de hook gekoppeld zijn. 
De routines van de TsrManager zijn, om ruimte te besparen in
pagina 3, in het MemMan segment geplaatst, dat in pagina 1 wordt
opgeroepen. De registers AF, HL, DE en BC worden opgeslagen in de
schaduw registers, zodat ze gebruikt kunnen worden door de
Manager. Daarna worden de huidige segment stand bewaard en wordt
het Manager-segment aangeschakeld. Er wordt van een interslot
call gebruikt gemaakt om het juiste slot van de TsrManager aan te
schakelen. Omdat de interslot call de schaduw registers wijzigt,
worden deze voor de call eerst nog even terug gehaald uit de
schaduw en door de TsrManager - na de call - direct weer in de
schaduw geschopt. Bij terugkomst van de TsrManager - van de
interslot call - worden de registers weer meteen in de schaduw
gestopt en wordt de segment stand hersteld en wordt er
teruggeschakeld op de originele stack.

De TsrManager verwerkt verder de aanroep van de hook. Het
terugkeer adres van de hook - dat nog op de originele stack
staat - geeft aan waar de extra twee bytes van de hook zich
bevinden. De registers die van de hook afkwamen staan nu in de
gewone registers en worden als eerste weer in de schaduw
geschopt.

Pas in de TsrManager wordt de actieve stand van de mapper in
pagina 2 bepaald en opgeslagen voor de functies van MemMan.
Pagina 0 mag niet gebruikt worden door de TSR's, dus wordt ook de
actieve stand daarvan niet bepaald.

