dimanche 18 juin 2023

projet pomme I

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.