!PCCache
Par Benoît Gilon
Cet article et le programme inclus sont les développements d'un programme du numéro précédent, portant le nom de PC Gate.
De façon pratique, le programme présenté dans cet article permet de contrôler l'état du cache ARM3 à partir de la ligne de commande du PC. Trois syntaxes sont admises:
C:\CACHE
- affiche l'état courant de ce dernier;
C:\CACHE OFF
- désactive le cache ARM3;
C:\CACHE ON
- active celui-ci.
Vous aurez deviné que l'intérêt ici ne réside pas dans le but mais plutôt dans la manière de l'atteindre.
Présentation
- Différemment de l'architecture du premier article, la fonctionalité est presque entièrement déportée côté PC puisqu'elle met en oeuvre l'appel direct de SWIs RISC OS à partir de l'environnemnt MS/DOS. La forme prise par la librairie d'interface est un mix entre modules écrits en assembleur 8086 et en Turbo Pascal 5.
- Seul un petit module support est nécessaire côté RISC OS afin de retourner le message d'erreur dans un "format" exploitable par le programme ayant initié le SWI.
Implémentation
Module PCSupport
Rappelons que, à l'issue d'un SWI pouvant retourner une erreur (son nom est donc préfixé par la lettre X), soit le bit V est nul en retour et le SWI s'est bien déroulé, soit le bit V est 1, et une erreur s'est produite: à ce moment là, le registre R0 pointe sur un bloc de description d'erreur:
[R0] |
Code d'erreur |
[R0], #4 |
Message d'erreur (se terminant par un caractère nul) |
Une fois récupéré l'adresse du bloc de description au sein de l'environnement PC. Aucune assistance n'est possible puisque:
- Le mécanisme de translation d'adresse ne s'effectue que dans un sens PC -> ARM;
- Il est certain que l'adresse cible se trouve en dehors de l'espace adressable de l'émulation PC.
Notre module comporte donc un seul SWI de récupération des divers champs de la structure au sein de l'espace d'adresse de l'émulation PC.
Notre SWI s'appelle "PCSGetError", son numéro est &C0000 soit le premier numéro du premier chunk réservé aux applications de l'utilisateur.
SWIBASE * (1<<18) :OR: (1<<19)
; Bit inhibant la génération d'erreurs au
; sein des SWI appelés
XBit * (1<<17)
MBITV * (1<<28)
debut DCD 0 ; startcode
DCD 0 ; initialisation code
DCD 0 ; finalisation code
DCD 0 ; service handler
DCD title-debut
DCD help-debut
DCD 0 ; help-command table
DCD SWIBASE
DCD swientry-debut ; swi handler code
DCD swidecodetable-debut
DCD 0 ;SWIname decode code pointer
swientry
CMP R11, #(EndOfJumpTable -JumpTable)/4
; Dispatch if in range
ADDLO PC, PC, R11, LSL #2
B UnknownSWIError
JumpTable
B SWIGetError
EndOfJumpTable
UnknownSWIError
ADR R0, ErrToken
ORRS PC, R14, #MBITV
title DCB "PCSupport",0
help DCB "PCSupport",9,"0.01 (16 Jan 1996)",0
ALIGN
swidecodetable
DCB "PCS",0 ; prefix name
; Get error block from inside PC code
DCB "GetError",0
ALIGN
ErrToken DCD &1B6
DCB "PCS internal error",0
ALIGN
SWIGetError
; En entrée:
; R0 contient le block d'erreur en entrée
; R1 contient l'adresse ou transmettre le
; texte de l'erreur (un buffer de 256 octets
; est supposé exister à cet emplacement)
; En sortie:
; R0: contient le code de l'erreur
; [R1] contient le texte du block d'erreur
; (standard C)
ADD R2, R0, #4
MOV R4, #0
1 LDRB R3, [R2, R4]
STRB R3, [R1, R4]
ADD R4, R4, #1
TEQ R4, #256
BEQ %F2
TEQ R3, #0
BNE %B1
2 LDR R0, [R0, #0]
MOVS PC, R14
END
Librairie d'interface
Le module d'interface est constitué de deux modules:
- Un module en assembleur chargé d'appeler directement l'A.P.I. définie par Acorn;
- Un module en Turbo Pascal constituant l'interface d'appel par des programmes client Turbo Pascal.
Fichier Acorn.ASM
.MODEL TPASCAL
.CODE
AcornSWI PROC NEAR pSWIBlock: DWORD RETURNS Res: BYTE
PUBLIC AcornSWI
MOV DX, 'sa'
MOV AX, 'fe'
LES BX, pSWIBlock
DW -1, 258
XOR AX, AX
JNC AFin
INC AX
AFin: RET
ENDP
IntelTAcorn PROC FAR pIntel: DWORD RETURNS Res: DWORD;
; Retourne une adresse ARM correspondant
; une paire segment/offset en mode Intel.
PUBLIC IntelTAcorn
LES BX, pIntel
DW -1, 257
JNC ICont
; Retourne la valeur 0 en cas d'erreur...
XOR AX, AX
MOV DX, AX
ICont:
RET
ENDP
ENDS
END
Fichier ACORN.PAS
{ Unité permettant de faire communiquer une
application MS/DOS écrite en Turbo Pascal
(à partir de la version 5) avec le monde
RISC OS:
Version 0.3 (bas niveau uniquement).
Droit de copie réservé:
© Benoit GILON 1995-96
Projet Janus
Appel de SWI a partir d'une application
Référence biblio:
PC Emulator User Guide pages 69-71 }
UNIT Acorn;
INTERFACE
TYPE
tSWIBlock = ARRAY[0..16] OF LONGINT;
{ Fonction de conversion:
Addresse Intel > Adresse ARM }
FUNCTION IntelTAcorn(IntelAddress: POINTER):
LONGINT;
PROCEDURE AcornMSWI(VAR vSWI: tSWIBlock);
IMPLEMENTATION
TYPE
tpSwiBlock = ^tSwiBlock;
VAR
{ L'alignement de tableau sur
frontière de mot (long)
n'étant pas garanti par
Turbo Pascal, nous réservons ici une place
suffisante dans lequel tiendront 17 mots
longs sur une telle frontière }
SwiBlock: ARRAY[0..34] OF INTEGER;
mPointer: tpSwiBlock;
errorText: STRING;
pErrorText: LONGINT;
PROCEDURE AdjustOffset;
VAR
mOff: WORD;
BEGIN
mOff:= Ofs(SwiBlock);
IF (mOff AND 3)<> 0 THEN Inc(mOff,2);
mPointer:= Ptr(Seg(SwiBlock), mOff);
END;
FUNCTION IntelTAcorn(IntelAddress: POINTER):
LONGINT; EXTERNAL;
FUNCTION AcornSWI(pSwi: tpSwiBlock): BYTE; EXTERNAL;
{$L ACORN.OBJ }
PROCEDURE AcornMSWI(VAR vSWI: tSWIBlock);
CONST
BitVMask : LONGINT = (1 SHL 28);
SpecialPurposeSWI : LONGINT = (1 SHL 18) OR (1 SHL 19);
{d'erreurs retournables au client }
ChainResult : ARRAY [0..5] OF STRING[32] =
('General failure',
'Invalid signature',
'Command block not in user RAM',
'Alignement error',
'SWI number is out of range',
'SWI number is protected');
{ Certaines erreurs sont signe d'une erreur
interne de l'unité et doivent donc
terminer le programme au plus tot...
D'autres sont signes d'une erreur de
paramétrage au niveau du client, il n'est
pas alors nécessaire de sortir }
ExResult : ARRAY [0..5] OF BOOLEAN =
(FALSE, TRUE, TRUE, TRUE, FALSE, FALSE);
VAR
Resultat: BYTE;
vC: CHAR;
vIChar: BYTE;
BEGIN
mpointer^ := vSWI;
Resultat:= AcornSWI(mPointer);
IF Resultat <> 0 THEN
BEGIN
Resultat:= mPointer^[0] AND $7fffffff;
WriteLn(ChainResult[Resultat]);
IF ExResult[Resultat] THEN
Halt(Resultat+1);
END
ELSE
BEGIN
{ Teste le bit V }
IF (mPointer^[16] AND BitVMask) <> 0 THEN
BEGIN
{ mpointer^[1] contient déjà le
pointeur sur le bloc descripteur }
{ mpointer^[2]: adresse où stocker
le message textuel }
mpointer^[2]:= pErrorText;
mpointer^[0]:= SpecialPurposeSWI;
Resultat:= AcornSWI(mpointer);
WriteLn(
'SWI failed, error code, r0:',
mpointer^[1]);
{ Impression du message au standard C }
vIChar:= 0;
REPEAT
vC:= errorText[vIChar];
Inc(vIchar);
IF vC <> #0 THEN Write(vC);
UNTIL vC= #0;
WriteLn;
END
ELSE
BEGIN
vSWI:= mpointer^;
END;
END;
END;
BEGIN
AdjustOffset;
pErrorText:= IntelTACorn(@errorText);
END.
Programme client CACHE
Le programme client exposé ici est un exemple simple afin d'illustrer l'emploi de la librairie d'interface.
PROGRAM Cache;
USES ACORN;
CONST
cXCacheControl : LONGINT = (1 SHL 17) OR $280;
VAR
SB: tSWIBlock;
vPstring: STRING;
PROCEDURE Usage;
BEGIN
WriteLn('Cache turns the cache on or off, or returns the cache state');
WriteLn('Syntax: Cache [on|off]');
Halt;
END;
BEGIN
SB[0]:= cXCacheControl;
CASE ParamCount OF
0: BEGIN
SB[1]:= 0;
SB[2]:= 1;
END;
1: BEGIN
vPstring:= ParamStr(1);
IF (vPstring<> 'on') AND
(vPstring<> 'off') THEN Usage;
SB[2]:= 0;
IF (vPstring= 'on') THEN SB[1]:= 1
ELSE SB[1]:= 0;
END;
ELSE Usage;
END;
AcornMSWI(SB);
IF ParamCount= 0 THEN
BEGIN
Write('Cache o');
IF SB[1] = 0 THEN WriteLn('ff')
ELSE WriteLn('n');
END;
END.
Appendice
Voici en guise de conclusion, la traduction de l'«appendice D: détails de programmation» issus du manuel de l'émulateur PC (v1.8). Un prochain article traitera de la mise en place de la sollicitation ayant pour origine un programme RISC OS (c'est le mode réciproque).
Accès à RISC OS
Les programmes DOS peuvent accéder à RISC OS en utilisant une instruction spéciale du 8086 (nouveau SVC). Celui ci est un code op. inutilisé sur un 8086 réel et que l'émulateur PC trappe et utilise pour communiquer avec RISC OS. Les programmes utilitaires GETFILE.EXE et PUTFILE.EXE utilisent ce code op. SVC pour transférer des fichiers entre les systèmes de fichiers RISC OS et MS/DOS.
Il existe aussi un périphérique PC virtuel "I/O mapped" qui permet que des évènements RISC OS soient détectés par le PC et puissent engendrer une interruption des programmes tournant dans l'environnement MS/DOS.
Le code opération SVC
Le nouveau code op. 8086 SVC a le format suivant:
FF FF nn nn
4 octets le constituent, les deux premiers formant la valeur FFFF
, les troisièmes et quatrième formant un nombre 16 bits qui indiquent à l'émulateur quels services sont requis. Par exemple, le code op. SVC pour traduire une adresse 8086 en une adresse ARM peut être assemblée avec un assembleur compatible MASM en utilisant la ligne suivante:
dw -1, 257
Seule une toute petite partie parmi les SVCs possibles est réellement utilisée. Certains SVCs qui sont utilisés ne sont pas décrits ici car ils le sont uniquement pour assurer des fonctions internes de l'émulateur. Seuls les SVCs décrits ici peuvent être utilisés au sein d'applications DOS.
- SVC 257
- Traduit une adresse 8086 en adresse ARM
- En entrée:
- En sortie:
- DX:AX Adresse ARM 32 bits
- CY = 1 si erreur
- CY = 0 si OK
- SVC 258
- Interface générique pour accéder au SWIs
- En entrée:
- DX:AX = 'safe' (DH='s', AL='e')
- ES:BX Pointeur sur bloc de paramètres
Le bloc de paramètres doit être aligné sur une frontière de mot long (adresse divisible par 4)
dword 0 |
Numéro de SWI |
dword 1 |
R0 |
dword 2 |
R1... |
dword 15 |
R14 |
dword 16 |
R15 (drapeaux uniquement, ne contient pas le PC) |
Cette structure sert à la fois pour fixer des valeurs de registres en entrée et pour recuellir des valeurs de registres en sortie.
- En sortie
Si le drapeau Carry (CY) est à zéro, le bloc paramètre est "valide": dans ce cas, si le drapeau V du registre R15 en retour est à zéro, alors le SWI s'est exécuté sans erreur et la structure recueille alors les valeurs de registres au retour du SWI, sinon (bit V = 1), le SWI a échoué (et le registre R0 pointe alors vers le bloc descripteur d'erreur).
Si le drapeau CY est à 1, le bloc de paramètres est malformé, Le bit de poids fort (#31) du numéro de SWI (dword 0) est mis à 1, et le reste du champ contient un code d'erreur:
0 |
Erreur générale |
1 |
Signature invalide |
2 |
Bloc de commande n'est pas en RAM utilisateur |
3 |
Mauvais alignement |
4 |
# SWI en dehors du domaine de validité |
5 |
# SWI protégé |
Le périphérique RISC OS
Ce périphérique occupe les ports 0x700
et 0x701
. Il permet à des évènements d'être vus par l'émulateur PC. Un évènement RISC OS #13 va générer une interruption PC IRQ3 (correspondant à l'interruption 0BH). 4 interruptions peuvent être bufferisés dans ce périphérique avant la prise en compte de la première. Le périphérique RISC OS PC permet au 8086 d'examiner les registres ARM tels qu'ils étaient à l'instant où l'évènement ARM a été généré.
Port 700H |
Lecture |
bit 0 |
Interruption en attente |
bit 1 |
Dépassement de capacité |
Ecriture |
bit 0-1 |
Sélection de l'octet à l'intérieur du registre (00: octet le moins significatif) |
bit 2-5 |
# du registre (0 à 15) (seuls les registres R1 et R2 sont lisibles) |
bit 6 |
Doit etre zéro (réservé) |
bit 7 |
Réinitialise le statut d'interruption, réautorise la prise en compte des évènements consécutifs |
Port 701H (lecture seule) |
Fournit la valeur de l'octet spécifé par écriture préalable sur le port 700H |