1
Ça fait un petit moment que je fais des tests de programmes TI z80 en C et finalement le résultat n'est pas forcément si moche. Ce n'est pas aussi rapide ou petit que de l'assembleur pur mais c'est tout à fait acceptable avec quelques routines ASM... En gros le résultat est comparable selon moi à ce qu'on fait avec l'Axe Parser &co.

Du coup je me suis dit qu'il serait intéressant de faire une librairie contenant des routines assez pratiques pour rendre la programmation en C sur TI z80 accessible et attrayante pour tous (un peu comme la Monochrome-Lib sur casio).

Voici les routines que j'ai déjà adapté ou codé :
- TL_random(max) : renvoi un nombre compris entre 0 et la valeur maximale spécifiée (pour l'instant 255)
- TL_cpu_full_speed() : fout le processeur à fond (15 MHz) sur les calto qui le permettent (non testé)
- TL_cpu_normal_speed() : idem met à 6MHz pour toutes les calc (non testé)
- TL_get_contrast() : renvoi la valeur du contraste de l'écran (non testé)
- TL_set_contrast(value) : change la valeur du contraste de l'écran (non testé)
- TL_delay(delay) : crée une pause en ms (bug : la pause est trop longue)
- TL_small_sprite(x, y, height, *sprite, logic) : affiche un sprite de 8 pixel de large et à hauteur variable ORé/XORé/ANDé dans le gbuf (marche niquel)
- TL_large_sprite(x, y, width, height, *sprite, logic) : idem mais les deux dimensions du sprite sont spécifiables (marche nickel)
- TL_large_clipped_sprite(x, y, width, height, *sprite, logic) : ne marche pas et le dernier paramètre n'est pas encore pris en compte :/
- TL_gbuf_to_lcd() : copie le gbuf à l'écran
- TL_direct_input(keygroup) : renvoi un octet dont les bits représentent l'état des touches du groupe spécifié (utilise les DKEY de mon TI83p.h)
- TL_get_key() : équivalent du TI-Basic mais non bloquant (utilise les SKEY de mon TI83p.h)
- TL_is_key_up(key) : renvoie 1 si la touche testée est relevée sinon 0
- TL_is_key_down(key) : inverse
- TL_get_pixel(x, y) : renvoie la valeur du pixel testé dans le gbuf
- TL_set_pixel(x, y, color) : change la valeur d'un pixel dans le gbuf (allumé/éteint/inversé)
- TL_draw_rectangle_filled(x, y, width, height, color) : affiche un rectangle plein noir/blanc/inversé dans le gbuf (merci chickendude wink)
- TL_draw_line(start_x, start_y, end_x, end_y, color) : affiche une ligne noire/blanche/inversée dans le gbuf
- TL_dialog(x, y, *dialog, is_typed, typing_speed) : affiche un texte caractère par caractère à l'écran à une certaine vitesse avec la prise en compte de plusieurs tokens (changer les coordonnées, faire une pause avec 2nd etc...) (remerci !)
- TL_put_val(x, y, val) : affiche une valeur 16-bits dans le gbuf

Routines qu'il reste à faire :
- TL_small_clipped_sprite(x, y, height, *sprite, logic)
- battery check
- scaled sprite
- flipped sprite
- rotated sprite
- screen invert
- option invert pour les dialog (res/set textinverse,(iy+textflags))
- RLE decode(/encode ?)
- installation d'interruptions (createthread() ?)

Si vous avez d'autres routines intéressantes ou que vous avez du code plus optimisé, faites moi signe smile

Ah et aussi, j'ai adapté GBA Lib 2 pour pouvoir l'utiliser en C. Il faudra simplement que je présente ses routines (l'auteur, Martin Bousquet, avait fait un tuto qu'il faudra que j'adapte un peu).

J'aurai besoin de personnes prêtes à m'aider à déboguer/compléter la lib.

Pour l'instant le plus simple pour pouvoir l'utiliser c'est de se servir de z88dk, car il permet de facilement générer des programmes TI z80 (bien que wabbitemu refuse de les manger ensuite à cause d'un mauvais header, mais ça c'est peut être à cause de bin2var, il faudra vérifier :/), et surtout parce que certaines notations du code sont spécifiques à son compilateur z80 (z80ASM, bien que j'aurai aimé pouvoir utiliser spasm2, qui lui reconnait au moins le caractère '$' pour le SMC et les macro !! D'ailleurs je suis en train de tenter d'adapter le code asm généré par z88dk avec l'option -a au lieu de -o pour spasm grâce à un programme PureBasic, mais ça ne fonctionne pas encore).

Pour compiler ensuite, le mieux c'est de créer un sous-dossier dans le dossier de z88dk, qu'on nommera par exemple 'dev', d'y coller bin2var et un fichier .bat dans lequel on aura mis (pour compiler sous windows un fichier appelé 'test.c') :
@echo off
cd .. call z88dkenv.bat
cd bin
zcc +ti8x -lm -o ..\dev\test.bin ..\dev\test.c
cd ..\dev
bin2var test.bin test.8xp
del test.bin >nulpause

(Sous linux aucune idée, mais si quelqu'un veut bien poster la marche à suivre ce serait sympa smile).

Les fichiers :

dev.zip

Donc en gros dans l'immédiat, outre les nouvelles routines à coder, il me faudrait de l'aide pour réparer certaines routines. Par exemple, j'ai essayé de coder une routine qui fait une pause d'1ms à 6MHz, mais j'ai l'impression que la pause est plus longue que prévue (c'est ce que teste le programme test.c dans l'archive) :
TL_delay()
#if defined TL_DELAY char __FASTCALL__ TL_delay(unsigned int delay){ #asm ; delay = ~1 ms (without interrupts !) ; 1 cycle = 240 ns at 6 MHz TL_delay: ld b,231 ; 2 cycles (480 ns) TL_delay_loop: rlc (ix+0) ; 7 cycles (1680 ns) rrc (ix+0) ; 7 cycles (1680 ns) djnz TL_delay_loop ; 4 cycles (960 ns) if nz, else 3 cycles (720 ns) dec hl ; 2 cycles (480 ns) ld a,h ; 1 cycle (240 ns) or a ; 1 cycle (240 ns) jr nz,TL_delay ; 3 cycles (720 ns) if nz, else 2 cycles (480 ns) ld a,l ; 1 cycle (240 ns) or a ; 1 cycle (240 ns) jr nz,TL_delay ; 3 cycles (720 ns) if nz, else 2 cycles (480 ns) #endasm } #endif

J'ai peut être mal compris la durée d'exécution des instructions mais pourtant c'est ce que semble indiquer cet article : http://www.ganssle.com/articles/abuscyc.htm

Et sinon il y a aussi la routine TL_large_clipped_sprite() qui ne marche pas encore (j'ai essayé d'adapter celle là), pourtant j'ai passé des heures à tenter de la déboguer :/
2
rlc (ix) prend 23 t-states, pas 7. Les instructions shift en général sont assez lentes comparés avec les autres qui marchent avec les registres 8-bit. J'ai pas beaucoup de temps maintenant, mais j'en aurais plus en Octobre. Je ne sais pas de C, mais je pourrai peut-être t'aider avec quelques routines en asm smile

Pourrait-on aussi ajouter une option pour choisir des routines plus petites ? Je ne sais pas si ça vaut la peine, mais j'ai vu le code de "ClipBigSprite" et il semble qu'il a été écrit pour être vite mais il est assez grand.

EDIT : Et si tu veux poster le code de TL_large_clipped_sprite je peux y jeter un coup d'oeuil.
3
chickendude (./2) :
rlc (ix) prend 23 t-states, pas 7. Les instructions shift en général sont assez lentes comparés avec les autres qui marchent avec les registres 8-bit.

Ah d'accord, pourtant si je comprend bien ce n'est pas ce qui est dit ici : http://quasar.cpcscene.com/doku.php?id=iassem:timings :/

Et justement, pour ce genre de fonction il faut des instructions lentes et petites smile

Il faudrait que je trouve une liste complète (et surtout vraie) des instructions z80 avec leur nombre de cycles.
chickendude (./2) :
J'ai pas beaucoup de temps maintenant, mais j'en aurais plus en Octobre.

Ok ok, moi je n'ai pas beaucoup de temps non plus, c'est pourquoi je n'avance pas énormément sur mes gros projets et plus sur les plus petits (comme celui-là) smile
chickendude (./2) :
Je ne sais pas de C, mais je pourrai peut-être t'aider avec quelques routines en asm

Enfaite il n'y a quasiment rien en C dans cette lib, toutes les routines sont en asm.
chickendude (./2) :
Pourrait-on aussi ajouter une option pour choisir des routines plus petites ? Je ne sais pas si ça vaut la peine, mais j'ai vu le code de "ClipBigSprite" et il semble qu'il a été écrit pour être vite mais il est assez grand.

Je veux bien (il suffit d'ajouter une constante que l'utilisateur (de)commentera pour choisir entre la taille et la vitesse, comme je le fait déjà pour spécifier les routines qu'on souhaite inclure à notre projet), mais il faudra trouver/créer ces routines.
chickendude (./2) :
EDIT : Et si tu veux poster le code de TL_large_clipped_sprite je peux y jeter un coup d'oeuil.

Ok, par contre le code est très moche (notamment parce qu'on ne peut pas utiliser '$' pour le smc... :/) :
TL_large_clipped_sprite()
#if defined TL_LARGE_CLIPPED_SPRITE char TL_large_clipped_sprite(unsigned char x, unsigned char y, unsigned char width, unsigned char height, unsigned char *sprite, unsigned char logic){ #asm ; Clipped sprite routine by James Montelongo ld hl,2 add hl,sp inc hl inc hl ld e,(hl) inc hl ld d,(hl) push de pop ix inc hl ld b,(hl) inc hl inc hl ld c,(hl) inc hl inc hl ld e,(hl) inc hl inc hl ld d,(hl) ; max size : 64x64 ; ix = sprite ; b = height ; c = width in bytes ; d = x ; e = y TL_large_clipped_sprite: ld a,e cp SCREEN_HEIGHT ret p add a,b ret m ret z ld a,d cp SCREEN_WIDTH ret p ld a,c add a,a add a,a add a,a add a,d ret m ret z ld a,e or a jp p,TL_lcs_clip_bottom neg push de ld hl,0 ld d,l ld e,a bit 2,c jr z,TL_lcs_skip_1 add hl,de TL_lcs_skip_1: add hl,hl bit 1,c jr z,TL_lcs_skip_2 add hl,de TL_lcs_skip_2: add hl,hl bit 0,c jr z,TL_lcs_skip_3 add hl,de TL_lcs_skip_3: pop de ex de,hl add ix,de ex de,hl ld e,0 neg add a,b ld b,a TL_lcs_clip_bottom: ld a,e add a,b sub SCREEN_HEIGHT jp m,TL_lcs_clip_left neg add a,b ld b,a TL_lcs_clip_left: xor a ld (TL_lcs_big_skip),a ld a,TL_lcs_left_clip-(TL_lcs_do_left_clip+1) ld (TL_lcs_do_left_clip),a ld a,d or a jp p,TL_lcs_clip_right cpl and 0xf8 rra rra rra ex de,hl ld e,a ld d,0 add ix,de ld (TL_lcs_big_skip),a ex de,hl inc a neg add a,c ld c,a xor a ld (TL_lcs_do_left_clip),a ld a,d and 0x07 ld d,a TL_lcs_clip_right: ld a,TL_lcs_right_clip-(TL_lcs_do_right_clip+1) ld (TL_lcs_do_right_clip),a ld a,c add a,a add a,a add a,a add a,d sub SCREEN_WIDTH jp m,TL_lcs_middle_clip and 0xf8 rra rra rra ld l,a ld a,(TL_lcs_big_skip) add a,l inc a ld (TL_lcs_big_skip),a neg add a,c ld c,a xor a ld (TL_lcs_do_right_clip),a TL_lcs_clip_middle: xor a ld (TL_lcs_do_middle_clip),a ld a,c or a jp nz,TL_lcs_dont_skip_middle ld a,TL_lcs_middle_clip-(TL_lcs_do_middle_clip+1) ld (TL_lcs_do_middle_clip),a TL_lcs_dont_skip_middle: ld l,e ld a,d ld h,0 ld d,h add hl,hl add hl,de add hl,hl add hl,hl ld e,a and 0x07 xor 7 ld (TL_lcs_rotation_1),a ld (TL_lcs_rotation_2),a ld (TL_lcs_rotation_3),a add a,a ld (TL_lcs_clip_rotation1),a ld a,0xff defb 0x18 ; jr TL_lcs_clip_rotation1: defb 0xfe srl a srl a srl a srl a srl a srl a srl a srl e srl e srl e add hl,de ld de,gbuf add hl,de ld d,a cpl ld e,a TL_lcs_row: push bc push hl ld b,c defb 0x18 ; jr TL_lcs_do_left_clip: defb 0x11 ld a,(ix) inc ix defb 0x18 ; jr TL_lcs_rotation_1: defb 0xfe rrca rrca rrca rrca rrca rrca rrca TL_lcs_big_mask_0: and e or (hl) ld (hl),a TL_lcs_left_clip: defb 0x18 ; jr TL_lcs_do_middle_clip: defb 0 TL_lcs_loop: ld a,(ix) inc ix defb 0x18 ; jr TL_lcs_rotation_2: defb 0xfe rrca rrca rrca rrca rrca rrca rrca ld c,a TL_lcs_mask_1: and d or (hl) ld (hl),a inc hl ld a,c TL_lcs_mask_2: and e or (hl) ld (hl),a djnz TL_lcs_loop TL_lcs_middle_clip: defb 0x18 ; jr TL_lcs_do_right_clip: defb 0x0f ld a,(ix) defb 0x18 ; jr TL_lcs_rotation_3: defb 0xfe rrca rrca rrca rrca rrca rrca rrca TL_lcs_mask_3: and d or (hl) ld (hl),a TL_lcs_right_clip: pop hl ld bc,SCREEN_WIDTH/8 add hl,bc defb 0x01 ; ld bc,word TL_lcs_big_skip: defw 0 add ix,bc pop bc djnz TL_lcs_row #endasm } #endif

À mon avis c'est une erreur toute bête mais je n'arrive pas à la trouver sad
4
Je crois que cette liste te donne les M-cycles (http://en.wikipedia.org/wiki/Zilog_Z80#Instruction_execution ) en lieu des t-states. Chaque M-cycle peut prendre 3-6 t-states. Et oui, utiliser ix/iy prend pas mal de temps, mais ils prennent beaucoup d'espace aussi. Un octet pour le préfixe ($DD pour ix, $FD pour iy) et un autre pour l'offset. Un push/pop occupera 21 cycles et ne prendra que 2 octets.

Plus tard je verrai le code pour voir où se trouve le problème smile

EDIT : Et personnellement j'utilise la table de Asm in 28 days :
http://t.eeems.ca/ASMin28Days/ref/z80is.html
5
Génial je vais pouvoir modifier tout ça comme il faut, merci tongue

D'ailleurs il faudra que je trouve un moyen de tester si le processeur est mis à 15MHz, et si c'est le cas de le passer à 6MHz le temps de la pause. Ça risque d'augmenter légèrement le temps d'attente (mais bon ce sera imperceptible, de l'ordre de quelques ns).

Je me demande bien comment ce genre de fonction est codé en général cheeky
6
Je l'ai trouvé :
TL_lcs_clip_right:
	ld a,TL_lcs_right_clip-(TL_lcs_do_right_clip+1)
	ld (TL_lcs_do_right_clip),a	;jump to TL_lcs_do_right_clip
	ld a,c				;width in bytes of sprite
	add a,a
	add a,a
	add a,a				;x8
	add a,d				;+X position
	sub SCREEN_WIDTH
	jp m,TL_lcs_middle_clip	;no clipping if right edge of sprite 
La dernière ligne devrait être TL_lcs_clip_middle wink
7
Arg j'étais sûr que c'était ce genre d'erreur (avec ma manie de vouloir nommer les labels de manière explicite ça m'arrive souvent ! fou).

Merci beaucoup je vais pouvoir passer aux autres routines (même si je n'ai pas encore eu le temps de modifier TL_delay()) top

edit : bon je n'arrive pas à calculer correctement le temps d'exécution des instructions... :/

Selon moi cette routine devrait prendre 341171.5 ns pour s'exécuter si hl=0 (290.5+255(788.5+539.5)+332+249+166*4+290.5*2+415; soit ~0.3 ms), mais j'ai l'impression que c'est bien plus long (beaucoup plus qu'1 ms) :
char __FASTCALL__ TL_delay(unsigned int delay){ #asm ; delay = ~0.3 ms (without interrupts !) ; 1 z80 T-state at 6 MHz = 41.5 ns ; 1 z80 cycle (= 4 T-states) at 6 MHz = 166 ns TL_delay: ld b,255 ; 7 T-states (290.5 ns) TL_delay_loop: sub a,(ix+0) ; 19 T-states (788.5 ns) djnz TL_delay_loop ; 13 T-states (539.5 ns) if nz, else 8 T-states (332 ns) dec hl ; 6 T-states (249 ns) ld a,h ; 4 T-states (166 ns) or a ; 4 T-states (166 ns) jr nz,TL_delay ; 12 T-states (498 ns) if nz, else 7 T-states (290.5 ns) ld a,l ; 4 T-states (166 ns) or a ; 4 T-states (166 ns) jr nz,TL_delay ; 12 T-states (498 ns) if nz, else 7 T-states (290.5 ns) ; ret ; 10 T-states (415 ns) #endasm }
C'est peut être dû au fait qu'un cycle ne prend peut être pas 166 ns à 6MHz (pourtant à 10 MHz ça en prend 100, et ça j'en suis sûr) fou

edit 2 : voilà un petit aperçu de la routine de sprite clippée :

6fCH

C'est assez rapide et ça pourrait l'être encore plus, parce que là je redessine l'écran sans cesse tongue
test.c
#pragma string name test #include "..\devtest\ti83p.h" #include "..\devtest\tilib.c" extern char sprite[]; #asm ._sprite sprite: defb 0xdb,0x24 defb 0xc2,0x3d defb 0x82,0x65 defb 0x01,0xda defb 0x01,0xbe defb 0x01,0xda defb 0x9b,0x64 defb 0xdb,0x24 #endasm char main(){ unsigned char i = 1; unsigned char x = 0, y = 0; while(TL_direct_input(DKEY_GROUP_2) != DKEY_CLEAR){ C_bcall(_cleargbuf); TL_draw_rectangle_filled(3, 3, 20, 18, TL_BLACK); TL_draw_line(4, 4, 13, 15, TL_XOR); TL_large_clipped_sprite(x, y, 2, 8, sprite, TL_XOR); TL_gbuf_to_lcd(); switch(TL_direct_input(DKEY_GROUP_1)){ case DKEY_UP: y-=1; break; case DKEY_DOWN: y+=1; break; case DKEY_LEFT: x-=1; break; case DKEY_RIGHT: x+=1; break; } } }


Maintenant il ne me reste plus qu'à y ajouter la possibilité de XOR/AND le sprite.
8
Je crois qu'il y a une petite change selon le niveau des batteries, mais où as-tu trouvé les timings en ns ? D'ailleurs, tu ne sais pas la valeur d'hl. Je suis sûr que la plupart des fois tu vas répéter la boucle pas mal de temps. Je crois que environ trois répétitions suffirait.

Et je ne vois pas d'image..
9
Oui mais justement hl doit contenir le nombre de fois qu'on veut faire une pause d'1 ms (enfin là ça en fait 0.3, le temps de régler la pause correctement).

Pour les timings, je sais qu'à 6 MHz 1 cycle sur z80 (4 T-states) prend 166 ns, donc je suppose qu'1 T-state en prend 41.5, non ? Autrement je ne vois pas trop comment estimer le temps d'exécution des instructions :/

Pour l'image, c'est parce que mirari a eut quelques problèmes, du coup les fichiers uploadés il y a moins d'une semaine sont perdus... Je vais la refaire.
Je ne sais pas, mais un cycle peut prendre de 3 à 6 t-states. Lire l'opcode prend 4 t-states, donc toutes les instructions prennent au moins 4 t-states (parce qu'il faut au moins lire l'opcode).

EDIT : J'ai trouvé cette information :
http://www.ticalc.org/archives/oldmail/calc-ti/1997_August/msg00104.html
The NOP ("no operation") instruction in the Z80 takes up approximately
664 nanoseconds on a 6 MHz clock, but this is somewhat innaccurate
since the TI-85 clock is not crystal/resonator based (i.e. that timecan vary widely depending on temperature and battery drain).

nop = 4 t-states, donc 664/4 = 166 ns chaque t-state. Je crois que ce n'était pas un M-cycle mais un clock cycle, c'est-à-dire (je crois) un t-state.
Mmh ok il va falloir que je reprenne tous les calculs, je ferais ça quand j'aurais 5min. Merci ! smile
Génial ça marche !!! grin
#if defined TL_DELAY char __FASTCALL__ TL_delay(unsigned int delay){ #asm ; delay = ~1 ms (without interrupts and depending of the temperature/battery state !) ; 1 z80 cycle (= 4 T-states) at 6 MHz = ~664 ns ; 1 z80 T-state at 6 MHz = ~166 ns TL_delay: ld b,186 ; 7 T-states (1162 ns) TL_delay_loop: sub a,(ix+0) ; 19 T-states (3154 ns) djnz TL_delay_loop ; 13 T-states (2158 ns) if nz, else 8 T-states (1328 ns) dec hl ; 6 T-states (996 ns) ld a,h ; 4 T-states (664 ns) or a ; 4 T-states (664 ns) jr nz,TL_delay ; 12 T-states (1992 ns) if nz, else 7 T-states (1162 ns) ld a,l ; 4 T-states (664 ns) or a ; 4 T-states (664 ns) jr nz,TL_delay ; 12 T-states (1992 ns) if nz, else 7 T-states (1162 ns) ; ret ; 10 T-states (1660 ns) #endasm } #endif

Si le paramètre delay=0 ou 1 (=hl), la routine prend environs 1162+186(3154+2158)+1328+996+4*64+2*1162+1660=995758 ns soit 0.9 ms et environs 1 ms autrement.

Petit screen pour prouver que ça marche (j'ai comparé avec un chronomètre) :

s50z

Le code :
#pragma string name test #include "..\devtest\ti83p.h" #include "..\devtest\tilib.c" char main(){ unsigned char i; for(i=0; i<10; i++){ C_bcall(_cleargbuf); TL_put_val(0, 0, i); TL_gbuf_to_lcd(); TL_delay(1000); } }

Je vais pouvoir commencer à porter quelques petits jeux avec toutes ces routines smile

D'ailleurs je trouve que certaines ont des noms assez peu explicites, non ? Peut-être vaudrait-il mieux appeler les sprites bitmaps ? Et je n'arrive pas à trouver un meilleur nom à la routine "TL_put_val".

(Purée mon screenshot de la sprite clippée a encore été supprimé sick Je le referais plus tard).
Peut-être, mais je préfère "sprites" personnellement smile Et pour "put_val" pourquoi ne pas "print_val" ? On peut y passer un numéro ou une variable, non ?

Et j'ai vu l'autre screenshot avant qu'il avait été supprimé.
Ou alors TL_print_value() et vu qu'il faudra aussi créer une routine de texte "normale" je pourrais l'appeler TL_print_text(). Et oui on peut y passer une constante ou une variable (de n'importe quel type).
Yeah super deeph !

J'ai posté un trcu à propos de ta lib : http://ti-84-plus.com/blog/deeph-release-an-alpha-version-of-ti-lib/

Bravo en tout cas tu commence à prouver que l'on peut faire de belles choses en C sur TI (bon c'est vrai au final c'est quasiment que de l'asm mais bon tongue)
Génial, merci ! grin

Enfaite il y a toujours du mouvement sur ton site, j'avais pas fait gaffe ! sorry

À mon avis il vaudrait mieux fusionner le blog avec les news du site, parce que là on passe un peu à côté.

Il me semble que tu avais un peu travaillé avec les programmeurs de z88dk, non ? Parce qu'on dirait, sauf erreur de ma part, que les programmes 83+ sont mal générés (les deux octets de l'header qui spécifient pour quelle calc c'est sont mal choisis, ça donne ceux de la 83, du coup ça bug sur wabbitemu mais pas sur vti/tilem). Et puis ce serait sympa d'ajouter quelques fonctions à leur compilo assembleur ('$' pour le SMC, macro asm etc... Mais si vraiment c'est pas possible je vais essayer d'adapter le fichier source généré pour spasm).

Autrement j'ai commencé à porter des add-in casio (qui sont tous en C et rarement en C++ apparemment), mais il me manque encore quelques routines, notamment celle qui s'appelle RTC_getticks() qui n'est autre qu'un timer à partir de minuit qui s'incrémente 128 fois par seconde. Or seules les 84+SE ont une horloge donc j'ai pensé utiliser les interruptions (qui s'exécutent environs 200 fois par secondes). J'ai pas testé mais ça donnerai quelque chose comme ça :
#if defined TL_TIMER #asm interruption_start: di exx defb 21 ; ld hl, timer: defw 0 inc (hl) exx ei ret interruption_end: #endasm #define interrupt_jump_table 0x9900 #define interrupt_offset 0x9a9a void TL_start_timer(void){ #asm start_timer: di ld hl,interrupt_jump_table ld (hl),$9a ld bc,256 ld a,h ld d,h ld e,b ldir ld hl,interruption_start ld de,interrupt_offset ld bc,interruption_end-interruption_start ldir ld i,a im 2 ei #endasm } #define reset_timer(); asm("xor a\nld (timer),a"); void TL_get_ticks(void){ #asm ld hl,(timer) #endasm } #endif

Le seul souci avec cette méthode c'est que le timer se reset toutes les 5.46 mn (65536/200=327.68 s) et qu'on ne pourra pas se servir des interruptions pour autre chose (installer un thread...). Enfin en pratique étant donné qu'on s'en sert pour calculer des fps je ne pense pas que ça pose autant problème que ça (sauf si dans un calcul le premier tick donne 65536 et le deuxième 0 sorry).

Vous en pensez quoi ?

(Tiens d'ailleurs je viens de penser qu'il faudra faire des routines de link, sans doute avec Bell).

Bref y'a encore du boulot cheeky
Est-ce que ce code marche ? D'abords tu charges 0 dans hl, puis tu fais un "inc (hl)". La valeur que tu change c'est la valeur à $0000, dans ROM, ce qui veut dire que tu ne change rien. Si tu changes TL_get_ticks à: defb 21 ; ld hl, timer: defw 0et le code dans interruption start à ld hl,timer inc (hl)Je crois que ça marchera...
Oups effectivement, mais je n'ai toujours pas eu le temps de tester :/

Merci !