Après avoir adapter le moniteur Wozmon du Apple I sur le STM8 j'ai poursuivie sur ma lancée et créer le nouveau projet pomme I. Je veux créer un petit ordinateur 8 bits avec la carte NUCLEO-8S207K8. Cet ordinateur aura en mémoire flash le moniteur du Apple I ainsi que le BASIC du Apple I. En plus bien que ce n'était pas nécessaire j'ai ajouter un noyau système. D'ailleurs l'écriture de celui-ci m'a posé un problème auquel j'ai trouvé la solution suivante.
Pas d'interruption
Le noyau système utilise l'instruction machine TRAP du STM8 pour affectuer les appels syscall, hors cette interruption a la priorité la plus élevée. Donc quand l'ordinateur est en train d'exécuter un syscall les interruptions pour la minuterie des millisecondes et celle sur réception d'un charactère du UART de peuvent pas être déclenchées. Hors ces interruptions sont nécessaires à l'exécution de certaines fonctions du noyau. Comment résoudre ce problème?
La solution
Voici la solution que j'ai trouvé:
TrapHandler::
ldw x,(8,sp) ; get trap return address
_strxz trap_ret
ldw x,#syscall_handler
ldw (8,sp),x
iret
.macro _syscode n, t
cp a,#n
jrne t
.endm
;---------------------------------
; must be handled outside
; of TrapHandler to enable
; interrupts
;---------------------------------
syscall_handler:
_syscode SYS_RST, 0$
_swreset
0$:
_syscode SYS_TICKS,1$
_ldxz ticks
jp syscall_exit
1$:
_syscode PUTC, 2$
ld a,xl
call uart_putc
jp syscall_exit
2$:
_syscode GETC,3$
call uart_getc
jp syscall_exit
3$:
_syscode QCHAR,4$
call qgetc
jra syscall_exit
4$:
_syscode CLS,5$
call clr_screen
jra syscall_exit
5$:
_syscode DELBK,6$
call bksp
jra syscall_exit
6$:
_syscode GETLN , 7$
call readln
jra syscall_exit
7$:
_syscode PRT_STR , 8$
call puts
jra syscall_exit
8$:
_syscode PRT_INT , 9$
call print_int
jra syscall_exit
9$:
_syscode SET_TIMER , 10$
bres sys_flags,#FSYS_TIMER
_strxz timer
jra syscall_exit
10$:
_syscode CHK_TIMOUT, 11$
clr a
btjf sys_flags,#FSYS_TIMER,syscall_exit
cpl a
jra syscall_exit
11$:
_syscode START_TONE , 12$
call tone
jra syscall_exit
12$:
_syscode GET_RND , 13$
call prng
jra syscall_exit
13$:
_syscode SEED_PRNG , 14$
call set_seed
jra syscall_exit
14$:
; bad codes ignored
syscall_exit:
jp [trap_ret]
Normalement à l'exécution de l'instruction IRET le programme devrait continuer à l'adresse qui suis l'instruction TRAP. Lorsqu'une interruption est déclenchée tous les registres du STM8 sont sauvegardés sur la pile, incluant l'adresse de retour qui est située à la position (8,sp) sur la pile. Donc le gestionnaire d'interruption logicielle va chercher cette addresse et la sauvegarde dans la variable système trap_ret. Ensuite il remplace sur la pile l'adresse original par l'adresse de la sous-routine qui gère les appels syscall et puis il quitte avec l'instruction IRET. Puisque l'adresse de retour a étée modifiée le programme continue non pas à l'endroit où il aurait du mais au début de la routine syscall_handler.
Notez que la sous-routine syscall_handler se termine par un jp [trap_ret]. trap_ret est une variable pointeur et cette instruction fait un saut à l'adresse contenue dans la variable pointeur qui se trouve être l'adresse où normalement le programme aurait du continuer à la sortie de TrapHandler. Et voilà le problème est résolu.
Aucun commentaire:
Publier un commentaire
Remarque : Seuls les membres de ce blogue sont autorisés à publier des commentaires.