![]() |
Bienvenue ! - Articles : Article -
|
News | Archives | FAQ | Communauté | Projets |
News Non Officielles | Le site | TiWiki | Liens |
Bienvenue sur Ti-Fr v3!
News
Officieuses
BTS en bâtiment...
Message personnel... Romain Liévin quitte la communauté TI - la suite TIGCC v0.95 moins pratique que GTC v0.90 ? sortie de ppglib Et 100000, ça fait un joli nombre, non ? Problème d'accès MERCI !
Anciennes news
Heartbleed
Avec un peu de retard InfinitEye, un projet de casque de réalité virtuelle De retour... Questions posées en messages privés. Bonne année ! Messages... Du nouveau sur Punix
Plus...
Articles
Programmation Tutorial : Programmation C [OLD] (205831) Tutorial : Programmation C [NEW] (120378) Tutorial sur Vertel3 (62223) Hardware
Dernières archives
Assembleur & C
Basic
nSpire & nSpire CAS
Production Clickpad Nspire infor (15/09/2012)
imgmanip pour Nspire (3/04/2012) imgdump Clickpad - Touchpad - CX (4/03/2012)
Meilleurs DL
La plus consultée
Plus...
Infos
|
Article TI [Programmation] Articles sur la programmation des TI68k Programmation avec UTSRLibProgrammation assembleur : TSR en mode kernel avec la bibliothèque UTSRLib'Flanker, membre de notre staff, vient de sortir ce tutoriel sur la programmation de TSRs, ces programmes résidents en mémoire, à l'aide la librairie UTSRLib. En cas de besoin, n'hésitez pas à lui demander conseil, c'est lui l'expert sur le sujet ! Programmation kernel de TSR en assembleur 68 000Auteur : Flanker
|
while(1){/*je vous l'avais dit que c'était une boucle
infinie !*/ EV_getc(busy, *event);/*récupère la touche appuyée, éteint la calc si ça dure trop longtemps, etc ...*/ EV_Hook(*event)/*c'est à ce niveau là que l'event hook agit */ App_Event_Handler(*event); /*envoie l'Event à l'Application flash actuelle pour qu'elle en fasse quelque chose (de bien si possible : insérer le caractère si l'Event est une touche alphabétique, par exemple)*/ } |   |
Ce sont des interruptions gérées par le processeur. Le processeur va stopper le déroulement normal du programme et passer en mode superviseur pour exécuter ces routines. Reportez-vous à n'importe quel tutorial d'assembleur pour comprendre leur principe de fonctionnement et ce que chaque interruption fait. UTSRLib ne permet pas de détourner les interruptions avec les types UTSR_AUTOINT_n et UTSR_TRAP_n ; les interruptions d'origine sont appellées après vos interruptions.
Comme je ne pouvais pas penser à tous les types de TSR possibles quand j'ai codé UTSRLib, et que de toutes façon c'eût été
un gaspillage de place, j'ai pensé à créer le type UTSR_UNKNOWN. Ce type particulier consiste juste à remplacer une adresse
par une autre, à un endroit donné de la mémoire. Cela peut revenir à détourner une interruption de façon plus radicale que
le type UTSR_AUTOINT_n, mais également détourner autre chose que des interruptions ; on peut par exemple changer la
JUMP TABLE ou le pFrame d'une application Flash :)
Les UTSR_EMPTY ne servent à rien, leur seule utilité est d'enregistrer un bloc mémoire dans la liste. Cela permet par exemple
de créer des variables sans perdre leur trace. Enfin, peut-être qu'en fait cela sert à quelque chose, mais j'en doute quand
même un peu.
J'ai programmé UTSRLib pour plusieurs raisons :
* Le format EvHk de Kevin Kofler ne me convenait plus, car il est bien trop rigide ; et même avec des programmes parfaitement sains,
des pertes de mémoire ou des plantages de la calculatrice peuvent tout de même arriver.
* Je voulais profiter de la simplicité offerte par le kernel, notamment pour utiliser des bibliothèques dans les TSR
* Eviter de recopier le code d'installation à chaque nouveau TSR.
Surtout que pour un TSR un peu complexe, il faut écrire également le code de désinstallation, ce qui est assez
fastidieux
* Définir un format de TSR qui aille au-delà des Event Hooks pour regrouper également des interruptions, et qui soit
relativement évolutif
* Permettre des liaisons entre les différents TSR (ils peuvent pour l'instant se "parler" entre eux par le biais d'events,
mais je travaille également sur un système analogue aux bibliothèques dynamiques)
* Il me fallait qu'un TSR soit averti de sa propre désinstallation pour effacer ses variables ou pour pouvoir la refuser :
si un TSR a lancé le désinstalleur, des bugs peuvent arriver si un autre TSR est supprimé.
* Un seul désinstalleur permet de désinstaller une plus grande variété de TSR.
* Reporter tous les problèmes de compatibilité sur le kernel et sur la lib. Par exemple, vous n'avez plus à vous soucier
d'inclure le code NON-LIBRE de h220xtsr dans chaque TSR ou de vérifier si hw3patch est bien installé. Pas la peine non plus de
vous embêter avec les histoires de Ghost Space. UTSRLib s'en occupe pour vous.
* Vous n'avez pas à vous occuper de repasser la main aux autres TSR ou aux interruptions d'origine.
Des TSR à l'ancienne convention EvHk peuvent très bien être installés en même temps que des TSR au format UTSR (format UTSRLib).
Seulement, avec les désinstalleurs UnHook, UnInEvHk ou celui intégré à CS, vous verrez un tsr "HK:LetMe" qu'il ne faudra pas effacer. Il s'agit du TSR superviseur correspondant à la fonction EV_HOOK (cf. plus bas).
C'est la concession que j'ai faite pour pouvoir garder une compatibilité la plus complète possible.
UTSRLib maintient une liste des TSR installés. Cette liste est stockée dans un handle, dont le numéro est stocké dans le texte main\sin. Il ne faut en aucun cas archiver ce texte !!!
Ensuite, il faudra distinguer deux types de TSR : les TSR utilisateurs (programmés par vous) et les TSR superviseurs (installés par UTSRLib).
A chaque nouveau type de TSR (UTSR_EV_HOOK, UTSR_AUTOINT_n, UTSR_TRAP_n), un tsr superviseur sera installé par UTSRLib, il aura pour rôle
d'appeller votre tsr utilisateur. Si deux TSR du même type sont installés, un seul tsr superviseur sera installé.
Prenons un petit exemple :
vous installez un EV_HOOK -> un UTSR_TSRLIB et un UTSR_EV_HOOK sont installés
puis vous installez un EV_HOOK -> un UTSR_EV_HOOK est installé
puis vous installez un EV_HOOK et un TRAP_5 -> un UTSR_TSRLIB, un UTSR_EV_HOOK et un UTSR_TRAP_5 sont installés
puis vous installez un TRAP_4 -> un UTSR_LIB et un UTSR_TRAP_4 sont installés
Un tsr superviseur correspond à une entrée dans la liste et à un bloc mémoire dans la RAM. Un tsr utilisateur correspond à au moins
une entrée dans la liste et à un seul bloc mémoire dans la RAM.
Les TSR superviseurs ont pour rôle de parcourir la liste et d'exécuter les TSR utilisateurs correspondants.
Au passage, les fonctions utilisateurs peuvent détruire les registres d0-d2 et a0-a1.
Les fonctions utilisateurs que vous programmez doivent avoir des prototypes particulièrement simples :
void my_interrupt(void) |
void my_hook(EVENT *event) |
Rien de très compliqué !
Si vous voulez installer plusieurs fonctions du même type, il faudra répéter le type à chaque fois dans la liste. Enfin, je ne pense pas que installer plusieurs fonctions du même type soit très utile...
Le programme suivant installe un tsr qui ne fait rien du tout sur l'auto-interruption 5 :)
; Assembly Source File ; Created 22/03/2005, 12:07:20 include "utsrlib_asm.h" include "tios.h" xdef _main xdef _ti89 xdef _ti92plus xdef _v200 xdef _ti89ti _main: move.w #UTSR_AUTHORIZE_DLG,-(a7);quelques flags pea functions_list(pc);liste des fonctions move.w #1,-(a7);nombre de fonctions dans le TSR ! move.l #end_address-base_address,-(a7);taille à recopier en RAM pea base_address(pc);adresse de début jsr utsrlib::utsr_install;appel à UTSRLib lea 16(a7),a7 rts functions_list: dc.w UTSR_AUTOINT_5,utsr_autoint_5-base_address ;debut du contenu du TSR base_address: name: dc.b 'sample',0,0 tsrid: dc.w 0 ;la fonction qui ne fait rien : utsr_autoint_5: rts end_address: |
Regardons le header file (utsrlib_asm.h) fourni avec UTSRLib :
short utsrlib::install(const void *base_address, longint size, short functions_number, const void* functions_list, short flags); |
base_address : beginning of the code of the TSR to install
this code must begin by the name (exactly 8 chars) followed by a blank short (which will be filled by the UtsrId)
size : total size of data to copy in RAM
functions_number : number of UTSR functions
functions_list : pointer to the functions list, which must have exactly functions_number elements
flags : flags which fix utsr_install behaviour
returns UTSR_NULL in case of error, utsrId else (utsrId is the handle in which the utsr is copied).
C'est la principale fonction à utiliser, vu que c'est elle qui installe tout :) Son utilisation est montrée dans l'exemple ci-dessus.
functions_list contient est une liste d'éléments (UTSR_UNKNOWN, offset, vector) ou (type, offset) (pour les autres fonctions). Consultez les exemples, c'est sûrement ce qu'il y a de plus simple pour comprendre.
void utsrlib::utsr_delete(short utsrId, short flags); |
utsrId : utsrId of the utsr to remove from the list
flags : flags wich fix utsr_delete behaviour
Cette fonction doit être utilisée pour désinstaller proprement un TSR. TTools l'utilise, et je pense qu'il n'y a pas besoin
d'autre désinstalleur. Mais rien ne vous empêche de vous en servir quand même.
short utsrlib::utsr_is_present(const char* utsrName); |
utsrName : pointer to an array of 8 chars, which contains the name of the searched utsr
returns UTSR_NULL in case of error (utsr not found, by example), tsrId else.
HANDLE utsrlib::utsr_get_handle(void); |
returns the handle of utsr list, or H_NULL in case of error
void utsrlib::kernel_uninstall(void); |
warns all utsrs from a kernel uninstallation
removes all utsrs from the utsr list
keep in mind that even in case of errors, all utsrs will be removed (as wanted by PpHd ;) )
Normalement, cette fonction ne devrait être utilisée que par un kernel !
UTSR_AUTHORIZE_TWINS: si ce flag n'est pas utilisé, le TSR ne peut être installé qu'en un seul exemplaire
Comme c'est rare qu'on veuille installer un TSR en plusieurs exemplaires, j'ai décidé de permettre la vérification
dans la lib.
UTSR_AUTHORIZE_SL: les messages d'avertissement (TSR installé correctement, etc..) seront affichés dans la Status Line
UTSR_AUTHORIZE_DLG: les messages seront affichés dans des boîtes de dialogue.
Si ni UTSR_AUTHORIZE_SL, ni UTSR_AUTHORIZE_DLG n'est utilisé, aucun message ne sera affiché
UTSR_ERRORS_ONLY: seules les erreurs auront droit à un message
Vous pouvez bien sûr combiner les flags avec un OU logique, si vous voulez autoriser les doublones et les messages dans des boîtes de dialogues, il faudra que marquer UTSR_AUTHORIZE_TWINS||UTSR_AUTHORIZE_DLG
Dans functions_list, il faut rajouter une ligne contenant UTSR_EV_HOOK (pour dire qu'on veut ajouter une entrée EV_HOOK dans la liste) et l'offset de la fonction.
dc.w UTSR_EV_HOOK, utsr_ev_hook-base_address |
utsr_ev_hook doit être une fonction de prototype void utsr_ev_hook(EVENT *event).
Certains EVENT spéciaux ont été définis, pour permettre d'interagir avec les TSR. Pour qu'un TSR puisse réagir à ces EVENT, il doit donc disposer d'une fonction UTSR_EV_HOOK.
Ils doivent être passés directement à l'event hook EV_hook (sans passer par la fonction EV_sendEvent).
Rappelons d'abord la structure d'un EVENT :
en C:
typedef struct EventStruct { unsigned short Type; /*ID code of the message*/ unsigned short RunningApp; /*AppId of the sender of the message*/ unsigned short Side; /*Side from which message is sent*/ unsigned short StatusFlags; /* Status line flags */ union { /*Message-dependent extra information*/ WINDOW *w; WIN_RECT *r; char *pasteText; HANDLE hPasteText; struct { unsigned short Mod; unsigned short Code; } Key; } extra; unsigned char StartType; /* Used only in the CM_STARTTASK message */ } EVENT; |   |
en assembleur:
Offset | Taille | Valeur |
0 | 2 | Type |
2 | 2 | RunningApp |
4 | 2 | Side |
6 | 2 | StatusFlags |
8 | 4 | *WINDOW |
8 | 4 | *WIN_RECT |
8 | 4 | *pasteText |
8 | 2 | hPasteText |
8 | 2 | Mod |
10 | 2 | Code |
8 | 4 | Key |
8 | 4 | extra |
12 | 1 | StartType |
Valeur | Type | Autres champs | Description |
0x7FFF | UTSR_CAN_DELETE |
RunningApp = tsrId, hPasteText = 1, Code = (* ev_can_delete) (HANDLE)can_delete_UTSR. | Permet de demander à l'ensemble des TSR si on peut effacer le TSR tsrId.
Si un TSR refuse sa désinstallation, il doit mettre hPasteText à 0, sinon il ne doit rien faire. Si un TSR A doit demander la désinstallation d'un TSR B, il peut utiliser le pointeur vers la fonction can_delete_UTSR (donné par Code), fonction qui prend comme unique argument le tsrId de B. |
0x7FFE | UTSR_DELETE | RunningApp = tsrId. | Préviens les TSR qu'on efface le TSR tsrId |
0x7FFD | UTSR_ICON | RunningApp
= tsrId, pasteText = NULL. | Demande au TSR tsrId un pointeur vers une icône 22x22. Le pointeur doit être mis dans pasteText. |
0x7FFC | UTSR_ABOUT | RunningApp
= tsrId, pasteText = NULL. | Demande au TSR tsrId un pointeur vers une chaîne de caractère.
Le pointeur doit être mis dans pasteText. On peut par exemple s'en servir pour afficher le nom de l'auteur. |
0x7FFB | UTSR_INSTALL | RunningApp = tsrId | Préviens les TSR que le TSR tsrId vient d'être installé |
0x7FFA | UTSR_FORMAT | RunningApp = tsrId | quivalent pour le TSR tsrId de la commande Menu Format... |
0x7FF9 | UTSR_HELP | RunningApp
= tsrId, pasteText = NULL. | Demande au TSR tsrId un pointeur vers une chaîne de caractère qui servirait d'aide. Le pointeur doit être mis dans pasteText. |
0x7FF8 | UTSR_RELOAD | RunningApp = tsrId | Demande au TSR tsrId de recharger son fichier de configuration (de préférence sans avertissement) |
0x7FF7 | UTSR_KERNEL_UNINSTALL | Préviens les TSR que le kernel va être désinstallé (et donc eux aussi). | |
0x7F00..0x7F0F | UTSR_CMD_00 .. UTSR_CMD_0F | RunningApp = tsrId | Utilisables pour des commandes spécifiques au TSR tsrId |
Voici un petit bout de code qui demande au TSR de tsrId d3 un pointeur sur une chaîne de caractère. Si le TSR en question n'en a pas, on aura a0 = NULL ; sinon a0 sera ce pointeur.
lea -14(a7),a7 move.w d3,2(a7);TsrID du TSR dont on veut l'About clr.l 8(a7) move.w #UTSR_ABOUT,(a7) move.l a7,a2;Il faut mettre l'adresse de l'Event dans a2 ; pour de sombres raisons de compatibilité move.l a2,-(a7) move.l 200,a0 move.l 2700(a0),a0;EV_hook move.l (a0),a0 move.l a0,d0 beq \skip jsr (a0) \skip: addq.l #4,a7 move.l 8(a7),a0;Ici on a le pointeur cherché ! lea 14(a7),a7 |
Il n'y a rien à dire de particulier à leur sujet, à part que pour les interruptions qui interviennent souvent (comme la 5), il faut bien faire attention à faire du code petit, en effet si elle arrive de nouveau avant que la précédente soit finie, la calculatrice va crasher inévitablement. Dans functions_list, il faut rajouter une ligne contenant UTSR_EV_HOOK (pour dire qu'on veut ajouter une entrée EV_HOOK dans la liste) et l'offset de la fonction.
dc.w UTSR_X, utsr_interrupt-base_address |
Il faut bien sûr remplacer UTSR_X par la fonction voulue. utsr_interrupt doit être une fonction de prototype void utsr_interrupt(void).
J'ai défini ce type de TSR pour laisser plus de liberté au programmeur. Contrairement aux 2 types précédents, UTSR_UNKOWN a besoin de plus que 2 arguments dans functions_list pour être utilisable. Voyons ce que ça donne :
dc.w UTSR_UNKNOWN, utsr_unknown-base_address dc.l VECTOR |
VECTOR doit être une adresse paire. La valeur située à cette adresse sera écrasée par l'adresse de utsr_unknown. A la désinstallation, elle sera restaurée.
Rien à dire, il n'y a aucune condition particulière sur utsr_empty.
dc.w UTSR_EMPTY, utsr_empty-base_address |
Voici un exemple qui installe un tsr à 3 entrées :
- une sur l'autoint 5 qui va faire clignoter le pixel en haut à gauche de l'écran (très utile !)
- une sur le trap 4 qui va afficher "A la prochaine !" quand on éteint la calculatrice.
- une event hook qui va afficher un joli message "NOOOONNN !!" quand on quitte une application Flash. Cette fonction va également permettre de répondre aux demandes d'icônes et de chaîne "About".
; Assembly Source File ; Created 22/03/2005, 12:07:20 include "utsrlib_asm.h" include "tios.h" xdef _main xdef _ti89 xdef _ti92plus xdef _v200 xdef _ti89ti _main: move.w #UTSR_AUTHORIZE_DLG,-(a7);quelques flags pea functions_list(pc);liste des fonctions move.w #3,-(a7);nombre de fonctions dans le TSR ! move.l #end_address-base_address,-(a7);taille à recopier en RAM pea base_address(pc);adresse de début jsr utsrlib::utsr_install;appel à UTSRLib lea 16(a7),a7 rts functions_list: dc.w UTSR_AUTOINT_5,utsr_autoint_5-base_address dc.w UTSR_TRAP_4,utsr_trap_4-base_address dc.w UTSR_EV_HOOK,utsr_ev_hook-base_address base_address: name: dc.b 'sample',0,0 tsrid: dc.w 0 utsr_autoint_5: bchg.b #0,$4C00 rts utsr_trap_4: pea bye_str(pc) move.l 200,a0 move.l 920(a0),a0 jsr (a0) addq.l #4,a7 rts utsr_ev_hook: movem.l a2-a5/d0-d7,-(a7) move.l (4+8+1)*4(a7),a4;on récupère l' EVENT * move.w tsrid(pc),d0;on récupère notre propre tsrId cmp.w 2(a4),d0; on regarde si c'est bien à nous qu'on s'adresse bne \not_me cmp.w #UTSR_ABOUT,(a4) bne \skip_about lea about_str(pc),a0 move.l a0,8(a4) \skip_about: cmp.w #UTSR_ICON,(a4) bne \skip_icon lea icon_data(pc),a0 move.l a0,8(a4) \skip_icon: \not_me: cmp.w #CM_ENDTASK,(a4) bne \skip_endtask clr.l -(a7) pea quitte_str(pc) clr.l -(a7) move.l 200,a0 move.l $1B4*4(a0),a0;DlgMessage jsr (a0) lea 12(a7),a7 \skip_endtask movem.l (a7)+,a2-a5/d0-d7 rts icon_data: dc.w 22,22 ;après il faut mettre les données de l'icône :p about_str: dc.b 'Sample TSR by Flanker',0 quitte_str: dc.b 'Noooooonnnnn!',0 bye_str: dc.b 'A la prochaine !',0 even end_address: |
Vous pouvez également consulter les sources de mes TSR, en général elles sont un peu commentées.
- Ti FR v3 - Ce site n'est pas le site officiel de texas instruments. En cas de problèmes techniques sur le site veuillez contacter l'administrateur. Merci de vos visites ! |