Schuiven en roteren Genic Clubguide, 00-00-00 MACHINETAAL: S C H U I V E N E N R O T E R E N ======================================= Ik heb nu al een aantal mensen gesproken die in principe best in staat moeten zijn om een werkend machinetaal programma te schrijven. Ze kennen de meeste belangerijke instrukties wel, maar tot mijn verbazing blijken roteer en schuifinstrukties niet tot deze elementaire kennis te vallen. Dit vind ik raar omdat deze soort instrukties niet echt moeilijk zijn en ze vooral bij grafische software nogal eens gebruikt moeten worden. Gevorderde programmeurs kunnen het eerste stuk van het nu volgende artikel wel overslaan, maar ik raad ze toch aan om het laatste deel te lezen omdat daar interessante tips staan over vermenigvuldigen en delen. Ik ga er vanaf nu verder vanuit dat u een lijst hebt met MNEMONICS (=instruktie tabellen) + Opcodes (=de code van een instruktie) hebt. Hebt u deze niet, zorg dan dat u er ‚‚n krijgt omdat u anders NOOIT in staat zult zijn om een behoorlijk programma te schrijven, omdat u niet zult weten hoe de vlaggen be‹nvloed worden bij een willekeurige instruktie. (Nvdr: deze tabellen zullen in gedeelten op de paper- enclosure worden gepubliceerd. Deze keer de tabel met schuif- en roteerinstrukties.) Er zijn twee soorten schuif en roteerinstrukties, nl. logische en rekenkundige, maar het is in de praktijk niet nodig dat u ze uit elkaar kunt houden. Als u de werking ervan weet is dat goed genoeg. Cy = De Carry vlag van het F register Dus niet het C register Bit: 76543210 RLCA Cy < 7 <--- 0 RLCA = Rotate Left Carry Accumulator Dit betekent zoiets als Roteer de Accu Linksom naar de Carry. Bit 7 van het A register komt in de Cy vlag te staan, waarna alle bits van het A register 1 plaats naar links opschuiven. Het zevende bit komt op de plaats van bit 0 Vb. SCF ; (Set Cy vlag ==> Cy = 1) CCF ; (Invert Cy vlag ==> Cy = 0) LD A,33 ; (A = 10100001B Cy = 0) RLCA ; (A = 01000011B Cy = 1) RRCA werkt precies andersom, hier roteert alles naar rechts en komt de inhoud van Bit 0 van register A in de Cy. Dit is even een voorbeeld van een roteerinstruktie. Als u in een MNEMONICS tabellenlijst kijkt zult u zien dat alles daar nog veel duidelijker in staat. U zult bij de instrukties plaatjes aantreffen met pijlen die de richting van de verschillende bewegingen aangeven. Als u deze tabellen eens even bestudeert, dan zult u ook zien dat andere schuifinstrukties ook met andere registers gedaan kunnen worden, of zelfs met bytes in het geheugen. De instukties RLD en RRD vallen een beetje op door hun vele pijltjes bij de uitleg. Het praktische nut van deze instrukties is mij nog nooit opgevallen. Theoretisch wordt een 12 bits woord 4 bits opgeschoven en worden de 4 afgestoten bits aan de andere kant weer neergezet. De 12 bits worden door het A register en byte (HL) gevormd. Vb. A = 00001111B (HL) = 10101001B A = 16 (HL) = 196 RLD A = 00001010B (HL) = 10011111B A = 10 (HL) = 159 RLD A = 00001001B (HL) = 11111010B A = 09 (HL) = 250 RLD A = 00001111B (HL) = 10101001B A = 16 (HL) = 196 Als iemand een toepassing voor deze beide instrukties heeft, dan wil ik het graag horen. Goed, dan komt nu het deel dat ook nog interessant kan zijn voor de wat gevorderde programmeurs. Als je een byte schuift dan is dat hetzelfde als een vermenigvuldiging of een deling door 2, zolang er maar geen bit door het schuiven verdwijnt. Het antwoordt zou in zo'n geval groter dan 255 worden, en dat kan niet bij een 8 bits getal. Het getal dat verdwijnt komt altijd in de Cy terecht. Dit verklaart meteen de naam van dit bit. Een 'Carry overflow' is namelijk de Engelse term voor het wegvallen van een bit. Als je alleen maar een vermenigvuldiging of deling door 2 kunt doen, dan kom je niet erg ver. Het is echter heel gemakkelijk om een vermenigvuldiging met b.v. 25 te maken als je de vermenigvuldiging opsplitst. 4 x 25 = 100 4 x (16 + 8 + 1) = 4 x 25 = 100 Als de vermenigvuldigingsfaktor dus niet een macht van twee is, dan moet u deze faktor in machten van 2 opsplitsen zoals hierboven vermeld staat. Ik kan hier alleen maar het vermenigvuldigen en delen met integers behandelen. Dan nu het praktische voorbeeld: LD A,4 ; De startwaarde LD B,A ; Bewaar faktor A x 2^0 = 1 RLCA ; A x 2 RLCA ; A x 2 RLCA ; A x 2 ==> totaal = x 8 LD C,A ; Bewaar faktor RLCA ; A x 2 ==> totaal = x 16 ADD A,B ; Tel B erbij op ADD A,C ; Tel C erbij op. In A staat nu het antwoord ! Hierboven staat dus: 4x1 + 4x8 + 4x16 = 4 x (1+8+16) = 4 x 25 = 100 Een deling is niet volgens dit principe te maken, alleen als u een getal door een macht van 2 wilt delen gaat dat. In alle andere gevallen is herhaald aftrekken de enige methode. 192 / 16 LD A,192 SRL A ; SRL = Shift Right Logic SRL A SRL A SRL A ; Totaal gedeeld door 2^4 = 16 U mag hier niet van de snelle roteer instrukties gebruik maken omdat verdwijnende bits dan weer aan de linker kant in het register geschoven worden. Dit kan niet de bedoeling zijn, omdat dat verkeerde antwoorden oplevert. 192 / 24 = 8 192 - n x 24 = 0 ==> n = 8 LD A,192 ; Beginwaarde LD B,255 _SP1: INC B AND A SUB 24 ; De deler JP NZ,_SP1 ; Zolang A niet 0 is, blijven aftrekken LD A,B ; Zet het antwoord in A Goed, dat was het dan voor deze keer. Ik heb natuurlijk lang niet alles behandeld, maar u kunt zelf ook wel wat uitproberen. Pas met de deling op dat u alleen getallen deelt waar als antwoord een geheel getal uit komt. Als het toch anders uit kan komen, dan moet u deze routine niet gebruiken omdat het dan mogelijk is dat de lus nooit onderbroken zal worden. Het komt in de praktijk toch niet veel voor dat u in een routine wilt delen, vermenigvuldigen komt echter redelijk vaak voor en ik hoop dat ik een aantal mensen heb kunnen helpen. Veel programmeerplezier, Alex van der Wal |