CODING

Dans cette rubrique vous trouverez quelques-unes de mes prods sur Amstrad CPC. Le CPC est une machine des années 80 qui possédait au mieux 128Ko de RAM, ne pouvait en temps normal afficher au maximum que 16 couleurs maximum à l'écran parmis une palette de 26 couleurs... A l'époque, pas de disc dur ni de lecteur CD, tout ce passait sur disquette 3" ou sur K7. Mais sur ces machines c'est développé le démomaking: l'art de repousser au maximum les possibilité d'une machine dont le système est figé. Hors de question d'ajouter à la machine des extensions pour l'accélérer ou autre. Une démo ce doit de fonctionner sur la machine de base. C'est pour cette raison que nous ne pouvons pas parler de démo sur PC. Une démo est en fait un programme complètement inutil, comme un tableau que l'on regarde, juste pour le plaisir des yeux et des oreilles. Pour les personnes connaissants les machines, c'est aussi l'occasion de s'impressionner. Voici donc quelques-unes de mes prods, certes pas les meilleurs... Vous ne trouverez pas de fichiers téléchargeables ici étant donné que je suis contre l'utilisation d'émulateurs.

FANZINES:

HELPFANZ I

HELPFANZ II

Voici la ZM2000. Sortie justement pour commémorer le meeting du même nom. Cette production est en fait la 1ère démo que j'ai sorti. Au programme: FULLSCREEN; une soixantaines de couleurs simultanées à l'écran; une musique de Shap et quelques heures de travail. Cette démo tourne sur CPC+ et n'apporte hormis la rupture soft de sprites hard, rien de nouveau. Les amateurs reconnaitrons le gfx qui n'est autre que la pochette de l'album live "LIVE AFTER DEATH" du groupe IRON MAIDEN.
Voici "WALKING ON A SCROLL" que de sombres crétins ont cru bon de renommer IRON2. Cette démo est ma deuxième production. Celle-ci a représenté à l'époque quelques heures de travail pour le code. Vous pourrez y voir des rasters; des splits rasters; un scroll text hard illisible; de la ligne à ligne; un perso qui marche et, si vous cherchez un peu, une cheat part (partie cachée). Rien de révolutionnaire ici.
Voici la Cheat part de "Walking on a scroll".
Voici la "BLACK SABBATH", la 1ère vrai démo sur CPC+ de l'histoire. Celle-ci apporte de vrai nouvelles choses: Les splits rasters les plus petits (2 NOPS); la 1ère rupture hard de sprites hard. Cette démo à été codée à l'occasion d'une amstrad expo et exprimait déja mon raz le bol pour la scène... Ce qui n'a pas été en s'améliorant. (Les couleurs du screenshot ne sont pas réaliste).
La première OFE demo, codée devant tout le monde pendant un ZM... Personne ne s'en est rendu compte. Au final cette petite démo a fait l'effet d'une bombe. Tout le monde cherchait qui était OFE. Il existe un cheat mode tout bête en modifiant le lanceur basic de quelques lettres ;)
Dernière démo officiellement sortie, la "croco démo" fait partie d'une compilation de démos commémorants le Croco chanel meeting 3. Elle sera aussi ma dernière prod avant longtemps. Cette démo n'apporte rien de nouveau. Elle contient 3 plans de paralaxes rasters qui bougent devant une espèce de plasma.
OFE'S MODE: La 3ème OFE demo... Premier essais de rupture verticale... La transiton CRTC du haut est loin d'être parfaite, je n'avais pas encore tout compris !!!
Voici GRAPH'OS aussi appelé GOS, mon logiciel de dessin. C'est en fait le 1er logiciel de dessin en Fullscreen. GOS ne tourne que sur CPC+ et utilise donc la palette des 4096 couleurs. C'est certainement le meilleur logiciel de dessin sur CPC, bien que OCP soit trés bon (mais l'ergonomie n'y est pas). GOS est toujours en évolution et ne sera sans doute jamais vraiment fini. Il existe uniquement en version ROM.

Bien, passons maintenant à la technique... Vous trouverez ici une initiation au code assembleur. Une bonne partie peut etre utilisée sur d'autres machine que le CPC puisqu'il s'agit de code Z80A. Ainsi, les utilisateurs de SPECTRUM entre autre pourrons pourquoi pas s'initier ici. Seul les parties parlants de Hardware ne seront pas appliquables sur leur belle machine. Mais, attention, je ne compte pas vous apprendre ici l'arithmétique binaire hexadécimale ou autre, de toute façon, si vous ne savez pas ce que c'est, vous trouverez suffisement de doc sur le net pour ça. Pour les utilisateurs de CPC/+, comprenez que je tourne ces "cours" plus vers la démo qu'autre chose. Cette décision est simple à expliquer: la démo permet de connaitre la machine par coeur. Ainsi, en devenant démomaker, vous pourrez ensuite décider de coder soit des démos, soit des jeux ou encore, des logiciels... à vous de voir... Bien, attaquons les choses sérieuses:

Quelques connaissances du CPC :

Le CPC est construit comme beaucoup de machines de son époque, sur la base du processeur Z80A de Zilog. Ce qui fait du CPC un CPC, c’est le Gate-Array qui gère la palette, les modes graphiques ainsi que les connexions BANK / ROM / RAM. L’écran quant à lui est géré par le très connu CRTC 6845. Le CRTC ayant été changé d’années en années, celui-ci est la principale cause d’incompatibilité entre CPCs. Pour le son, comme sur Atari ST ou ZX Spectrum, il s’agit d’un AY 2149. Enfin, un autre composant : le PPI a été ajouté pour la gestion des ports I/O tels que le clavier… Sur CPC+, le Gate-Array ; le CRTC ainsi que le PPI sont émulés (C’est aussi le cas sur CRTC 4 mais à une échelle moindre.).

Généralités graphiques :

A la base, le CPC dispose de 4 modes graphiques. Ceux-ci ont pour différences, le nombre de couleurs affichables et la résolution. Quelque soit le mode, l’écran de base (sans modifications) est composé de 80 octets de large pour 200 lignes de haut. Les différences entre les modes sont :

 

Mode graphique
Résolution (pixels)
Nombre d’encres
0
160*200
16
1
320*200
4
2
640*200
2
3
160*200
4

Qu’est-ce qu’un octet ?

Pour comprendre l’octet, il faut le regarder en binaire : 1 octet est égal à 8 bits correspondants chacun à une valeur tel que :

bit
7
6
5
4
3
2
1
0
octet
0/1
0/1
0/1
0/1
0/1
0/1
0/1
0/1
valeur 128 64 32 16 8 4 2 1

Prenons un exemple, nous voulons que notre octet ait pour valeur 186 :

bit
7
6
5
4
3
2
1
0
octet
1
0
1
1
1
0
1
0
valeur 128 64 32 16 8 4 2 1

128+32+16+8+2=186

En mode 2, nous pouvons visualiser l’octet car 1 bit mis à 1 est égal à 1 pixel d’encre 1 sur l’écran. Si 1 bit est à 0, c’est donc un pixel d’encre 0 qui est affiché…

Ex : POKE &C000,&X10111010 (en BASIC)

Ou en assembleur:

LD A,%10111010
LD (#C000),A

Affichera : X XXX X (X étant un pixel)

Attention à ne pas confondre Bit et Byte. Byte en anglais signifie : Octet. 1 Mb (méga byte) n’est donc pas 1 méga de Bits mais en fait 1 méga octet…

Notions sur le Z80A :

Le Z80A, processeur central du CPC décide seul de la vitesse de la machine qui est de 3,33 MHz. Mais il décide surtout de son langage. Outre le fait de contenir le langage, le Z80A permet de décider du mode d’interruption (nous reviendrons sur ce point plus tard). Voici la liste des instructions du Z80 :

Instructions
opcodes
Cycles NOP
ADC A,reg

#86,#1 rrr
#8E
CE,data
#DD,#8E,disp
#ED,#01,#xxA
#FD,#8E,disp
#09
#19
#29
#39
#8 0rrr
#86
#C6,data
#DD,#00xx9
#DD,#86,disp
#FD,#00xx9
#FD,#86,disp
#A0rrr
#A6
#DD,#A6,disp
#E6,data
#DD,#A6,disp
#CB,%01bbbrrr
#CB,%01bbb110
#DD,#CB,disp01bbb110
#FD,#CB,disp01bbb110
#C4,ll,hh
#CC,ll,hh
#CD,ll,hh
#D4,ll,hh
#DC,ll,hh
#E4,ll,hh
#EC,ll,hh
#F4,ll,hh
#FC,ll,hh
#3f
#B 1rrr
#BE
#DD,#BE,disp
#FD,#BE,disp
#FE,data
#ED,#A9
#ED,#B9
#ED,#A1
#ED,#B1
#2F
#27
#05
#0B
#0D
#15
#1B
#1D
#25
#2B
#2D
#35
# 3B
#3D
#DD,#2B
#DD,#35,disp
#FD,#2B
#FD,#35,disp
#F3
#10,disp-2
#FB
#08
#DD,#E3
#E3
#EB
#FD,#E3
#D9
#76
#ED,%010nn110
#DB,data
#ED,%01ddd000
#03
#04
#0C
#13
#14
#1C
#23
#24
#2C
#33
#34
#3C
#DD,#23
#DD,#34,disp
#FD,#23
#FD,#34,disp
#ED,#AA
#ED,#8A
#ED,#A2
#ED,#B2
#C2,ll,hh
#C3,ll,hh
#CA,ll,hh
#D2,ll,hh
#DA,ll,hh
#DD,E9
#E2,ll,hh
#E9
#EA,ll,hh
#F2,ll,hh
#FA,ll,hh
#FD,#E9
#18,disp-2
#20,disp-2
#28,disp-2
#30,disp-2
#38,disp-2
#01,ll,hh
#02
#06,data
#0A
#0E,data
#11,ll,hh
#12
#16,data
#1A
#1E,data
#21,ll,hh
#22,ll,hh
#26,data
#2A,ll,hh
#2E
#31,ll,hh
#32,ll,hh
#36,data
#3A,ll,hh
#3E,yy
#4%0sss
#46
#4%1sss
#4E
#5%0sss
#56
#5%1sss
#5E
#6%0sss
#66
#6%1sss
#6E
#7%0sss?
#7%0sss?
#7E
#DD,#21,ll,hh
#DD,#22,ll,hh
#DD,#2A,ll,hh
#DD,#36,disp,data
#DD,%01ddd110,disp
#DD,#7%0sss,disp
#DD,#F9
#ED,01xx3,ll,hh
#ED,#47
#ED,01xxB,ll,hh
#ED,#4F
#ED,#57
#ED,#5F
#F9
#FD,#21,ll,hh
#FD,#22,ll,hh
#FD,#2A,ll,hh
#FD,#36,disp,data
#FD,%01ddd110,disp
#FD,#7%0sss,disp
#FD,#F9
#ED,#A8
#ED,#B8
#ED,#A0
#ED,#B0
#ED,#44
#00
#B%0rrr
#B6
#DD,#B6,disp
#F6,data
#FD,#B6,disp
#ED,#B8
#ED,#B3
#D3,data
#ED,%01sss001
#ED,#AB
#ED,#A3
#C1
#D1
#DD,#E1
#E1
#F1
#FD,#E1
#C5
#D5
#DD,#E5
#E5
#F5
#FD,#E5
#CB,%10bbbrrr
#CB,%10bbb110
#DD,#CB,disp,%10bbb110
#FD,#CB,disp,%10bbb110
#C0
#C8
#C9
#D0
#D8
#E0
#E8
#F0
#F8
#ED,#40
#ED,#45
#CB,100rrr
#CB,#16
#DD,#C8,disp,#16
#FD,#C8,disp,#16
#17
#CB,#0%0rrr
#CB,#06
#DD,#CB,disp,#06
#FD,#CB,disp,#06
#07
#ED,#6F
#CB,#1%1rrr
#CB,#1E
#DD,#C8,disp,#1E
#FD,#C8,disp,#1E
#1F
#CB,#0%1rrr
#CB,#0E
#DD,#CB,disp,#0E
#FD,#CB,disp,#0E
#0F
#ED,#67
#C7
#CF
#D7
#DF
#E7
#EF
#F7
#FF
#9%1rrr
#9E
#DD,#9E,disp
#DE,data
#ED,01xx2
#FD,#96,disp
#37
#CB,%11bbbrrr
#CB,%11bbb110
#DD,#CB,disp,%11bbb110
#FD,#CB,disp,%11bbb110
#CB,#2%0rrr
#DD,#CB,disp,#26
#FD,#CB,disp,#26
#CB,#2%1rrr
#CB,#2E
#DD,#CB,disp,#2E
#FD,#CB,disp,#2E
#CB,#3%1rrr
#CB,#3E
#DD,#CB,disp,#3E
#FD,#CB,disp,#3E
#9%0rrr
#96
#D6,data
#DD,#96,disp
#FD,#96,disp
#A%1rrr
#AE
#DD,#AE,disp
#EE,data
#FD,#AE,disp
ADC A,(HL)
ADC A,data
ADC A,(IX+disp)
ADC HL,rp
ADC A,(IY+disp)
ADD HL,BC
ADD HL,DE
ADD HL,HL
ADD HL,SP
ADD A,reg
ADD A,(HL)
ADD A,data
ADD IX,pp
ADD A,(IX+disp)
ADD IY,rr
ADD A,(IY+disp)
AND reg
AND (HL)
AND (IX+disp)
AND data
AND (IY+disp)
BIT b,reg
BIT b,(HL)
BIT b,(IX+disp)
BIT b,(IY+disp)
CALL NZ,adr
CALL Z,adr
CALL adr
CALL NC,adr
CALL C,adr
CALL PO,adr
CALL PE,adr
CALL P,adr
CALL M,adr
CCF
CP reg
CP (HL)
CP (IX+disp)
CP (IY+disp)
CP data
CPD
CPDR
CPI
CPIR
CPL
DAA
DEC B
DEC BC
DEC C
DEC D
DEC DE
DEC E
DEC H
DEC HL
DEC L
DEC (HL)
DEC SP
DEC A
DEC IX
DEC (IX+disp)
DEC IY
DEC (IY+disp)
DI
DJNZ adr
EI
EX AF,AF’
EX (SP),IX
EX (SP),HL
EX DE,HL
EX (SP),IY
EXX
HALT
IM 0/1/2
IN A,(port)
IN reg,(C)
INC BC
INC B
INC C
INC DE
INC D
INC E
INC HL
INC H
INC L
INC SP
INC (HL)
INC A
INC IX
INC (IX+disp)
6
INC IY
3
INC (IY+disp)
6
IND
5
INDR
INI
5
INIR
JP NZ,adr
3
JP adr
3
JP Z,adr
3
JP NC,adr
3
JP C,adr
3
JP (IX)
2
JP PO,adr
3
JP (HL)
1
JP PE,adr
3
JP P,adr
3
JP H,adr
3
JP (IY)
2
JR adr
3
JR NZ,adr
2
JR Z,adr
3
JR NC,adr
2
JR C,adr
3
LD BC,data
3
LD (BC),A
2
LD B,data
2
LD A,(BC)
2
LD C,data
2
LD DE,data
3
LD (DE),A
2
LD D,data
2
LD A,(DE)
2
LD E,data
2
LD HL,data
3
LD (adr),HL
5
LD H,data
2
LD HL,(adr)
5
LD L,data
2
LD SP,data
3
LD (adr),A
4
LD (HL),data
3
LD A,(adr)
4
LD A,data
2
LD B,reg
1
LD B,(HL)
2
LD C,reg
1
LD C,(HL)
2
LD D,reg
1
LD D,(HL)
2
LD E,reg
1
LD E,(HL)
2
LD H,reg
1
LD H,(HL)
2
LD L,reg
1
LD L,(HL)
2
LD (HL),reg
2
LD A,reg
1
LD A,(HL)
2
LD IX,data
4
LD (adr),IX
6
LD IX,(adr)
6
LD (IX+disp),data
6
LD reg,(IX+disp)
5
LD (IX+disp),reg
5
LD SP,IX
3
LD (adr),rp
6
LD I,A
3
LD rp,(adr)
6
LD R,A
3
LD A,I
3
LD A,R
3
LD SP,HL
2
LD IY,data
4
LD (adr),IY
6
LD IY,(adr)
6
LD (IY+disp),data
6
LD reg,(IY+disp)
5
LD (IY+disp),reg
5
LD SP,IY
3
LDD
5
LDDR
BC-1=0:5 ; BC<>0:6
LDI
5
LDIR
BC-1=0:5 ; BC<>0:6
NEG
2
NOP
1
OR reg
1
OR (HL)
2
OR (IX+disp)
5
OR data
2
OR (IY+disp)
5
OTDR
OTIR
OUT (adr),A
1
OUT (C),reg
4
OUTD
5
OUTI
5
POP BC
4
POP DE
4
POP IX
5
POP HL
4
POP AF
4
POP IY
5
PUSH BC
4
PUSH DE
4
PUSH IX
5
PUSH HL
4
PUSH AF
4
PUSH IY
5
RES b,reg
2
RES b,(HL)
4
RES b,(IX+disp)
7
RES b,(IY+disp)
7
RET NZ
2
RET Z
4
RET
3
RET NC
2
RET C
4
RET PO
RET PE
RET P
4
RET M
4
RETI
RETN
RL reg
2
RL (HL)
4
RL (IX+disp)
7
RL (IY+disp)
7
RLA
1
RLC reg
2
RLC (HL)
4
RLC (IX+disp)
7
RLC (IY+disp)
7
RLCA
1
RLD
5
RR reg
2
RR (HL)
4
RR (IX+disp)
7
RR (IY+disp)
7
RRA
1
RRC reg
2
RRC (HL)
4
RRC (IX+disp)
7
RRC (IY+disp)
7
RRCA
1
RRD
5
RST #00
4
RST #08
4
RST #10
4
RST #18
4
RST #20
4
RST #28
4
RST #30
4
RST #38
4
SBC A,reg
1
SBC A,(HL)
2
SBC A,(IX+disp)
5
SBC A,data
2
SBC HL,rp
4
SBC A,(IY+disp)
5
SCF
1
SET b,reg
2
SET b,(HL)
4
SET b,(IX+disp)
7
SET b,(IY+disp)
7
SLA reg
2
SLA (IX+disp)
7
SLA (IY+disp)
#FD,#CB,#disp,#26
7
SRA reg
#CB,#2(quartet 2:%1rrr)
SRA (HL)
#CB,#2E
SRA (IX+disp)
#DD,#CB,#disp,#2E
7
SRA (IY+disp)
#FD,#CB,#disp,#2E
7
SRC reg
#CB,#3(quartet 2:%1rrr)
2
SRL (HL)
#CB,#3E
4
SRL (IX+disp)
#DD,#CB,#disp,#3E
7
SRL (IY+disp)
#FD,#CB,#disp,#3E
7
SUB reg
#9(quartet 2:%0rrr)
1
SUB (HL)
#96
2
SUB data
#D6,#data
2
SUB (IX+disp)
#DD,#96,#disp
5
SUB (IY+disp)
#FD,#96,#disp
5
XOR reg
#A(quartet 2:%1rrr)
1
XOR (HL)
#AE
2
XOR (IX+disp)
#DD,#AE,#disp
5
XOR data
#EE,#data
2
XOR (IY+disp)
#FD,#AE,#disp
5

Non-documenté:

SLL A:CB,37
SLL H: CB,34
SLL L: CB,35
SLL D: CB,32
SLL E: CB,33
SLL B: CB,30
SLL C: CB,31
SLL (HL):CB,36
SLL (IX+dd):DD,CB,dd,36
SLL (IY+dd):FD,CB,dd,36

Complément: codage des registres:

100 : H
101 : L
010 : D
011 : E
000 : B
001 : C
111 : A
100 : IX
101 : IY

Qu’est-ce que sont les opcodes ?

Les instructions ne sont en fait que des mots incompréhensibles pour le Z80A. Ces mots ne sont compris que par l’assembleur. Celui-ci sert en fait de traducteur entre le Z80A et les instructions. Chaque instruction est en fait codée sur 1 ou plusieurs octets en mémoire. Ces octets sont appelés opcodes. Par exemple en mémoire, au lieu d’être écrit RET, il y aura d’inscrit #C9. En mémoire il y aura cependant des changements dans le stockage des adresses sur 16 bits (2 octets). Les adresses sont effectivement inversées en mémoire. Par exemple, regardons comment est codée en mémoire l’instruction : LD HL,#C040 . En mémoire nous trouverons : #21,#40,#C0. #21 correspond au LD HL, et #40,#C0 correspond à l’adresse #C040 !!!

Les cycles NOP :

Prenons l’instruction NOP qui prend 1 micro seconde pour être exécutée par le Z80A. C’est l’instruction la plus rapide. A partir de cette instruction ont été déterminés le nombre de cycles NOP que prennent les autres instructions. Par exemple, si une instruction prend 2 NOP, cela signifie qu’elle prend 2 fois plus de temps que l’instruction NOP, soit 2 micros secondes. L’intérêt de connaître le temps d’exécution des instructions est bien évidemment de pouvoir optimiser des routines pour qu’elles soient plus rapides. Cela peut aussi servir à ce synchroniser précisément sur le balayage écran.

Initiation à l’assembleur :

Utilisation des registres :

Le Z80A possède plusieurs registres qui sont :

A, F, H, L, D, E, B, C,R, IX, IY, SP,PC

Certains registres peuvent être couplés pour devenir des registres 16 bits. Ainsi, nous avons aussi :

HL, DE, BC, IX, IY, SP,PC.

Mais à quoi servent les registres ?

Prenons un exemple mathématique : X=3 … Les registres servent exactement à la même chose : à stocker des valeurs pour ensuite pouvoir les utiliser (additions, soustractions…). Mais certains registres ont une fonction spéciale :

F est le registre flag qui sert pour tester le résultat d’opérations. Ainsi, nous pouvons tester si le résultat d’une opération est 0 ou 255, s’il y a eut débordement d’un registre 8 bit… Voici le codage de ce registre :

Bit 7 : Flag S : si le résultat d’une opération donne une valeur positive, donc >127.

Bit 6 : Flag Z : mis si le résultat d’une opération est égal à 0.

Bit 4 : Flag H

Bit 2 : Flag P/V : P=parité ; V= overflow
Bit 1 : Flag N

Bit 0 : Flag C : flag carry : mis s’il y a eut débordement.

Pour tester le flag, il suffit d’utiliser les instructions de saut (CALL ou JP ou JR ainsi que RET). Par exemple, un JP Z,adr signifie que je programme fera un saut en adr si le flag Z a été mis. Aussi NZ signifie : non 0…

Le registre I est utile lors du passage en mode IM2. Il détermine le poids fort de l’adresse de saut.

SP est le registre de pile. La pile est utilisée pour le stockage de valeur. Pour l’expliquer, nous pouvons dire que la pile fonctionne comme une pile d’assiettes. La première valeur sauvegardée sera la dernière récupérée, tandis que la dernière sauvegardée étant sur le dessus de la pile sera la première récupérée… La pile ne fonctionne qu’avec des registres 16 bits. Ainsi, pour sauvegarder une valeur il suffit d’utiliser l’instruction PUSH reg et pour la récupérer : POP reg. Petit exemple :
LD HL,#4000 ;HL=#4000
LD DE,#2031 ;DE=#2031
LD BC,#8562 ;BC=#8562
PUSH HL ;sauve HL
PUSH DE ;sauve DE
PUSH BC ;sauve BC
Dans la pile nous avons donc sauvegardé les valeurs. Maintenant, si nous récupérons la dernière valeur (#8562 contenue à l’origine dans BC), nous tapons : POP reg. Ainsi nous pouvons le récupérer dans un autre registre que celui d’origine. Par exemple : DE
POP DE ;DE=#8562
POP BC ;BC=#2031
POP HL ;HL=#4000
Les valeurs stockées dans la pile y restent jusqu’à ce qu’elles soient récupérées… A chaque sauvegarde, SP est décrémenté de 2 octets et à chaque récupération de valeur dans la pile, SP est incrémenté de 2 octets (1 word).

Le registre R est le registre Refresh inutilisable sinon pour obtenir un nombre presque aléatoire.

Comme vu précédemment, nous pouvons charger un registre avec une valeur grâce à l’instruction LD reg,val. Mais ce n’est pas tout. Nous pouvons aussi le charger avec une valeur contenue à une certaine adresse : par exemple, nous voulons récupérer l’octet se trouvant à l’adresse #4000. Il suffira d’écrire :
LD A,(#4000)
Ainsi, quand un registre ou une valeur est mise entre parenthèse, cela signifie que l’on parle d’une adresse. Par exemple :
LD A,(DE)
Signifie : Mettre dans le registre A, la valeur contenue à l’adresse DE.
Par exemple si DE=#6000, la valeur contenue à l’adresse #6000 sera mise dans le registre A.

Les valeurs peuvent être échangées entre les registres 16 bits HL et DE avec l’instruction EX HL,DE.

Le registre 16 bits BC a une fonction spécifique dans le sens ou il est le seul permettant d’adresser un périphérique. Par exemple, si nous voulons adresser le Gate-Array : Celui-ci a pour entrée l’adresse #7F. Pour plus de précision, allez faire un toure du coté de la rubrique: "opérations I/O"

Pour l’adresser, nous écrirons donc :

LD BC,#7F00 ;BC=#7F00
OUT (C),C ;validation du port
LD A,84 ;A=84
OUT (C),A ;envois de la valeur

De même, nous pouvons aussi adresser le CRTC. Par exemple le registre 13 qui contrôle le déplacement au word de l’offset.

LD BC,#BC0D ;selection registre 13
OUT (C),C ;validation
LD BC,#BD00+val ;port d’écriture
OUT (C),C ;envois

Arithmétique simple :

Nous allons voir maintenant quelques instructions utiles pour effectuer des opérations sur les registres ou des tests…

Commençons par les instructions de rotations. Ces instructions ne fonctionnant que sur des registres 8 bits peuvent ce montrer très utils.

Les flèches représentent le mouvement des bits de l’octet.

RL reg:


RLC reg


RR reg


RRC reg

 

Il existe également les instructions RLA, RLCA, RRA, RRCA qui ne fonctionnent qu’avec l’accumulateur et ne prennent qu’1 NOP. Ces instructions ne mettent pas à jour d’autres flags que la carry.

Outre les rotations, il existe aussi des instructions de décalages. Pour SRA, le numéro 7 signifie que ce bit ne change pas.

Bon, raz le bol des schéma, ca prend trop de temps à faire sur cette sous machine de PC, alors hop, explications...

SLA reg: Décalage vers la gauche d'un reg. Le bit 7 va dans la carry tandis qu'un 0 est injecté dans le bit 0

SRA reg: Décalage vers la droite d'un reg. Le bit 7 ne change pas, la carry contient le bit 0.

SRL reg: Décalage vers la droite d'un reg. un 0 est injecté en bit 7, le bit 0 est dans la carry

SLL reg: le meme mais vers la gauche.:

Il y a 2 types de décalages : les arithmétiques (SLA, SRA) et les logiques (SLL, SRL). Les 1er sont signés (une valeur 8 bits est considérée comprise entre –128 et +127, le bit 7 étant le signe.) et le 2nd non signés (valeur de 0 à 255).

L’instruction SLL est dite non documentée et n’est donc pas comprise par la plupart des assembleurs. Les opcodes sont donc notés à la fin du tableau des instructions.

Passons maintenant à quelque chose de plus interessant: l'instruction LDIR:

Grace à cette instruction, nous allons pouvoir réaliser de nombreuses choses. Cette instruction est en fait une instruction de copie de blocs. Voici son mode de fonctionnement:

Pour toute copie, il faut une adresse de départ et une de destination. LDIR ce sert de HL comme adresse de départ et de DE comme DEstination. S'ajoute à cela le registre BC qui donnera la longueur en octets à copier.

Ex: LD HL,#4000:LD DE,#C000:LD BC,32:LDIR

Ainsi, 32 octets à partir de l'adresse #4000 seront copiés à l'adresse #C000.

Si vous ne voulez copier qu'un octet, utilisez LDI, qui fait la même chose mais pour une seul octet. L'avantage est qu'il est plus rapide que LDIR ( 5 NOPS au lieu de 6). De même, pour optimiser vos routines, il est préférable d'écrire 15 fois LDI que d'utiliser LDIR avec BC=15. Vous perdrez un peu de place en mémoire mais gagnerez en temps machine.

Concrètement, à chaque voici ce que fait LDIR:

l'octet à l'adresse HL est envoyé à l'adresse DE; HL et DE sont incrémenté (+1); BC est décrémenté (-1). Si BC<>0 alors on boucle. Sinon on stoppe.

Aprés un LDIR, HL=HL+BC; DE=DE+BC et BC=0. A n'est pas modifié.

A noter que chose stupide: lors d'un LDI, BC est décrémenté...

Il existe aussi 2 autres instruction de copies:

LDD et LDDR.

ce sont des équivalents respectifs à LDI et LDIR, sauf que:

HL et DE au lieu d'être incrémenté sont décrémentés. Les adresses à indiquer dans HL et DE sont donc celles de fin de bloc a copier...

 

Voyons maintenant l'interet du LDIR pour nous...

Si je vous dis que dans un premier temps (plus tard, vos connaissances ce faisant, vous changerez de méthode, soit dans une routine soft pure nécessitant plus qu'une simple copie; soit vers du hardware...), que cette instruction va vous permettre de faire des scrollings (décallage d'une partie de l'écran), mais aussi d'afficher un sprite (envoyer un gfx à l'écran)... Déja de jolies choses à faire avec cette instruction !!!

LE SCROLLING SOFT A BASE DE LDIR:

Notre but va être ici de faire scroller quelques lignes à l'écran... Disons 8 pour commencer.

L'écran standard (c'est a dire, si vous ne vous êtes pas amusé à le changer d'adresse), débute à l'adresse #C000 et ce termine en #FFFF. les 8 premières lignes ont pour adresse:

Chaque ligne fait 80 octets de large (sauf si vous l'avez changé). Ainsi, nous voulons scroller la 1ère ligne de la droite vers la gauche. Si nous réfléchissons, cela signifit que l'octet ce trouvant en #C001 sera envoyé en #C000... Donc, notre adresse de départ sera #C001 et celle de destination sera #C000. J'ai aussi dit qu'une ligne fait 80 octets de largeur, notre longueur sera donc 79 (vu que notre point de départ est #C001 et non pas #C000). Ainsi, faire scroller la première ligne ce résume a:

à vous de faire l'éssais pour les autres lignes...

J'en vois déja qui rallent en disant que ca ne scroll pas à l'infini, qu'il y a un scroll et que paf, cela s'arrete !!! Soyez patients, ca va venir !!! nous avons tout d'abord pas mal de chose à voir:

Pour que le scroll boucle à l'infini, vous pouvez toujours remplacer le RET par un JP DEBUT et rajouter le label DEBUT juste avant le LD HL... Ca bouclera !!! Mais la, je vois que vous rallez encore !!! C'est trop rapide, vous n'avez pas eut le temps de voir ce qui ce passait... Je vais donc maintenant vous expliquer un petit peu ce qu'il ce passe à l'écran, entre autre les signaux de synchronisation:

 

 

A suivre...