Posté le 22/02/2013 à 11:08 Membre depuis le 15/03/2005, 3470 messages
Créer un shell pour la 84+ C SE à plusieurs ça vous dit ?

Je ne parle pas d'une usine à gaz qui regroupe 36000 routines, des icônes énormes etc... mais d'un petit shell proposant des routines simples et suffisante pour rapidement porter nos projets actuels smile

Voici quelques routines qui pourraient être intéressante (à compléter et à discuter bien entendu) :

- tirage d'un nombre aléatoire
- affichage de sprite clippées (16-bits voire moins ? Peut être même 1-bit pour la retrocompatibilité ?)
- flip/rotation de sprites
- dessin de rectangle pleins/vides, cercles, lignes
- routine qui copie un buffer de 768 octets au milieu de l'écran (ou 1 bit = 1 pixel)
- link ?

Au niveau du format, je pense qu'il vaudrait mieux partir sur une app.

Pour la mise en page il faudrait un truc simple : le nom du shell, un "toggle" (button on/off) pour l'installation, le choix de "write-backer" les programmes désarchivés et de quoi quitter l'app.

Au niveau des fonctions : autoréinstallation après un reset (peut être re-réglage de l'horloge aussi ?) etc...

J'ai commencé à écrire quelques bouts de codes, le problème c'est qu'on ne peux pas (encore) tester sur 84+ C SE, du coup ça compile pour 83+, mais de toute façons il n'y aura que la partie graphique à revoir (le système des apps/hook est très certainement le même). On peut déjà commencer à coder quelques routines (tirage aléatoire, copie de buffers...) smile

L'header est normalement correcte, l'app est bien signée (par contre la clé RSA est-elle la même ?), j'ai codé la création de l'appvar (qui stock l'état de l'installation du shell (mais on pourrait peut être le deviner en détectant le hook ?), et si on write-back), un début de lecture/écriture de ce même appvar et l'installation d'un hook qui empêche le lancement des programmes (par contre je n'ai pas encore codé sa désinstallation).
zshell.z80
	.nolist
;#include "ti84pcse.inc"
#include "ti83p.inc"	; only for debug
	.list
	.org $4000
	.db $80,$0f,$00,$00,$00,$00	; program length = 0
	.db $80,$12,$01,$04	; program type = shareware for TI 83+
	.db $80,$21,$01	; app id = 1
	.db $80,$31,$01	; app build # = 1
	.db $80,$48, "zSHELL  "    ; app name (must be 8 bytes long)
	.db $80,$81,$01	; app page = 1
	.db $80,$90	; no default splash screen
	.db $03,$26,$09,$04,$04,$06f,$1b,$80	; date stamp = 5/12/1999
	.db $02,$0d,$40	; encrypted TI date stamp signature
	.db $a1,$6b,$99,$f6,$59,$bc,$67
	.db $f5,$85,$9c,$09,$6c,$0f,$b4,$03,$9b,$c9
	.db $03,$32,$2c,$e0,$03,$20,$e3,$2c,$f4,$2d
	.db $73,$b4,$27,$c4,$a0,$72,$54,$b9,$ea,$7c
	.db $3b,$aa,$16,$f6,$77,$83,$7a,$ee,$1a,$d4
	.db $42,$4c,$6b,$8b,$13,$1f,$bb,$93,$8b,$fc
	.db $19,$1c,$3c,$ec,$4d,$e5,$75
	.db $80,$7f,$00,$00,$00,$00	; program image length = 0
	.dw $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000	; padding (header length must be 128 bytes long)

start:
	di	; disable interrupts (todo : check which bcall may resume them)
	bcall(_clrlcdfull)	; clear screen
	bcall(_indicatoroff)	; disable run indicator
	bcall(_cleargbuf)	; clear graph buffer
	res texterasebelow,(iy+textflags)	; reset some textflags
	res textinverse,(iy+textflags)	; reset some textflags
	ld hl,$0501
	ld (currow),hl
	ld hl,zshell_string
	call iputs
	ld hl,zshell_appvar
	rst rmov9toop1	; hl to op1
	bcall(_chkfindsym)
	call c,create_zshell_appvar
	ex de,hl	; cause of _getbytepaged parameters
	ld a,b
	or a
	jr z,appvar_is_in_ram
	; todo : unarchive appvar

appvar_is_in_ram:
	inc hl
	inc hl	;skip size bytes
	call get_byte
	or a
	jr z,install_zshell

uninstall_zshell:
	dec hl
	ld (hl),0
	ld hl,$0003
	ld (currow),hl
	ld hl,uninstalling_string
	call iputs
	bcall(_getkey)
	bcall(_jforcecmdnochar)

install_zshell:
	dec hl
	ld (hl),1	; set zschell installed in the appvar
	bit parserhookactive,(iy+hookflags4)	; activate parser hook
	jr nz,some_hook_already_exists
	ld hl,zschell_hook	; put hook adress into hl
	in a,(pmpagea)	; put page # into a
	bcall(_setparserhook)	; install hook
	ld hl,$0003
	ld (currow),hl
	ld hl,installing_string
	call iputs
	bcall(_getkey)

some_hook_already_exists:
	; todo : ask for destroying or chaining it
	bcall(_jforcecmdnochar)	; quit the app

get_byte:
	ld a,b
	or a
	ld a,(hl)
	push de
	call nz,get_byte_paged
	pop de
	inc hl
	ret

get_byte_paged:
	ld a,b
	bcall(_getbytepaged)
	ld a,b
	ret

create_zshell_appvar:
	ld hl,zshell_appvar
	rst rmov9toop1
	ld hl,zshell_appvar_content_length-zshell_appvar_content
	bcall(_createappvar)	; todo : check if enough ram
	inc de
	inc de	; skip first two bytes (size of the appvar)
	ld hl,zshell_appvar_content
	ld bc,zshell_appvar_content_length-zshell_appvar_content
	ldir
	ld hl,zshell_appvar
	rst rmov9toop1
	bcall(_chkfindsym)
	ret

iputs:
	ld a,(hl)
	or a
	ret z
	bcall(_putc)
	inc hl
	jr iputs

zshell_appvar:
	.db appvarobj,"zSHELL",0

zshell_appvar_content:
	.db 0	; is installed
	.db 0	; allow program writeback

zshell_appvar_content_length:

#include "hook.inc"

zshell_string:
	.db "zSHELL",0

installing_string:
	.db "zSHELL has been installed",0

uninstalling_string:
	.db "zSHELL has been uninstalled",0
	.end
hook.inc
zschell_hook:
	.db $83	; used by os for hook safety check
	ld a,(parse_var)	; check the currently executed program type
	cp progobj
	jr z,run_program
	cp protprogobj
	jr nz,exit_zschell_hook

run_program:

exit_zschell_hook:
	or $80	; reset zero flag, the parser can't continue to parse the variable
	ret

zSHELL.zip

Qu'en pensez-vous ? Il faudrait aussi discuter de l'header des programmes asm compatibles (pour ma part je pensais au moins inclure du code unsquishé au début qui afficherai un message d'erreur si le shell n'est pas installé).

La prochaine chose à coder est le hook en lui même (et gérer quelques autres cas gênant lors de l'installation : s'il y a déjà un hook d'installé, si l'appvar est dans l'archive etc...).

Quant au nom du shell, j'ai fait simple mais on peut tout à fait le changer, j'attend vos propositions ! happy
Posté le 22/02/2013 à 16:18Edité par chickendude le 22/02/2013 à 16:48 Membre depuis le 03/06/2011, 520 messages
Une chose que l'on pourrait ajouter serait l'option d'activer le writeback (et vice-versa) dans le programme même. Si tu as choisi de ne pas l'activer, alors un petit message pourrait s'afficher comme avertissement, mais il y a des fois que je ne veux pas que le jeu "writeback".

Et maintenant le clippage de sprites ne va pas être si difficile comme avant smile Une autre chose qui serait utile serait pouvoir descomprimir tes sprites 1-bit dans un buffer quelque part pour ne pas avoir à le faire chaque fois que tu veux afficher un sprite. Par exemple :
;hl = source
;de = destination
;b = taille (en octets)
unpack:
 ld c,(hl)
unpack8_boucle_out:
 push bc
 ld b,8
unpack8_boucle_in:      ;unpack un octet
 xor a
 rl b
 sbc a,0          ;s'il y avait un carry, a=$FF, sinon, a=0
 ld (de),a     ;premier octet
 inc de
 ld (de),a      ;deuxième octet (des couleurs 16-bit)
 inc de
 djnz unpack8_boucle
 inc hl
 pop bc
 ld c,(hl)
 djnz unpack8_boucle_out
 ret
Je l'ai pas testé, mais ça c'est l'idée. Comme ça tu pourras descomprimir tes sprites dans la RAM additionnelle, par exemple, pour utiliser des routines de sprite plus vites.
Posté le 22/02/2013 à 16:31 Membre depuis le 15/03/2005, 3470 messages
Le write-back dans les programme eux-mêmes c'est une bonne idée, oui smile

En détectant si le hook est installé il n'y a même plus besoin d'appvar. Par contre il faudra que je regarde comment le réinstaller à chaque reset de la calc.

La décompression des sprites des sprites dans un buffer semble être une bonne idée aussi, mais je me demande comment gérer ça côté des utilisateurs (sauf si on demande le buffer en paramètre, comme ça ils se débrouillent ensuite ?).

Pour le moment j'essaie de faire comprendre au hook la différence entre l'exécution d'un programme et une simple fonction...

Autrement il semblerai que certains programmes/fonctions ont le caractère '#' ($23) en début de nom (à basic_prog+1 ou parse_var+1, après l'octet du type), mais je ne voit pas trop pourquoi (parce qu'ils sont lancés depuis l'écran d'accueil ?).

Le wikiti m'aide un peu ( http://wikiti.brandonw.net/index.php?title=83Plus:Hooks:9BAC ), mais il y a beaucoup de zones d'ombre (et pourquoi TI n'a pas pris la peine de documenter ces fonctions dans le SDK ??? mad).
Posté le 22/02/2013 à 17:05 Membre depuis le 03/06/2011, 520 messages
Je n'ai jamais utilisé les hooks, donc je ne sais pas comment je pourrait t'aider :/

Et si le hook ne se réinstalle pas à chaque reset je crois que c'est pas trop grave, on peut simplement exécuter encore une fois l'app.

Quant aux décompression, j'ai quelques idées. La première, charger tes sprites comme ci :
sprite1:
.dw 8 ;taille du sprite en octets
.db %11111111
.db %10000001
.db %10000001
.db %10000001
.db %10000001
.db %10000001
.db %10000001
.db %11111111
Puis, quand tu décompresses le sprite tu n'as que charger l'adresse du sprite dans HL, la routine de décompression lira la taille du sprite (ici 8 octets), la mettre dans b, puis SMC l'adresse où le sprite va se décompresser (disons, $8000). Après avoir décompressé le sprite, tu peut envoyer l'adresse de sprite1 à la routine d'affichage, la routine lira l'adresse sauvée ($8000) et l'utilisera pour afficher le sprite.

Une autre idée serait de donner un id à chaque sprite selon l'ordre de décompression. Donc le premier sprite décompressé aura l'id 0, et le 100ème aura l'id 99. La routine de décompression sauvera les adresses dans une table dans saferam. Puis, pour afficher un sprite, tu envoies l'id (0-255) du sprite, pas son adresse. Il faudrait que ton code soit un peu plus organisé comme ci pour savoir (peut-être avec des equates) l'id de chaque sprite décompressé, mais tous les datas extras sont sauvés dans saferam.

Ou si tu ne demandais que comment savoir où décompresser les sprites, on peut avoir deux octets dans saferam qui contiennent l'adresse du buffer, si on veux la changer on n'a qu'y écrire la nouvelle adresse.
Posté le 22/02/2013 à 18:14 Membre depuis le 15/03/2005, 3470 messages
Oui mais c'est un peu contraignant pour l'utilisateur qu'on "empiète" sur les saferams, non ? Moi je verrai ça comme ça : l'utilisateur met dans un registre 16-bit l'adresse du buffer où la routine doit décompresser la sprite et dans un autre l'adresse du sprite (dont le premier octet est la taille du sprite), et la routine se charge du reste. Ensuite une autre routine permettrai d'afficher la sprite à partir de l'adresse d'un buffer quelconque, de sa largeur et de sa hauteur.

Comme ça ça ne limite pas les utilisateurs à 256 sprites.
chickendude (./4) :
Ou si tu ne demandais que comment savoir où décompresser les sprites, on peut avoir deux octets dans saferam qui contiennent l'adresse du buffer, si on veux la changer on n'a qu'y écrire la nouvelle adresse.

Autant demander l'adresse du buffer à chaque fois avec hl, de, bc ou af, non ?

edit : une version sans appvar :
zshell.z80
	.nolist
;#include "ti84pcse.inc"
#include "ti83p.inc"	; only for debug
	.list
	.org $4000
	.db $80,$0f,$00,$00,$00,$00	; program length = 0
	.db $80,$12,$01,$04	; program type = shareware for TI 83+
	.db $80,$21,$01	; app id = 1
	.db $80,$31,$01	; app build # = 1
	.db $80,$48, "zSHELL  "    ; app name (must be 8 bytes long)
	.db $80,$81,$01	; app page = 1
	.db $80,$90	; no default splash screen
	.db $03,$26,$09,$04,$04,$06f,$1b,$80	; date stamp = 5/12/1999
	.db $02,$0d,$40	; encrypted TI date stamp signature
	.db $a1,$6b,$99,$f6,$59,$bc,$67
	.db $f5,$85,$9c,$09,$6c,$0f,$b4,$03,$9b,$c9
	.db $03,$32,$2c,$e0,$03,$20,$e3,$2c,$f4,$2d
	.db $73,$b4,$27,$c4,$a0,$72,$54,$b9,$ea,$7c
	.db $3b,$aa,$16,$f6,$77,$83,$7a,$ee,$1a,$d4
	.db $42,$4c,$6b,$8b,$13,$1f,$bb,$93,$8b,$fc
	.db $19,$1c,$3c,$ec,$4d,$e5,$75
	.db $80,$7f,$00,$00,$00,$00	; program image length = 0
	.dw $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000	; padding (header length must be 128 bytes long)

start:
	di	; disable interrupts (todo : check which bcall may resume them)
	bcall(_clrlcdfull)	; clear screen
	bcall(_indicatoroff)	; disable run indicator
	bcall(_cleargbuf)	; clear graph buffer
	res texterasebelow,(iy+textflags)	; reset some textflags
	res textinverse,(iy+textflags)	; reset some textflags
	ld hl,$0501
	ld (currow),hl
	ld hl,zshell_string
	call iputs
	bit parserhookactive,(iy+hookflags4)
	jr z,install_zshell	; no current hook
	;in a,(pmpagea)
	;ld hl,parserhookptr+2
	;cp (hl)
	;jr nz,quit	; zshell hook already exists

uninstall_zshell:
	; todo : ask to destroy/chain current hooks or uninstall zshell hook
	bcall(_disableparserhook)
	ld hl,$0003
	ld (currow),hl
	ld hl,uninstalling_string
	call iputs
	bcall(_getkey)
	bcall(_jforcecmdnochar)

install_zshell:
	ld hl,zshell_hook	; put hook adress into hl
	in a,(pmpagea)	; put page # into a
	bcall(_setparserhook)	; install hook
	ld hl,$0003
	ld (currow),hl
	ld hl,installing_string
	call iputs
	bcall(_getkey)

quit:
	; todo : ask for destroying or chaining it
	bcall(_jforcecmdnochar)	; quit the app

iputs:
	ld a,(hl)
	or a
	ret z
	bcall(_putc)
	inc hl
	jr iputs

zshell_hook:
	.db $83	; used by os for hook safety check (add a,e can be used too)
	or a
	jr z,zshell_hook_start	; we just want to handle prgm, not TI-Basic functions

exit_zshell_hook:
	xor a
	ret

zshell_hook_start:
	;ld a,(parse_var)	; check the currently executed program type
	;cp protprogobj
	;jr nz,hook_return_nz
	;ld hl,parse_var
	;rst rmov9toop1
	;bcall(_chkfindsym)
	;ex de,hl
	;ld a,(parse_var+1)
	;cp '#'
	;jr nz,exit_zshell_hook

run_program:
	ld hl,test_str
	call iputs

hook_return_nz:
	or $80	; reset zero flag, the parser can't continue to parse the variable
	ret

test_str:
	.db "test",0

zshell_string:
	.db "zSHELL",0

installing_string:
	.db "zSHELL has been installed",0

uninstalling_string:
	.db "zSHELL has been uninstalled",0
	.end

Pour l'instant lancer l'app "toggle" l'installation du hook (qui ne fait rien d'autre à part afficher "test" lorsqu'on exécute une fonction).
Posté le 23/02/2013 à 05:34 Membre depuis le 03/06/2011, 520 messages
A propos, as-tu vu app.inc ?

Et deux octets n'est pas trop, on pourrait utiliser asm_Flags ou un autre endroit que dont on ne se sert que très rarement. Comment penses-tu intégrer les routines de zSHELL dans les programmes ? Je crois que ion charge les routines à la fin du programme et mettre les pointeurs dans textShadow, je ne sais pas comment le font MirageOS/CrunchyOS/DoorsCS, mais je suppose qu'ils aussi utilisent du saferam. Mais je n'en suis pas sûr.
Posté le 23/02/2013 à 11:48 Membre depuis le 15/03/2005, 3470 messages
Oui j'avais regardé un peu app.inc mais au final ça ne sert qu'a créer l'header et gérer les pages, et je ne pense pas dépasser la première (du moins pour l'instant).

Pour les routines je ne sais pas encore vraiment comment faire, il faudra les caser dans la RAM obligatoirement je pense, mais je vais voir comment noshell/zstart font.
Posté le 23/02/2013 à 12:30 Membre depuis le 03/06/2011, 520 messages
J'ai lu un comment de Kerm chez Cemetech qui disait que zStart patch l'OS pour l'exécuter après un RAM Clear. Et je crois que zStart/noshell auront obligatoirement à mettre au moins la table de vecteurs dans cmdShadow, sinon qu'est-ce qu'on va faire quand le programme fait un appel à l'un des routines d'ion ?

Je crois que j'ai vu ce que fait zStart. Regarde ces deux bouts de code :
	ld	b, 8					;ion a 8 routines
	ld	hl, cmdShadow+80		;la table de vecteurs d'ion commence à partir d'ici
makeVectorsLoop:
	ld	(hl), $CD				;c'est le HEX pour "call"
	inc	hl
	ld	(hl), cmdShadow&255		;LSB : tous les routines vont faire un appel à cmdShadow
	inc	hl
	ld	(hl), cmdShadow>>8		;MSB
	inc	hl
	djnz	makeVectorsLoop		;répéter
	
	ld	hl, ionFaker			;le code qui va exécuter la routine
	ld	de, cmdShadow			;sauvé dans au début de cmdShadow
	ld	bc, ionFakerEnd-ionFaker
	ldir

	in	a, (06)					;SMC la page de flash actuelle dans la routine ionFaker
	ld	(smc_ionFaker-ionFaker+cmdShadow+1), a
Ce code-ci crée la table de vecteur et charge un petit code pour exécuter les routines dans cmdShadow.

Puis quand on fait un appel à une des routines d'ion, le code d'ionFaker va s'exécuter :
;chargé dans cmdShadow
ionFaker:
	ex	(sp), hl				;hl = valeur dans la pile (le prochain octet après le call)
	push	de					;sauver de
	ld	de, cmdShadow+80+3		;début du vecteur + 3 (parce que hl = l'adresse de l'appel + 3)
	or	a						;reset carry
	sbc	hl, de					;(adresse de la routine appelée + 3) - (l'adresse du début du vecteur + 3)
								;hl = un numéro entre 0 et 21 (0 = la première routine, 21 = la 8ème)
	ld	de, myIonVectors		;une autre table qui contient des sauts aux routines d'ion dans zStart
	add	hl, de					;un numéro entre 0 et 21 + myIonVectors, l'offset de la routine appelée
	push	af					;sauver af
smc_ionFaker:
	ld	a, 00					;smc a remplacé $00 avec la page de FLASH où se trouve zStart (et donc les routines d'ion)
	out	(06), a					;charger la page FLASH
	pop	af						;restaurer a
	pop	de						;restaurer de
	ex	(sp), hl				;(sp) = l'adresse de la routine appelée
	ret							;sauter à la routine
ionRet:							;toutes les routines sautent ici, je suppose que l'on restaure la page FLASH actuelle
	push	af
	ld	a, $C2
	out	(06), a
	pop	af
	ret
Alors les routines mêmes il semble qu'elles restent dans zStart, on les met pas dans safeRAM/à la fin du programme.
Posté le 23/02/2013 à 13:01 Membre depuis le 15/03/2005, 3470 messages
C'est pas bête, je pense faire pareil, mais doit-on tenter de garder la compatibilité avec Ion (en adaptant ses routines au nouvel écran) ? J'hésite, ce serait peut être mieux de repartir sur du neuf.

edit : Le parser hook commence à me prendre la tête sick

_chkfindsym est sensé retourner 0 ou le # de la page flash dans laquelle est le programme dans le registre b, sauf que ça me renvoi toujours 0...
hook.inc
zshell_hook:
	.db $83	; used by os for hook safety check (add a,e can be used too)
	or a
	jr z,zshell_hook_start	; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
	xor a
	ret

zshell_hook_start:
	ld a,(parse_var)	; check the currently executed program type
	cp progobj
	jr z,zshell_hook_continue
	cp protprogobj
	jr nz,zshell_hook_return_z	; if it's not a prgm or a protected prgm, let the parser continue

zshell_hook_continue:
	ld hl,parse_var
	rst rmov9toop1
	bcall(_chkfindsym)
	;ex de,hl
	;ld a,(parse_var+1)
	;cp '#'
	;jr nz,zshell_hook_return_z
	ld a,b
	or a	; if the prgm is in ram, read it as it
	jr z,zshell_hook_read_data
	; todo : unarchive or read the prgm from flash
	jr zshell_hook_return_nz

zshell_hook_read_data:

run_program:
	ld hl,test_str
	call iputs

zshell_hook_return_nz:
	or $80	; reset zero flag, the parser can't continue to parse the variable
	ret

test_str:
	.db "test",0
Posté le 23/02/2013 à 13:46 Membre depuis le 03/06/2011, 520 messages
Voici un bout de code que j'ai écrit :
		ld hl,nombre_de_programme
		rst	20h				;9 octets à (hl) dans OP1
		bcall(_ChkFindSym)	;chercher le programme dans OP1
							;hl = VAT, de = addresse du data
		ret	c				;c armé si pas encontré
		in a,(6)			;il faut sauvegarder la page FLASH actuelle
		ld (savePort),a			;sauver avec SMC
		ld a,b				;b = 0 si le fichier est dans RAM
		or a
		 ret z				;si pas dans le RAM, b = la page FLASH
		out (6),a			;a = la page FLASH où est notre fichier
;...
nombre_de_programme:
.db ProgObj,"PROGNAME",0
Tu es sûr que parse_var contient le type d'objet et son nom ? S'il retourne 0 je crois que c'est parce que l'objet doit être dans la RAM... Carry est armé si le programme/variable n'a pas été trouvé.

Et oui, tu as raison, je suppose que ça ne vaut pas la peine de supporter ion :P
Posté le 23/02/2013 à 14:15 Membre depuis le 15/03/2005, 3470 messages
Oui normalement après chaque appel du parser hook, parse_var contient le type et le nom du dernier programme lancé (mais d'ailleurs, même s'il est protégé, le type semble toujours être progobj ($05), alors qu'il devrait être protprogobj ($06)...).

Autrement les fonctions basiques types "sin(" etc... sont bien des fonctions de classe 1, 2 ou 3 ? Parce que c'est pareil, ça me renvoi toujours 0 (valeur de l'accumulateur au début du hook) sad
Posté le 24/02/2013 à 05:29 Membre depuis le 03/06/2011, 520 messages
Je ne sais pas, je vais y jeter un coup d'oeuil dès que j'aurai le temps smile

Le code actuel est-il disponible quelque part ?

EDIT : A propos, si tu veux tester si un variable est entre deux numéros, disons 10 et 25, tu peux faire :
	ld a,(numéro)
	sub 10
	cp 25-10+1	;cp 16
	 jr nc,sauter
;faire quelque chose
;...
sauter:
	ret
Posté le 24/02/2013 à 10:34 Membre depuis le 15/03/2005, 3470 messages
zSHELL.zip

Je ferais peut être une page google code si on arrive jusqu'au point d'être capable d'exécuter des programmes avec nos propres routines.
chickendude (./12) :
A propos, si tu veux tester si un variable est entre deux numéros, disons 10 et 25, tu peux faire

Tiens j'aurai pas pensé à ça, ça va m'être utile même pour d'autres projets ! Merci tongue
Posté le 24/02/2013 à 11:09 Membre depuis le 03/06/2011, 520 messages
J'ai testé avec l'émulateur et il semble que parse_var ne contient pas le nom du programme, mais je sais pas pourquoi. Mais il semble que tu peux tirer le nom de (basic_start), attends une minute et j'essayerai d'écrire quelque chose...

Et voilà, hook.inc :
zshell_hook:
    .db $83 ; used by os for hook safety check (add a,e can be used too)
    or a
    jr z,zshell_hook_start  ; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
    xor a
    ret
 
zshell_hook_start:
	ld hl,(basic_start)	;ce que l'on a écrit sur le homescreen
	ld a,(hl)
	cp $5F				;tProg, on pourrait même permettre l'utilisiteur de ne pas écrire prgm
	 jr nz,zshell_hook_return_z
zshell_hook_continue:
	rst rmov9toop1
	ld hl,op1
	ld (hl),5			;progObj
    bcall(_chkfindsym)
    ld hl,not_found_txt
     jr c,run_program
    ld a,b				;b = 0 (dans RAM) ou la page FLASH
    or a				;si a = 0, le programme est dans la RAM
    ld hl,ram_txt
	 jr z,zshell_hook_read_data
	    ld hl,flash_txt	;sinon, dans la FLASH
zshell_hook_read_data:
run_program:
    call iputs
zshell_hook_return_nz:
    or $80  ; reset zero flag, the parser can't continue to parse the variable
    ret

not_found_txt:
	.db "not found",0
ram_txt:
	.db "in RAM",0
flash_txt:
	.db "in FLASH",0
Posté le 24/02/2013 à 11:42 Membre depuis le 15/03/2005, 3470 messages
Ah génial, je ne comprenais pas pourquoi ça renvoyait "not found" pour un programme test en RAM, mais c'est parce qu'en faite il était vide... Mais c'est dommage de ne pas pouvoir simplement utiliser parse_var.

Maintenant il va falloir faire la différence entre les programmes TI-Basic et ceux en ASM, mais je crois que ça n'est pas si difficile que ça. Il faudrait peut être définir l'header, mais à part peut être un token spécial pour indiquer à quel shell se réfère le programme, et un octet (ou bit ?) pour spécifier le write-back, il n'y a rien d'autre à indiquer ? Le nom du programme peut être (même s'il n'apparaitra nul part avec ce shell) ?

Autrement, j'ai lu qu'il était possible avec un petit hack de lire un programme depuis la flash (sans le désarchiver), tu sais si c'est vraiment possible ? J'imagine que ça pose problème pour la lecture de données interne au programme/le SMC ?
Posté le 24/02/2013 à 15:05 Membre depuis le 03/06/2011, 520 messages
En effet, je l'ai fait dans un projet. A vrai dire, c'est très simple. Tu simplement cherches le programme dans la flash puis le copies toi-même dans la RAM. Il faut que le programme s'exécute de $9D95, donc tu n'as que l'y copier (après avoir _insertmem la taille du programme). Ce que l'on fait en général c'est copier 768 octets à la fois (tout ce que l'on peut mettre dans saferam). Voici le code :
openFile:
;... le (nom/type du)  fichier à chercher doit être dans OP1
	bcall(_ChkFindSym)	;chercher le programme dans OP1
						;hl = VAT, de = addresse du data
	 ret	c				;c armé si pas encontré
	in a,(6)			;il faut sauvegarder la page FLASH actuelle
	ld (savePort),a
	ld a,b				;b = 0 si le fichier est dans RAM
	or a
	 ret z				;si pas dans le RAM, b = la page FLASH
	out (6),a			;a = la page FLASH où est notre fichier
	ex de,hl
	ld de,20				;
	add hl,de			;il y a 20 octets avant le début du data, le nom du program, sa taille, addresse, page de FLASH, etc.
;...
; hl = début des datas
;...
	ret

closeFile:
savePort = $ + 1
	ld a,0
	out (6),a
	ret

;merci à thepenguin77 de m'avoir aidé avec ce code-ci
;vérifier que l'on ne va pas lire hors de $4000-$7FFF
;si hl = $8000, il faut le remettre à $4000 est incrémenter la page d'où nous lisons
loadNextHL:
	inc hl
checkOverflow:
	ld a,h
	res 7,h			;bit 7 = $8000+
	set 6,h			;bit 6 = $4000+
	cp h
	 ret z
		in a,(6)	;charger la prochaine page de FLASH
		inc a
		out (6),a
		ret
Chaque fois que tu veux lire le prochain octet il faut faire un appel à loadNextHL. Après tu peux ld a,(hl) ou faire ce que tu voudras. Il faut le faire comme ça parce que si la valeur de HL dépasse $7FFF il faut charger la prochaine page FLASH.

On a aussi écrit une routine style LDIR :
;hl = position dans FLASH
;bc = combien d'octets à charger
;gbuf utilisé comme buffer
flashToBuffer:
	ld de,gbuf
flashToBufferLoop:
	ldi
	 ret po
	call checkOverflow
	jr flashToBufferLoop
S'il y a de l'espace dans l'app on peut écrire une routine plus rapide qui calcule combien d'octets il reste avant d'atteindre $8000 pour ne pas avoir à vérifier après chaque octet lu.

En bref, le programme reste dans l'archive, tu ne fais que le copier dans la RAM. Si le programme a changé pendant son exécution, il faudra le récrire dans l'archive (mais je ne sais pas comment faire cette dernière partie, je simplement "désarchive" le fichier, copier les changements, puis je le "rearchive". Je crois que l'on peut "unlocker" l'archive et changer seulement les octets qui ont changé, mais je ne sais pas comment le faire.

Et la différence entre les programmes TI-BASIC/asm, on peut pas simplement chercher le token AsmPrgm ? Mais je suppose que l'on pourrait gagner deux octets en l'omettant :P Et pour le moment, il n'existe aucun shell pour la 84+C wink Je m'avais toujours interessé aux shells, mais je n'en ai jamais écrit un.

EDIT : J'ai trouvé _WriteAByte, _WriteFlash, et Port 14
Posté le 24/02/2013 à 15:31 Membre depuis le 15/03/2005, 3470 messages
Cool, dès que j'en suis à l'exécution de programmes je test tout ça, merci tongue

Autrement ça y est j'ai fait la différenciation des programmes ASM "unsquishés" avec le reste (donc principalement TI-Basic, mais il faudrait pouvoir identifier les autres futurs types de programmes TI 84+CSE).
zshell.z80
	.nolist
;#include "ti84pcse.inc"
#include "ti83p.inc"	; only for debug
#define program_size_count	saferam1
	.list
	.org $4000
	.db $80,$0f,$00,$00,$00,$00	; program length = 0
	.db $80,$12,$01,$04	; program type = shareware for TI 83+
	.db $80,$21,$01	; app id = 1
	.db $80,$31,$01	; app build # = 1
	.db $80,$48, "zSHELL  "	; app name (must be 8 bytes long)
	.db $80,$81,$01	; app page = 1
	.db $80,$90	; no default splash screen
	.db $03,$26,$09,$04,$04,$06f,$1b,$80	; date stamp = 5/12/1999
	.db $02,$0d,$40	; encrypted TI date stamp signature
	.db $a1,$6b,$99,$f6,$59,$bc,$67
	.db $f5,$85,$9c,$09,$6c,$0f,$b4,$03,$9b,$c9
	.db $03,$32,$2c,$e0,$03,$20,$e3,$2c,$f4,$2d
	.db $73,$b4,$27,$c4,$a0,$72,$54,$b9,$ea,$7c
	.db $3b,$aa,$16,$f6,$77,$83,$7a,$ee,$1a,$d4
	.db $42,$4c,$6b,$8b,$13,$1f,$bb,$93,$8b,$fc
	.db $19,$1c,$3c,$ec,$4d,$e5,$75
	.db $80,$7f,$00,$00,$00,$00	; program image length = 0
	.dw $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000	; padding (header length must be 128 bytes long)

start:
	di	; disable interrupts (todo : check which bcall may resume them)
	bcall(_clrlcdfull)	; clear screen
	bcall(_indicatoroff)	; disable run indicator
	bcall(_cleargbuf)	; clear graph buffer
	res texterasebelow,(iy+textflags)	; reset some textflags
	res textinverse,(iy+textflags)	; reset some textflags
	ld hl,$0501
	ld (currow),hl
	ld hl,zshell_string
	call iputs
	bit parserhookactive,(iy+hookflags4)
	jr z,install_zshell	; no current hook
	;in a,(pmpagea)
	;ld hl,parserhookptr+2
	;cp (hl)
	;jr nz,quit	; zshell hook already exists

uninstall_zshell:
	; todo : ask to destroy/chain current hooks or uninstall zshell hook
	bcall(_disableparserhook)
	ld hl,$0003
	ld (currow),hl
	ld hl,uninstalling_string
	call iputs
	bcall(_getkey)
	bcall(_jforcecmdnochar)

install_zshell:
	ld hl,zshell_hook	; put hook adress into hl
	in a,(pmpagea)	; put page # into a
	bcall(_setparserhook)	; install hook
	ld hl,$0003
	ld (currow),hl
	ld hl,installing_string
	call iputs
	bcall(_getkey)

quit:
	; todo : ask for destroying or chaining it
	bcall(_jforcecmdnochar)	; quit the app

iputs:
	ld a,(hl)
	or a
	ret z
	bcall(_putc)
	inc hl
	jr iputs

get_byte:
	push de	; de = vat pointer
	push hl ; hl = data to read
	ld a,b	; b = flash page #, or 0 if in ram
	or a
	call nz,get_byte_paged
	push hl
	ld hl,(program_size_count)
	dec (hl)	; just to make sure we're not reading out of the program (todo : check if prgm size are +1)
	ld a,(hl)
	or a
	pop hl
	ld a,(hl)
	pop hl
	pop de
	inc hl
	ret nz
	scf	; c is set if we're out of the program
	ret

get_byte_paged:
	ld a,b
	bcall(_getbytepaged)
	ld (hl),b
	ret

#include "hook.inc"

zshell_string:
	.db "zSHELL",0

installing_string:
	.db "zSHELL has been installed",0

uninstalling_string:
	.db "zSHELL has been uninstalled",0
	.end
hook.inc
zshell_hook:
	.db $83 ; used by os for hook safety check (add a,e can be used too)
	or a
	jr z,zshell_hook_start  ; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
	xor a
	ret

zshell_hook_start:
	ld hl,(basic_start)	; what's on homescreen
	ld a,(hl)
	cp tprog
	jr nz,zshell_hook_return_z

zshell_hook_continue:
	rst rmov9toop1
	ld hl,op1
	ld (hl),progobj
	bcall(_chkfindsym)
	ex de,hl	; cause of _getbytepaged parameters
	ld a,e_undefined
	bjumpc(_jerror)
	ld a,b	; b = 0 if in ram, else flash page #
	or a
	ld a,e_archived	; temporary
	bjumpnz(_jerror)

zshell_hook_read_data:
	inc hl
	call get_byte
	ld e,a
	call get_byte
	ld d,a	; de now contains the size of the program
	ld (program_size_count),de
	call get_byte
	ret c	; the program is empty
	cp tasmprgm
	ld hl,asm_unsquished_txt
	jr z,zshell_hook_next
	;cp tzshellprgm
	;ld hl,zshell_txt
	;jr z,zshell_hook_next
	ld hl,basic_txt

zshell_hook_next:
	call iputs

zshell_hook_return_nz:
	or $80  ; reset zero flag, the parser can't continue to parse the variable
	ret

asm_unsquished_txt:
	.db "ASM unsquished",0

zshell_txt:
	.db "zSHELL",0

basic_txt:
	.db "TI-Basic (?)",0

zSHELL.zip

Par contre je ne sais pas pourquoi mais basic_start ne contient pas toujours le type et le nom du programme exécuté, et du coup ça fait une erreur "undefined" de temps à autres...?
Posté le 24/02/2013 à 16:39 Membre depuis le 03/06/2011, 520 messages
Je n'ai reçu l'erreur "undefined" que quand le programme n'existait pas. Peut-être il faut écrire un zéro après le nom du programme (dans OP1) ? Mais même avec les noms courts je n'ai pas de problèmes.

Je crois que l'on peut commencer à coder la partie qui exécute les programmes grin Voici un bout de code que j'avais écrit pour sauter la limite de 8k (on peut peut-être l'optimiser et je suppose qu'il faudra faire quelques modifications, mais c'est un début) :
debut_routine:
	bcall(_ChkFindSym)
	 ret	c
	ld	a, b					;a = page flash
	or	a
	 ret	z					;quitter si dans la ram
	ex	de, hl					;hl = début du programme
	ld	de, appBackUpScreen
	ld	bc, 2+2+7+1+3+3+3
	push	af					;sauver page flash
		bcall(_FlashToRam)		;copier 22 octets (header/AsmPrgm) dans appbackupscreen
	pop	af						;restaurer page flash (possiblement pas nécéssaire)
	ld	bc, 2+2+7+1+3+3+3+$4000
	or	a
	sbc	hl, bc					;si hl <$4022, on a avancé à la prochaine page
	add	hl, bc					; il faut donc augmenter a
	adc	a, 0					;a+1 si on a avancé une page
	push	af
	ex	de, hl					;hl = prochain octet dans appBackUpScreen
	dec	hl
	dec	hl
	dec	hl
	ld	a, (hl)					;MSB de la taille du programme
	dec	hl						;
	ld	l, (hl)					;LSB de la taille du programme
	ld	h, a
	push	hl					;hl = taille du programme
	push	de
	ld	de, $9D95				;de = où charger le programme
	bcall(_InsertMem)			;créer de l'espace
	pop	hl						;hl = premier octet des datas du programme
	pop	bc						;bc = taille du programme
	pop	af						;af = première page de ses datas
	bcall(_FlashToRam)
	jp	$9D95					;l'exécuter
Posté le 24/02/2013 à 18:02 Membre depuis le 15/03/2005, 3470 messages
Donc pour notre propre header (celui des programmes), voilà un début :
	.nolist
#include "ti84pcse.inc"
	.list
	.org usermem-2
	.db texttok,tasm84ccmp	; permet au TI-OS de lancer le programme, je me demande quel serait le moyen le plus propre de lui indiquer
							; que le programme n'est pas exécutable sans zshell (ion rajoutait un 'ret' juste après il me semble) ?
	.db 1	; pour le write-back
	[...]
	.end


edit : un début de désarchivage des programmes (mais je suis à peu près sûr que ça ne marche pas encore tongue) :
zshell.z80
	.nolist
;#include "ti84pcse.inc"
#include "ti83p.inc"	; only for debug
#define program_length_count	saferam1
	.list
	.org $4000
	.db $80,$0f,$00,$00,$00,$00	; program length = 0
	.db $80,$12,$01,$04	; program type = shareware for TI 83+
	.db $80,$21,$01	; app id = 1
	.db $80,$31,$01	; app build # = 1
	.db $80,$48, "zSHELL  "	; app name (must be 8 bytes long)
	.db $80,$81,$01	; app page = 1
	.db $80,$90	; no default splash screen
	.db $03,$26,$09,$04,$04,$06f,$1b,$80	; date stamp = 5/12/1999
	.db $02,$0d,$40	; encrypted TI date stamp signature
	.db $a1,$6b,$99,$f6,$59,$bc,$67
	.db $f5,$85,$9c,$09,$6c,$0f,$b4,$03,$9b,$c9
	.db $03,$32,$2c,$e0,$03,$20,$e3,$2c,$f4,$2d
	.db $73,$b4,$27,$c4,$a0,$72,$54,$b9,$ea,$7c
	.db $3b,$aa,$16,$f6,$77,$83,$7a,$ee,$1a,$d4
	.db $42,$4c,$6b,$8b,$13,$1f,$bb,$93,$8b,$fc
	.db $19,$1c,$3c,$ec,$4d,$e5,$75
	.db $80,$7f,$00,$00,$00,$00	; program image length = 0
	.dw $0000,$0000,$0000,$0000,$0000,$0000,$0000,$0000	; padding (header length must be 128 bytes long)

start:
	di	; disable interrupts (todo : check which bcall may resume them)
	bcall(_clrlcdfull)	; clear screen
	bcall(_indicatoroff)	; disable run indicator
	bcall(_cleargbuf)	; clear graph buffer
	res texterasebelow,(iy+textflags)	; reset some textflags
	res textinverse,(iy+textflags)	; reset some textflags
	ld hl,$0501
	ld (currow),hl
	ld hl,zshell_string
	call iputs
	bit parserhookactive,(iy+hookflags4)
	jr z,install_zshell	; no current hook
	;in a,(pmpagea)
	;ld hl,parserhookptr+2
	;cp (hl)
	;jr nz,quit	; zshell hook already exists

uninstall_zshell:
	; todo : ask to destroy/chain current hooks or uninstall zshell hook
	bcall(_disableparserhook)
	ld hl,$0003
	ld (currow),hl
	ld hl,uninstalling_string
	call iputs
	bcall(_getkey)
	bcall(_jforcecmdnochar)

install_zshell:
	ld hl,zshell_hook	; put hook adress into hl
	in a,(pmpagea)	; put page # into a
	bcall(_setparserhook)	; install hook
	ld hl,$0003
	ld (currow),hl
	ld hl,installing_string
	call iputs
	bcall(_getkey)

quit:
	; todo : ask for destroying or chaining it
	bcall(_jforcecmdnochar)	; quit the app

iputs:
	ld a,(hl)
	or a
	ret z
	bcall(_putc)
	inc hl
	jr iputs

get_byte:
	push de	; de = vat pointer
	push hl ; hl = data to read
	ld a,b	; b = flash page #, or 0 if in ram
	or a
	call nz,get_byte_paged
	push hl
	ld hl,(program_length_count)
	dec (hl)	; just to make sure we're not reading out of the program (todo : check if prgm length are +1)
	ld a,(hl)
	or a
	pop hl
	ld a,(hl)
	pop hl
	pop de
	inc hl
	ret nz
	scf	; c is set if we're out of the program
	ret

get_byte_paged:
	push bc
	ld a,b
	bcall(_getbytepaged)
	ld (hl),b
	pop bc
	ret

#include "hook.inc"

zshell_string:
	.db "zSHELL",0

installing_string:
	.db "zSHELL has been installed",0

uninstalling_string:
	.db "zSHELL has been uninstalled",0
	.end
hook.inc
zshell_hook:
	.db $83 ; used by os for hook safety check (add a,e can be used too)
	or a
	jr z,zshell_hook_start  ; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
	xor a
	ret

zshell_hook_start:
	ld hl,(basic_start)	; what's on homescreen
	ld a,(hl)
	cp tprog
	jr nz,zshell_hook_return_z

zshell_hook_continue:
	rst rmov9toop1
	ld hl,op1
	ld (hl),progobj
	bcall(_chkfindsym)
	ex de,hl	; cause of _getbytepaged parameters
	ld a,e_undefined
	bjumpc(_jerror)
	call get_byte
	ld e,a
	call get_byte
	ret c	; the program is empty
	ld d,a	; de now contains the length of the program
	ld (program_length_count),de
	call get_byte	; skip t2bytetok/texttok
	call get_byte
	cp tasmprgm
	ld hl,asm_unsquished_txt
	jr z,zshell_hook_execute_prgm
	;cp tzshellprgm
	;ld hl,zshell_txt
	;jr z,zshell_hook_execute_prgm
	jr zshell_hook_return_z	; TI-Basic program

zshell_hook_execute_prgm:
	; todo : skip zshell things
	ld a,b
	or a
	call nz,zshell_hook_unarchive
	; todo : relocate non archived prgm before launch
	jp progstart

zshell_hook_unarchive:
	push hl
	ld hl,(program_length_count)
	push bc
	bcall(_enoughmem)
	pop bc
	pop hl
	ld a,e_memory
	bjumpc(_jerror)
	ld a,b
	ld de,progstart
	ld bc,(program_length_count)
	bcall(_flashtoram)
	ret

zshell_hook_return_nz:
	or $80  ; reset zero flag, the parser can't continue to parse the variable
	ret

asm_unsquished_txt:
	.db "ASM unsquished",0

zshell_txt:
	.db "zSHELL",0

basic_txt:
	.db "TI-Basic (?)",0
Posté le 25/02/2013 à 13:35 Membre depuis le 03/06/2011, 520 messages
Maintenant je bosse sur l'exécution des programmes dans RAM. Ça résulte assez compliqué :/ J'ai écrit une routine qui copie le program à $9D95, mais ça ne te permet utiliser que la motie de la RAM (sinon on aura pas espace suffisant pour le _InsertMem). Voice le "simple way" :
simpleWay:
;get program size
	ld e,(hl)
	inc hl
	ld d,(hl)				;de = program size, first two bytes in data
	dec de
	dec de					;-2 because of AsmPrgm token
;check if it starts with AsmPrgm token
	inc hl					;$BB
	ld a,(hl)
	cp $BB					;if first byte isn't $BB, not an assembly program
	 jr nz,zshell_hook_return_z	;parse as basic
	inc hl					;$6D AsmPrgm token (2 bytes)
	ld a,(hl)
	cp $6D
	 jr nz,zshell_hook_return_z	;if program is not an assembly program, quit
;create space at $9D95 to load the program
	inc hl					;first byte of program data
	push hl					;hl = first byte of prog data
	push de					;de = prog size (-AsmPrgm token)
		ex de,hl			;hl = prog size
		ld de,progstart		;$9D95
		bcall(_InsertMem)	;insert 'hl' bytes to $9D95
	pop bc					;bc = size of program
	pop hl					;hl = first byte of program data
	push bc					;save size of program
		add hl,bc			;we've inserted 'bc' bytes ;)
		ldir				;de = progstart
		call progstart		;run the program
;now delete that memory
	pop de					;de = number of bytes to delete
	ld hl,progstart			;hl = where to delete them from
	bcall($4357)			;_DelMem
	ret
Bientôt j'aurai fini le "hard way", au moins la première partie smile

EDIT : Ok, ça marche !
progstartLocation = saferam1	;current address in progstart
progAddress = saferam1+2		;current address of program in RAM

;the program is in RAM, so let's copy it to $9D95!
;hl = pointer to start of data
;de = VAT info (not important)
;a = 0 (in RAM) (also unimportant)
zshell_hook_execute_prgm_ram:
;get program size
	ld e,(hl)
	inc hl
	ld d,(hl)				;de = program size, first two bytes in data
	dec de
	dec de					;-2 because of AsmPrgm token
;check if it starts with AsmPrgm token
	inc hl					;$BB
	ld a,(hl)
	cp $BB					;if first byte isn't $BB, not an assembly program
	 jr nz,zshell_hook_return_z	;parse as basic
	inc hl					;$6D AsmPrgm token (2 bytes)
	ld a,(hl)
	cp $6D
	 jr nz,zshell_hook_return_z	;if program is not an assembly program, quit
	inc hl					;first byte of program data
load_program_to_progstart:
;hl = first byte of program data
;de = program size
	ld bc,progstart
	ld (progstartLocation),bc
	ld (progAddress),hl
	ex de,hl				;hl = size
load_loop:
;check if there are <768 bytes left to copy
	ld bc,768
	or a
	sbc hl,bc				;subtract 768 from the program size
	 jr nc,$+8				;if no carry, there are still more than 768 bytes to copy
		add hl,bc
		ld c,l
		ld b,h
		ld hl,$0000
	push hl					;how many bytes left to copy
	ld hl,(progAddress)
;copy the program to the gbuf
		push bc				;hl = program data start
			ld de,gbuf		;bc = # bytes to copy
			ldir			;copy bc bytes
		pop de				;# bytes copied
		ld (progAddress),hl	;save new program data pointer
;delete BC bytes from the program
		or a				;hl = start of prog data + 768
		sbc hl,de			;
		push de				;de = # of bytes copied
			bcall(_DelMem)	;hl = where to delete from, de = # bytes
		pop hl				;hl = # bytes deleted
;insert HL bytes to $9D95
		ld de,(progstartLocation)	;$9D95
		push hl				;hl = # bytes deleted
			bcall(_InsertMem)	;insert 'hl' bytes to $9D95
		pop bc				;bc = bytes deleted
		ld hl,(progstartLocation)		;ex de,hl ???
		add hl,bc
		ld (progstartLocation),hl
;copy gbuf to $9D95
		ld hl,gbuf			;de = location where memory was inserted ($9D95+XXX)
		ldir				;copy # of bytes deleted from gbuf to progstart
	pop hl					;how many bytes are left to copy
	ld a,l
	or h
	 jr nz,load_loop

	call progstart			;run the program
;now rewrite the data back into the program
;...not done yet...
	ret


x7e3

Pour le moment tu ne peux l'exécuter qu'une fois parce que je ne copie pas le programme de nouveau (donc la seconde fois le programme sera vide :P). Mais je crois que je peut tout simplement invertir progstartLocation et progAddress...
Posté le 25/02/2013 à 15:42 Membre depuis le 15/03/2005, 3470 messages
Wow, bravo happy

C'est génial, j'ai adapté ton premier code au shell : zSHELL.zip tongue

0exz

Mais je ne sais pas pourquoi j'ai des erreurs "undefined" de temps à autres (comme si _chkfindsym ne trouvait pas le programme)... sad
hook.inc
zshell_hook:
	.db $83 ; used by os for hook safety check (add a,e can be used too)
	or a
	jr z,zshell_hook_start  ; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
	xor a
	ret

zshell_hook_start:
	ld hl,(basic_start)	; what's on homescreen
	ld a,(hl)
	cp tprog
	jr nz,zshell_hook_return_z	; if it don't start with "prgm", we don't care
	rst rmov9toop1	; we put "prgmANYTHING" into op1
	ld hl,op1
	ld (hl),progobj	; then replace "prgm" token with the program type (progobj)
	bcall(_chkfindsym)	; so we can find its datas
	ex de,hl	; cause of _getbytepaged parameters
	ld a,e_undefined
	bjumpc(_jerror)	; if not found, throw an "undefined error"
	call get_byte	; else start to read it
	ld e,a
	call get_byte	; first two bytes are length of the program
	jr c,zshell_hook_return_nz	; if empty, don't parse
	ld d,a
	dec de
	dec de	; we don't count the first two bytes (t2bytetok/texttok+tasmcmp/tasm84ccmp) into the program length
	ld (program_length_count),de
	call get_byte	; skip t2bytetok/texttok
	call get_byte
	cp tasmcmp
	jr z,zshell_hook_execute_prgm
	;cp tzshellprgm
	;ld hl,zshell_txt
	;jr z,zshell_hook_execute_prgm
	jr zshell_hook_return_z	; TI-Basic program

zshell_hook_execute_prgm:
	; todo : skip zshell things
	ld a,b
	or a
	call nz,zshell_hook_unarchive
	; todo : relocate non archived prgm before launch

simpleWay:
	; create space at progstart to load the program
	push hl	; hl = first byte of prog data
	push de	; de = prog length-2
	ex de,hl	;hl = prog size
	ld de,progstart	; $9d95
	bcall(_insertmem)	; insert hl bytes to progstart
	pop bc	; bc = size of program
	pop hl	; hl = first byte of program data
	push bc	; save size of program
	add hl,bc	; we've inserted bc bytes ;)
	ldir	; de = progstart
	call progstart	; run the program
	; now delete that memory
	pop de	; de = number of bytes to delete
	ld hl,progstart	; hl = where to delete them from
	bcall(_delmem)
	ret

zshell_hook_unarchive:
	push hl
	ld hl,(program_length_count)
	push bc
	bcall(_enoughmem)
	pop bc
	pop hl
	ld a,e_memory
	bjumpc(_jerror)
	ld a,b
	ld de,progstart
	ld bc,(program_length_count)
	bcall(_flashtoram)
	ret

zshell_hook_return_nz:
	or $80  ; reset zero flag, the parser can't continue to parse the variable
	ret

Enfaite j'ai utilisé call get_byte pour calculer la taille du programme et son type pour ne pas avoir plus tard à d'abord désarchiver le programme avant de le tester (savoir s'il est vide et si c'est bien un programme ASM, enfin quoique si on veut permettre l'exécution de programmes TI-Basic archivés...?)

Je vais adapter le "hard way" (ah et je n'ai pas testé le désarchivage, mais ça m'étonnerai que ça marche) smile

edit : autrement je n'avais pas fait gaffe, mais un shell TI 85 porte déjà ce nom ZShell (enfin c'est pas exactement identique, mais ça peut être trompeur, non ?). J'aime bien ce nom mais s'il faut on peut le changer.

edit 2 : voilà :
hook.inc
zshell_hook:
	.db $83 ; used by os for hook safety check (add a,e can be used too)
	or a
	jr z,zshell_hook_start  ; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
	xor a
	ret

zshell_hook_start:
	ld hl,(basic_start)	; what's on homescreen
	ld a,(hl)
	cp tprog
	jr nz,zshell_hook_return_z	; if it don't start with "prgm", we don't care
	rst rmov9toop1	; we put "prgmANYTHING" into op1
	ld hl,op1
	ld (hl),progobj	; then replace "prgm" token with the program type (progobj)
	bcall(_chkfindsym)	; so we can find its datas
	ex de,hl	; cause of _getbytepaged parameters
	ld a,e_undefined
	bjumpc(_jerror)	; if not found, throw an "undefined error"
	call get_byte	; else start to read it
	ld e,a
	call get_byte	; first two bytes are length of the program
	jr c,zshell_hook_return_nz	; if empty, don't parse
	ld d,a
	dec de
	dec de	; we don't count the first two bytes (t2bytetok/texttok+tasmcmp/tasm84ccmp) into the program length
	ld (program_length_count),de
	call get_byte	; skip t2bytetok/texttok
	call get_byte
	cp tasmprgm
	jr z,zshell_hook_execute_unsquished_asm_prgm
	cp tasmcmp
	jr z,zshell_hook_execute_compiled_asm_prgm
	;cp tzshellprgm
	;ld hl,zshell_txt
	;jr z,zshell_hook_execute_zshell_prgm
	jr zshell_hook_return_z	; TI-Basic program

zshell_hook_execute_unsquished_asm_prgm:
	;call zshell_hook_program_start_begin
	bcall(_executeprgm)	; can only run unarchived prgm
	jr zshell_hook_return_nz

zshell_hook_execute_compiled_asm_prgm:
	call zshell_hook_program_start_begin

zshell_hook_load:
	push hl	; how many bytes left to copy
	ld hl,(progaddress)	; copy the program to the gbuf
	push bc	; hl = program data start
	ld de,gbuf	; bc = # bytes to copy
	ldir	; copy bc bytes
	pop de	; # bytes copied
	ld (progaddress),hl	; save new program data pointer
	; delete bc bytes from the program
	or a	; hl = start of prog data+768
	sbc hl,de
	push de	; de = # of bytes copied
	bcall(_delmem)	; hl = where to delete from, de = # bytes
	pop hl	; hl = # bytes deleted
	; insert HL bytes to $9d95
	ld de,(progstartlocation)	; progstart ($9d95)
	push hl	; hl = # bytes deleted
	bcall(_insertmem)	; insert hl bytes to $9d95
	pop bc	; bc = bytes deleted
	ld hl,(progstartlocation)	; ex de,hl ???
	add hl,bc
	ld (progstartlocation),hl
	; copy gbuf to $9d95
	ld hl,gbuf	; de = location where memory was inserted ($9d95+XXXX)
	ldir	; copy # of bytes deleted from gbuf to progstart
	pop hl	; how many bytes are left to copy
	ld a,l
	or h
	jr nz,zshell_hook_load_loop
	call progstart	; run the program
	; now rewrite the data back into the program
	; ...not done yet...

zshell_hook_return_nz:
	or $80  ; reset zero flag, the parser can't continue to parse the variable
	ret

zshell_hook_program_start_begin:
	ld a,b
	or a
	call nz,zshell_hook_unarchive
	; hl = first byte of program data
	; de = program length-2
	ld bc,progstart
	ld (progstartlocation),bc
	ld (progaddress),hl
	ex de,hl	; hl = length

zshell_hook_load_loop:
	ld bc,768	; check if there are <768 bytes left to copy (gbuf length)
	or a
	sbc hl,bc	; subtract 768 from the program size
	ret nc	; if no carry, there are still more than 768 bytes to copy
	add hl,bc
	ld b,h
	ld c,l
	ld hl,$0000
	ret

zshell_hook_unarchive:
	push hl
	ld hl,(program_length_count)
	push bc
	bcall(_enoughmem)
	pop bc
	pop hl
	ld a,e_memory
	bjumpc(_jerror)
	ld a,b
	ld de,progstart
	ld bc,(program_length_count)
	bcall(_flashtoram)
	ret

Enfaite les erreurs "undefined" étaient simplement dues au fait que le hook se terminait avec le zero flag mis cheeky
Posté le 26/02/2013 à 17:41 Membre depuis le 13/09/2011, 21 messages
Attention: Je suis une américaine et je ne parle pas bien le français. Je suis désolé en avance pour ma grammaire .___.

D: Je suis désolé, je pensais que j'ai déjà posté. Il y a été deux jours depuis je "l'ai posté" XD

J'ai crée ces codes:

Un Hook:

     .db 83h
     or a
     jr z,$+4
ExitHook3:
       cp a
       ret
     ld hl,(OP1)
     ld bc,2305h
     or a
     sbc hl,bc
     jr nz,ExitHook3
     ld hl,(nextParseByte)
     ld a,5Fh
     cp (hl)
     jr nz,ExitHook3
     ld de,OP1+1
     ld b,8
CopyNameLoop:
     inc hl
     ld a,(hl)
     cp 30h
     jr c,FinishCopyLoop
     cp 3A
     jr nc,FinishCopyLoop
     cp 41h
     jr c,FinishCopyLoop
     cp 5Ch
     jr nc,FinishCopyLoop
     ld (de),a
     inc de
     djnz CopyNameLoop
FinishCopyLoop:
     xor a
     ld (de),a
     bcall(_ChkFindSym)
     jr c,ProgNotFound
     ld a,b
     or a
     ex de,hl
     jr z,DataAtAHL
     ld b,0               ;BC = name size
     add hl,bc
     ld c,10
     add hl,bc
     bit 7,h
     jr z,$+7
       inc a
       set 6,h
       res 7,h
DataAtAHL:
     push hl
     push af
     ld bc,8
     ld de,OP2
     bcall(_FlashToRAM2)
     pop af
     pop hl
;Now OP2 has the first 8 bytes of data (first two bytes are the size of the var)
;A is the flash page the the size bytes start on
;HL points to to the size bytes

Utilisez le 8 octets pour le taille de la programme et le premier 6 octets de la programme pour le "header."


- routine qui copie un buffer de 768 octets au milieu de l'écran (ou 1 bit = 1 pixel)


Voila smile :

Define96x64Window:
	ld hl,$10B8		; BGR mode, increment order
	ld a,$03
	call SetLCDRegister
        ld hl,0                 ;coord start
        ld a,20h                ;set y coord = 0
        call SetLCDRegister+2   ;A incremented to 21h
        call SetLCDRegister+2   ;set x coord = 0
        ld a,50h                ;horizontal
        call SetLCDRegister+2   ;set y coord = 0
        ld hl,63
        call SetLCDRegister+2   ;set y coord = 63
        ld hl,0
        call SetLCDRegister+2   ;set x coord = 0
        ld hl,95
        call SetLCDRegister+2   ;set x coord = 95

BWImage: 
;Inputs: 
;     HL points to the data 
;     the window is already defined 
;Outputs: 
;     B,D,E are all 0 
;     A is either $00 or $FF 
;     C is the last byte of the buffer 

     ld de,3               ;10      10 
BWLoop:                    ; 
     ld b,8                ;7       7*768 
     ld a,(hl)             ;7       7*768
     cpl                   ;4       4*768
     ld c,a                ;4       4*768
BWLoop2:                   ; 
     rlc c                 ;8       8*6144 
     sbc a,a               ;4       4*6144 
     out (11h),a   ;11      11*6144 
     out (11h),a   ;11      11*6144 
     djnz BWLoop           ;13|8    768(13*8-5) 
     dec d                 ;4       4*768 
     jr nz,BWLoop          ;12|7    12*768-15 
     dec e                 ;4       4*3 
     jr nz,BWLoop          ;12|7    12*3-5 
     ret                   ;10      10 
;Total time: 
;314160 t-states.


SetLCDRegister:
     ld c,$11
     out ($10),a \ out ($10),a
     out (c),h
     out (c),l
     inc a
     ret


- dessin de rectangle pleins/vides, cercles, lignes

Dessiner un rectangle sur l'écran:

Rectangle:
;Inputs:
;     DE = color
;     4 pushes to the stack in order:
;        push <width>
;        push <right coordinate>
;        push <height>
;        push <upper coordinate>
;RAM: needs 2 bytes of RAM:
;     (TempWord1) is two bytes
     ld hl,$10B8             ; BGR mode, increment order
     ld a,$03
     call SetLCDRegister
     pop hl \ ex (sp),hl
     ld a,20h                ;set upper coordinate
     call SetLCDRegister+2   ;A incremented to 21h
     ld a,50h                ;horizontal
     call SetLCDRegister+2   ;
     ld b,h
     ld c,l
     pop hl \ ex (sp),hl
     ld (TempWord1),hl
     add hl,bc
     call SetLCDRegister+2   ;set lower coordinate

     pop hl \ ex (sp),hl
     ld a,21h
     call SetLCDRegister+2
     ld a,52h
     call SetLCDRegister+2   ;set right coordinate
     ld b,h
     ld c,l
     pop hl \ ex (sp),hl
     push hl
     add hl,bc
     call SetLCDRegister+2   ;set left coordinate
     pop hl                  ;width
     ld a,(TempWord1)        ;
     ld b,a                  ;b is height
;DE is color
;C is 11h
;B is the height
;HL is the width
     dec hl
     inc h
     inc l
     push hl
FillRectLoop:
     out (c),d
     out (c),e
     dec l
     jr nz,FillRectLoop
     dec h
     jr nz,FillRectLoop
     pop hl
     djnz FillRectLoop-1
     ret


Et je créerai le code pour les cercles, aussi grin
Posté le 26/02/2013 à 18:38 Membre depuis le 15/03/2005, 3470 messages
Wow c'est génial, merci smile

Je vais tenter de comprendre comment ça marche car ça m'a l'air très optimisé, bravo tongue

De mon côté je tente de gérer l'exécution de programmes TI-Basic archivés (en gros je les désarchive avec _flashtoram à $9d95 avant d'utiliser _parseinp, mais ça ne marche pas encore).

edit : Aussi, qu'est censé contenir OP1 au début du hook ? Le wikiti dit de ne pas s'y fier.
Posté le 27/02/2013 à 00:23 Membre depuis le 03/06/2011, 520 messages
Peut-être pour les programmes BASIC tu peux créer un nouveau programme dans RAM, l'y copier, puis exécuter ce nouveau programme ? Je crois que les programmes TI BASIC peuvent s'exécuter de n'importe quel endroit dans RAM. Peut-être quelque chose avec : http://wikiti.brandonw.net/index.php?title=83Plus:BCALLs:4C3C ?
Posté le 27/02/2013 à 11:00 Membre depuis le 15/03/2005, 3470 messages
J'ai trouvé une page intéressante : http://z80-heaven.wikidot.com/shells . Je tenterai bien de faire un système d'exécution de programmes compressés (comme crunchyos), mais je me demande si ça fait vraiment gagner de l'espace (je ferai quelques tests).

Autrement je me demande, lorsqu'un programme TI-Basic est désarchivé et exécuté, s'il fait appel à un autre programme TI-Basic archivé, il n'est pas possible de le désarchiver à son tour ? Ou alors il faut déplacer le programme actuel (progstart+la taille du deuxième programme), copier le nouveau à progstart, l'exécuter, puis quand on a finit replacer le premier programme ?

Ça risque d'être difficile à coder si le deuxième programme fait appel à un troisième etc..., non ?
Posté le 28/02/2013 à 07:55 Membre depuis le 03/06/2011, 520 messages
Je crois que les programmes TI-BASIC peuvent s'exécuter de n'importe quel endroit dans la RAM, il ne faut pas les copier à progstart. On pourrait peut-être écire un autre hook pour le token prgm, quand on exécute ce token notre hook cherchera le programme et le desarchiver s'il est dans l'archive avant de le faire courir. Je ne sais pas s'il serait plus efficace de le copier dans un nouveau programme et faire courir le nouveau programme. Pour le moment je vais seulement m'occuper des programmes asm grin
Posté le 28/02/2013 à 20:54 Membre depuis le 15/03/2005, 3470 messages
J'ai un début de gestion des programmes TI-Basic archivés (grâce à la source de noshell) : on crée un programme temporaire avec un nom unique, puis on y copie les données archivées avant de l'exécuter, mais je ne sais pas pourquoi ça bug encore (le programme temporaire semble bien créé) :/
hook.inc
zshell_hook:
	.db $83 ; used by os for hook safety check (add a,e can be used too)
	or a
	jr z,zshell_hook_start  ; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
	xor a
	ret

zshell_hook_start:
	ld hl,(nextparsebyte)	; what's on homescreen
	ld a,(hl)
	cp tprog
	jr nz,zshell_hook_return_z	; if it don't start with "prgm", we don't care
	rst rmov9toop1	; we put "prgmANYTHING" into op1
	ld hl,op1
	ld (hl),progobj	; then replace "prgm" token with the program type (progobj)
	bcall(_chkfindsym)	; so we can find its datas
	ex de,hl	; cause of _getbytepaged parameters
	bjumpc(_errundefined)	; if not found, throw an "undefined error"
	call get_byte	; else start to read it
	ld e,a
	call get_byte	; first two bytes are length of the program
	jr c,zshell_hook_return_nz	; if empty, don't parse
	ld d,a
	dec de
	dec de	; we don't count the next two bytes (t2bytetok/texttok+tasmcmp/tasm84ccmp) into the program length
	ld (program_length_count),de
	call get_byte	; skip t2bytetok/texttok
	call get_byte
	cp tasmprgm
	jr z,zshell_hook_handle_unsquished_asm_prgm
	cp tasmcmp
	jr z,zshell_hook_execute_compiled_asm_prgm
	;cp tzshellprgm
	;ld hl,zshell_txt
	;jr z,zshell_hook_execute_zshell_prgm
	set allowprogtokens,(iy+newdispf)	; allow programming tokens to be parsed in TI-Basic programs
	ld a,b
	or a
	ret z	; the TI-Basic program is unarchived, so let the parser handle it
	push hl
	push bc
	ld hl,zshell_error_handler
	call app_push_errorh
	call allocate_temp_prog	; check if there is other temp progs, then put an unique name into op1
	ld hl,(program_length_count)
	push af
	bcall(_createprotprog)
	pop af
	pop bc
	pop hl
	bjumpc(_errmemory)
	push hl
	push bc
	inc de
	inc de	; de = data section (skip the length bytes)
	xor a
	ld (parse_var),a
	ld (parse_var+1),a
	pop bc
	pop hl
	ld a,b
	ld bc,(program_length_count)
	bcall(_flashtoram)	; copy the datas from the archived TI-Basic prog to the temp prog
	bcall(_op4toop1)	; op1 was copied into op4 then destroyed by _createprotprog
	bcall(_parseinp)
	call delete_temp_prog
	call app_pop_errorh

zshell_hook_return_nz:
	or $80  ; reset zero flag, the parser can't continue to parse the variable
	ret

zshell_hook_handle_unsquished_asm_prgm:
	ld a,b
	or a
	jr z,zshell_hook_execute_unsquished_asm_prgm
	; todo : unarchive prgm

zshell_hook_execute_unsquished_asm_prgm:
	bcall(_executeprgm)	; can only run unarchived prgm
	or $80
	ret

zshell_hook_execute_compiled_asm_prgm:
	call zshell_hook_program_start_begin

zshell_hook_load:
	push hl	; how many bytes left to copy
	ld hl,(progaddress)	; copy the program to the gbuf
	push bc	; hl = program data start
	ld de,gbuf	; bc = # bytes to copy
	ldir	; copy bc bytes
	pop de	; # bytes copied
	ld (progaddress),hl	; save new program data pointer
	; delete bc bytes from the program
	or a	; hl = start of prog data+768
	sbc hl,de
	push de	; de = # of bytes copied
	bcall(_delmem)	; hl = where to delete from, de = # bytes
	pop hl	; hl = # bytes deleted
	; insert HL bytes to $9d95
	ld de,(progstartlocation)	; progstart ($9d95)
	push hl	; hl = # bytes deleted
	bcall(_insertmem)	; insert hl bytes to $9d95
	pop bc	; bc = bytes deleted
	ld hl,(progstartlocation)	; ex de,hl ???
	add hl,bc
	ld (progstartlocation),hl
	; copy gbuf to $9d95
	ld hl,gbuf	; de = location where memory was inserted ($9d95+XXXX)
	ldir	; copy # of bytes deleted from gbuf to progstart
	pop hl	; how many bytes are left to copy
	ld a,l
	or h
	jr nz,zshell_hook_load_loop
	call progstart	; run the program
	; now rewrite the data back into the program
	; ...not done yet...

zshell_hook_program_start_begin:
	ld a,b
	or a
	call nz,zshell_hook_unarchive
	; hl = first byte of program data
	; de = program length-2
	ld bc,progstart
	ld (progstartlocation),bc
	ld (progaddress),hl
	ex de,hl	; hl = length

zshell_hook_load_loop:
	ld bc,768	; check if there are <768 bytes left to copy (gbuf length)
	or a
	sbc hl,bc	; subtract 768 from the program size
	ret nc	; if no carry, there are still more than 768 bytes to copy
	add hl,bc
	ld b,h
	ld c,l
	ld hl,$0000
	ret

zshell_hook_unarchive:
	; push hl
	; ld hl,(program_length_count)
	; push bc
	; bcall(_enoughmem)
	; pop bc
	; pop hl
	; ld a,e_memory
	; bjumpc(_jerror)
	; ld a,b
	; ld de,progstart
	; ld bc,(program_length_count)
	; inc bc
	; inc bc	; we have to count t2bytetok/tprog this time
	; bcall(_flashtoram)
	; ret

zshell_error_handler:
	res 7,a	; ???
	push af
	call delete_all_temp_progs
	pop af
	bjump(_jerror)

allocate_temp_prog:	; fail is carry flag is set
	ld hl,temp_prog_name_str
	rst rmov9toop1

find_then_allocate_temp_prog:
	bcall(_chkfindsym)
	ccf	; inverse the carry flag
	ret nc	; ret if program not found (we can name it using the ID at op1+2)
	ld a,(op1+2)
	dec a
	scf	; set carry flag in case we ret (meaning we can't allocate the temp prog, but there's a few chance for that)
	ret z	; ret if a = 0
	ld (op1+2),a
	jr find_then_allocate_temp_prog

delete_temp_prog:
	ld hl,temp_prog_name_str
	rst rmov9toop1
	ld a,1
	ld (op1+2),a	; we start by checking the temp prog with the ID = 01

find_then_delete_temp_prog:
	bcall(_chkfindsym)
	jr nc,delete_temp_prog_ok	; if the temp prog is found, delete it
	ld a,(op1+2)	; else we increase the prog id
	inc a
	scf	; if we're over $ff, there's no more temp prog
	ret z
	ld (op1+2),a
	jr find_then_delete_temp_prog

delete_temp_prog_ok:
	bcall(_delvararc)
	xor a
	ret

delete_all_temp_progs:
	call delete_temp_prog
	ret c
	jr delete_all_temp_progs

temp_prog_name_str:
	.db protprogobj,$01,$ff,0

zSHELL.zip

J'ai aussi du mal à comprendre le handler des erreurs, et notamment pourquoi est-ce qu'il faut faire un "res 7,a" ?
chickendude (./26) :
On pourrait peut-être écire un autre hook pour le token prgm, quand on exécute ce token notre hook cherchera le programme et le desarchiver s'il est dans l'archive avant de le faire courir.

Il me semble que noshell/zstart font ça (d'où l'utilisation de programmes temporaires avec un ID unique dans le nom), il faudra que je vérifie. On aura peut être même pas besoin de créer un nouvel hook.
Posté le 01/03/2013 à 21:02 Membre depuis le 15/03/2005, 3470 messages
J'ai un peu "débuggé" la partie du code qui sert à désarchiver les programmes TI-Basic (juste au dessus du label zshell_hook_return_nz), mais je ne sais pas pourquoi le programme temporaire se remplit de n'importe quoi (alors que les paramètres de _flastoram semblent correctes) :/
hook.inc
zshell_hook:
	.db $83 ; used by os for hook safety check (add a,e can be used too)
	di
	or a
	jr z,zshell_hook_start  ; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
	xor a
	ret

zshell_hook_start:
	ld hl,(nextparsebyte)	; what's on homescreen
	ld a,(hl)
	cp tprog
	jr nz,zshell_hook_return_z	; if it don't start with "prgm", we don't care
	rst rmov9toop1	; we put "prgmANYTHING" into op1
	ld hl,op1
	ld (hl),progobj	; then replace "prgm" token with the program type (progobj)
	bcall(_chkfindsym)	; so we can find its datas
	ex de,hl	; cause of _getbytepaged parameters
	bjumpc(_errundefined)	; if not found, throw an "undefined error"
	call get_byte	; else start to read it
	ld e,a
	call get_byte	; first two bytes are length of the program
	jp c,zshell_hook_return_nz	; if empty, don't parse
	ld d,a
	dec de
	dec de	; we don't count the next two bytes (t2bytetok/texttok+tasmcmp/tasm84ccmp) into the program length
	ld (program_length_count),de
	call get_byte	; skip t2bytetok/texttok
	call get_byte
	cp tasmprgm
	jp z,zshell_hook_handle_unsquished_asm_prgm
	cp tasmcmp
	jp z,zshell_hook_execute_compiled_asm_prgm
	;cp tzshellprgm
	;ld hl,zshell_txt
	;jr z,zshell_hook_execute_zshell_prgm
	set allowprogtokens,(iy+newdispf)	; allow programming tokens to be parsed in TI-Basic programs
	ld a,b
	or a
	ret z	; the TI-Basic program is unarchived, so let the parser handle it
	exx	; app_push_errorh uses the stack, so we use shadow registers to hold hl and bc
	ld hl,zshell_error_handler
	call app_push_errorh
	call allocate_temp_prog	; check if there is other temp progs, then put an unique name into op1
	ld hl,(program_length_count)
	bcallnc(_createprog)	; bcallnc(_createprotprog)
	bjumpc(_errmemory)
	inc de
	inc de	; de = data section (skip the length bytes)
	xor a
	ld (parse_var),a	; clear the type byte of the currently executed TI-Basic program
	ld (parse_var+1),a	; and the first letter of its name ?
	push de
	exx
	pop de
	ld a,b
	ld bc,(program_length_count)
	bcall(_flashtoram)	; copy the datas from the archived TI-Basic prog to the temp prog
	;bcall(_op4toop1)	; op1 was copied into op4 then destroyed by _createprotprog
	;bcall(_parseinp)
	;call delete_temp_prog
	call app_pop_errorh

zshell_hook_return_nz:
	or $80  ; reset zero flag, the parser can't continue to parse the variable
	ret

zshell_hook_handle_unsquished_asm_prgm:
	ld a,b
	or a
	jr z,zshell_hook_execute_unsquished_asm_prgm
	; todo : unarchive prgm

zshell_hook_execute_unsquished_asm_prgm:
	bcall(_executeprgm)	; can only run unarchived prgm
	or $80
	ret

zshell_hook_execute_compiled_asm_prgm:
	call zshell_hook_program_start_begin

zshell_hook_load:
	push hl	; how many bytes left to copy
	ld hl,(progaddress)	; copy the program to the gbuf
	push bc	; hl = program data start
	ld de,gbuf	; bc = # bytes to copy
	ldir	; copy bc bytes
	pop de	; # bytes copied
	ld (progaddress),hl	; save new program data pointer
	; delete bc bytes from the program
	or a	; hl = start of prog data+768
	sbc hl,de
	push de	; de = # of bytes copied
	bcall(_delmem)	; hl = where to delete from, de = # bytes
	pop hl	; hl = # bytes deleted
	; insert HL bytes to $9d95
	ld de,(progstartlocation)	; progstart ($9d95)
	push hl	; hl = # bytes deleted
	bcall(_insertmem)	; insert hl bytes to $9d95
	pop bc	; bc = bytes deleted
	ld hl,(progstartlocation)	; ex de,hl ???
	add hl,bc
	ld (progstartlocation),hl
	; copy gbuf to $9d95
	ld hl,gbuf	; de = location where memory was inserted ($9d95+XXXX)
	ldir	; copy # of bytes deleted from gbuf to progstart
	pop hl	; how many bytes are left to copy
	ld a,l
	or h
	jr nz,zshell_hook_load_loop
	call progstart	; run the program
	; now rewrite the data back into the program
	; ...not done yet...

zshell_hook_program_start_begin:
	ld a,b
	or a
	call nz,zshell_hook_unarchive
	; hl = first byte of program data
	; de = program length-2
	ld bc,progstart
	ld (progstartlocation),bc
	ld (progaddress),hl
	ex de,hl	; hl = length

zshell_hook_load_loop:
	ld bc,768	; check if there are <768 bytes left to copy (gbuf length)
	or a
	sbc hl,bc	; subtract 768 from the program size
	ret nc	; if no carry, there are still more than 768 bytes to copy
	add hl,bc
	ld b,h
	ld c,l
	ld hl,$0000
	ret

zshell_hook_unarchive:
	; push hl
	; ld hl,(program_length_count)
	; push bc
	; bcall(_enoughmem)
	; pop bc
	; pop hl
	; ld a,e_memory
	; bjumpc(_jerror)
	; ld a,b
	; ld de,progstart
	; ld bc,(program_length_count)
	; inc bc
	; inc bc	; we have to count t2bytetok/tprog this time
	; bcall(_flashtoram)
	ret

zshell_error_handler:
	res 7,a	; ???
	push af
	call delete_all_temp_progs
	pop af
	bjump(_jerror)

allocate_temp_prog:	; fail is carry flag is set
	ld hl,temp_prog_name_str
	rst rmov9toop1

find_then_allocate_temp_prog:
	bcall(_chkfindsym)
	ccf	; inverse the carry flag
	ret nc	; ret if program not found (we can name it using the ID at op1+2)
	ld a,(op1+2)
	dec a
	scf	; set carry flag in case we ret (meaning we can't allocate the temp prog, but there's a few chance for that)
	ret z	; ret if a = 0
	ld (op1+2),a
	jr find_then_allocate_temp_prog

delete_temp_prog:
	ld hl,temp_prog_name_str
	rst rmov9toop1
	ld a,1
	ld (op1+2),a	; we start by checking the temp prog with the ID = 01

find_then_delete_temp_prog:
	bcall(_chkfindsym)
	jr nc,delete_temp_prog_ok	; if the temp prog is found, delete it
	ld a,(op1+2)	; else we increase the prog id
	inc a
	scf	; if we're over $ff, there's no more temp prog
	ret z
	ld (op1+2),a
	jr find_then_delete_temp_prog

delete_temp_prog_ok:
	bcall(_delvararc)
	xor a
	ret

delete_all_temp_progs:
	call delete_temp_prog
	ret c
	jr delete_all_temp_progs

temp_prog_name_str:
	;.db protprogobj,$01,$ff,$00
	.db progobj,"A",$ff,0
Posté le 02/03/2013 à 13:50 Membre depuis le 15/03/2005, 3470 messages
Bon alors je crois savoir d'où viens le problème, mais je n'arrive pas à le résoudre... D'abord il y avait un bug dans la routine get_byte : avec _getbytepaged, b était copié à l'adresse contenue dans hl, et non pas dans le registre lui même :
get_byte:
	push de
	push hl ; hl = data to read
	ld a,b	; b = flash page #, or 0 if in ram
	or a
	call nz,get_byte_paged
	push hl
	ld hl,(program_length)
	dec (hl)	; just to make sure we're not reading out of the program
	ld a,(hl)
	or a
	pop hl
	ld a,(hl)
	pop hl
	pop de
	inc hl
	ret nz
	scf	; c is set if we're out of the program
	ret

get_byte_paged:
	push bc
	ld a,b
	bcall(_getbytepaged)
	ld h,0
	ld l,b
	pop bc
	ret

Ensuite le problème vient de la lecture des deux octets de la taille du programme lorsqu'il est archivé : _chkfindsym renvoi bien l'adresse des données du programme dans de (qu'on swap avec hl), et _getbytepaged y accède bien, sauf que ça ne semble pas être la taille du programme...

Dans la source de noshell il y a :
; ce code est exécuté si le prog est archivé, après un _chkfindsym et ex de,hl
	ld de,9
	call BHL_plus_DE
	call getDataByte
	ld c,a
$$:	call getDataByte
	dec c
	jr nz,$B
readProgramData:
	call getDataByte
	ld e,a
	call getDataByte
	ld d,a
	ld (wProgSize),de

Donc hl ne pointe pas vers les données du programme (ce qui est le cas si le prog est dans la ram), mais vers l'header ? Le wikiti ne dit rien là dessus...

Si c'est le cas donc, il saute les 9 premiers octets (type+nom), mais pourquoi ensuite sauter x fois des données avant d'arriver à la taille du prog ?! confus
hook.inc
zshell_hook:
	.db $83 ; used by os for hook safety check (add a,e can be used too)
	di
	or a
	jr z,zshell_hook_start  ; we just want to handle prgm, not TI-Basic functions

zshell_hook_return_z:
	xor a
	ret

zshell_hook_start:
	ld hl,$0002
	ld (program_length),hl	; to be able to read at least the length bytes
	ld hl,(nextparsebyte)	; what's on homescreen
	ld a,(hl)
	cp tprog
	jr nz,zshell_hook_return_z	; if it don't start with "prgm", we don't care
	rst rmov9toop1	; we put "prgmANYTHING" into op1
	ld hl,op1
	ld (hl),progobj	; then replace "prgm" token with the program type (progobj)
	bcall(_chkfindsym)	; so we can find its datas
	bjumpc(_errundefined)	; if not found, throw an "undefined error"
	ex de,hl	; cause of _getbytepaged parameters
	call get_byte	; else start to read it
	ld e,a
	call get_byte	; first two bytes are length of the program
	jp c,zshell_hook_return_nz	; if empty, don't parse
	ld d,a
	ld (program_length),de
	call get_byte	; skip t2bytetok/texttok
	call get_byte
	cp tasmprgm
	jp z,zshell_hook_handle_unsquished_asm_prgm
	cp tasmcmp
	jp z,zshell_hook_execute_compiled_asm_prgm
	;cp tzshellprgm
	;ld hl,zshell_txt
	;jr z,zshell_hook_execute_zshell_prgm
	set allowprogtokens,(iy+newdispf)	; allow programming tokens to be parsed in TI-Basic programs
	ld a,b
	or a
	ret z	; the TI-Basic program is unarchived, so let the parser handle it
	exx	; app_push_errorh uses the stack, so we use shadow registers to hold hl and bc
	ld hl,zshell_error_handler
	call app_push_errorh
	call allocate_temp_prog	; check if there is other temp progs, then put an unique name into op1
	ld hl,(program_length)
	bcallnc(_createprog)	; bcallnc(_createprotprog)
	bjumpc(_errmemory)
	inc de
	inc de	; de = data section (skip the length bytes)
	xor a
	ld (parse_var),a	; clear the type byte of the currently executed TI-Basic program
	ld (parse_var+1),a	; and the first letter of its name ?
	push de
	exx
	pop de
	ld a,b
	ld bc,(program_length)
	bcall(_flashtoram)	; copy the datas from the archived TI-Basic prog to the temp prog
	;bcall(_op4toop1)	; op1 was copied into op4 then destroyed by _createprotprog
	;bcall(_parseinp)
	;call delete_temp_prog
	call app_pop_errorh

zshell_hook_return_nz:
	or $80  ; reset zero flag, the parser can't continue to parse the variable
	ret

zshell_hook_handle_unsquished_asm_prgm:
	ld a,b
	or a
	jr z,zshell_hook_execute_unsquished_asm_prgm
	; todo : unarchive prgm

zshell_hook_execute_unsquished_asm_prgm:
	bcall(_executeprgm)	; can only run unarchived prgm
	or $80
	ret

zshell_hook_execute_compiled_asm_prgm:
	call zshell_hook_program_start_begin

zshell_hook_load:
	push hl	; how many bytes left to copy
	ld hl,(progaddress)	; copy the program to the gbuf
	push bc	; hl = program data start
	ld de,gbuf	; bc = # bytes to copy
	ldir	; copy bc bytes
	pop de	; # bytes copied
	ld (progaddress),hl	; save new program data pointer
	; delete bc bytes from the program
	or a	; hl = start of prog data+768
	sbc hl,de
	push de	; de = # of bytes copied
	bcall(_delmem)	; hl = where to delete from, de = # bytes
	pop hl	; hl = # bytes deleted
	; insert HL bytes to $9d95
	ld de,(progstartlocation)	; progstart ($9d95)
	push hl	; hl = # bytes deleted
	bcall(_insertmem)	; insert hl bytes to $9d95
	pop bc	; bc = bytes deleted
	ld hl,(progstartlocation)	; ex de,hl ???
	add hl,bc
	ld (progstartlocation),hl
	; copy gbuf to $9d95
	ld hl,gbuf	; de = location where memory was inserted ($9d95+XXXX)
	ldir	; copy # of bytes deleted from gbuf to progstart
	pop hl	; how many bytes are left to copy
	ld a,l
	or h
	jr nz,zshell_hook_load_loop
	call progstart	; run the program
	; now rewrite the data back into the program
	; ...not done yet...

zshell_hook_program_start_begin:
	ld a,b
	or a
	call nz,zshell_hook_unarchive
	; hl = first byte of program data
	; de = program length-2
	ld bc,progstart
	ld (progstartlocation),bc
	ld (progaddress),hl
	ex de,hl	; hl = length

zshell_hook_load_loop:
	ld bc,768	; check if there are <768 bytes left to copy (gbuf length)
	or a
	sbc hl,bc	; subtract 768 from the program size
	ret nc	; if no carry, there are still more than 768 bytes to copy
	add hl,bc
	ld b,h
	ld c,l
	ld hl,$0000
	ret

zshell_hook_unarchive:
	; push hl
	; ld hl,(program_length)
	; push bc
	; bcall(_enoughmem)
	; pop bc
	; pop hl
	; ld a,e_memory
	; bjumpc(_jerror)
	; ld a,b
	; ld de,progstart
	; ld bc,(program_length)
	; inc bc
	; inc bc	; we have to count t2bytetok/tprog this time
	; bcall(_flashtoram)
	ret

zshell_error_handler:
	res 7,a	; ???
	push af
	call delete_all_temp_progs
	pop af
	bjump(_jerror)

allocate_temp_prog:	; fail is carry flag is set
	ld hl,temp_prog_name_str
	rst rmov9toop1

check_then_allocate_temp_prog:
	bcall(_chkfindsym)
	ccf	; inverse the carry flag
	ret nc	; ret if program not found (we can name it using the ID at op1+2)
	ld a,(op1+2)
	dec a
	scf	; set carry flag in case we ret (meaning we can't allocate the temp prog, but there's a few chance for that)
	ret z	; ret if a = 0
	ld (op1+2),a
	jr check_then_allocate_temp_prog

delete_temp_prog:
	ld hl,temp_prog_name_str
	rst rmov9toop1
	ld a,1
	ld (op1+2),a	; we start by checking the temp prog with the ID = 01

find_then_delete_temp_prog:
	bcall(_chkfindsym)
	jr nc,delete_temp_prog_ok	; if the temp prog is found, delete it
	ld a,(op1+2)	; else we increase the prog id
	inc a
	scf	; if we're over $ff, there's no more temp prog
	ret z
	ld (op1+2),a
	jr find_then_delete_temp_prog

delete_temp_prog_ok:
	bcall(_delvararc)
	xor a
	ret

delete_all_temp_progs:
	call delete_temp_prog
	ret c
	jr delete_all_temp_progs

temp_prog_name_str:
	;.db protprogobj,$01,$ff,$00
	.db progobj,"A",$ff,0
Posté le 02/03/2013 à 14:52 Membre depuis le 03/06/2011, 520 messages
http://www.omnimaga.org/index.php?topic=6989.msg264864#msg264864

[nombre d'octets: nom]
Flash archive variable format:

[1:status flag] [2:archived variable total size] [1tonguerog type] [1:T2] [1:version] [1tongueage] [2:address] [1:chars in name] [name length:name] [2:size of program] [size of programtonguerogram data]
So, I have these mentally grouped. In this order, it's 3+3+3+1+nameLength+2 and then the last +2 is for BB 6D. Really, the archive is just a vat entry with those extra three bytes out front.


La taille du programme n'est pas toujours la même, donc il faut lire la taille du nom et l'ajouter pour arriver à la taille du jeu/les données smile