Programmeren in TI-83+ Assembly/Registers en procedures/De OP-registers
Optellen en aftrekken in Assembly is al een vrij moeilijke aangelegenheid. Vermenigvuldigen gaat nog veel ingewikkelder en delen gaat bijna niet. Verder kun je in Assembly alleen maar met gehele getallen werken. Hoe kan het besturingssysteem dan de rekensommen uitrekenen die door de gebruiker worden ingegeven? TI heeft daarvoor de OP-registers bedacht. Dat zijn plaatsen in het geheugen waarin kommagetallen kunnen staan. Met die OP-registers kun je gemakkelijker rekenen.
Wat zijn OP-registers?
bewerkenAlhoewel de naam anders doet vermoeden, zijn de OP-registers feitelijk geen registers. Eigenlijk zijn het stukjes van het geheugen. Zoek maar eens in ti83plus.inc naar OP1, dan zie je dat deze zich bevindt op adres $8478 en volgende. OP2 bevindt zich op $8483, enz. Er zijn in totaal zes OP-registers. In deze registers kan een kommagetal worden opgeslagen in de wetenschappelijke notatie. Je kunt er bijvoorbeeld ook het getal 5,22·10^74 in kwijt.
Het voordeel van OP-registers is dat TI allerlei bcalls heeft meegegeven aan het besturingssysteem om ermee te rekenen. Er zijn bijvoorbeeld bcalls om op te tellen, af te trekken, enzovoorts.
De structuur van een OP-register
bewerkenDe structuur van een OP-register is vrij ingewikkeld. Zie de afbeelding hieronder.
Een OP-register bestaat dus uit in totaal 11 bytes:
- Byte 1 is het teken van het getal (positief of negatief). Dit kan twee waarden aannemen: $00 betekent positief en $80 betekent negatief.
- Byte 2 is de exponent van de tien-macht. Bijvoorbeeld bij 5,22·10^74 is de exponent 74. Maar wat nu als de exponent kleiner is dan 0? Je kunt immers geen negatief getal opslaan in een byte. Daarom wordt iedere exponent vermeerderd met $80 (= 128). Het resultaat is dus (voor 5,22·10^74) 128 + 74 = 202 = $CA. Voor negatieve exponenten wordt de uitkomst dus kleiner dan $80.
- Byte 3-9 bevatten de echte cijfers van het getal. Vreemd genoeg wordt het getal decimaal opgeslagen: ieder cijfer komt in een halve byte (dus 4 bits) te staan. Voor ons getal 5,22·10^74 wordt dat dus $52, $20, $00, $00, ... De hexadecimale waarden A-F kunnen dus nooit worden gebruikt. Het getal wordt altijd in strikt wetenschappelijke notatie opgeslagen, dus precies één cijfer voor de komma. Het getal 10 sla je dus op als 1,0·10^1. Op deze manier weet de TI waar de komma valt.
- Byte 10-11 bevatten vier extra cijfers, die nodig zijn om de precisie bij rekensommen te garanderen. Stel je voor dat je 100 deelt door 3 en het resultaat in OP1 zet. Stel dat er dan geen extra cijfers waren, en we het getal weer met 3 zouden vermenigvuldigen, dan zou het resultaat 99,99999... zijn in plaats van 100. Om dit soort afrondingsfouten te voorkomen, rekent de TI met 4 cijfers extra.
Een getal in een OP-register zetten
bewerkenOm een getal in een OP-register te laden, moet je de benodigde 9 bytes (de extra cijfers hoef je niet mee te nemen) eerst ergens in het geheugen zetten, bijvoorbeeld onderaan het programma. Laad daarna in hl het geheugenadres van de eerste byte van de te kopiëren data. Roep daarna de bcall _Mov9ToOPx aan (met x is 1 of 2). Deze bcall laadt de negen bytes, te beginnen bij (hl), in OP1 of OP2. Het voorbeeld hieronder laadt de eerste decimalen van π in OP2.
ld hl, GetalPi bcall(_Mov9ToOP2) GetalPi: .db $00, $80, $31, $41, $59, $26, $53, $58, $97
Rekenen met OP-registers
bewerkenNu komen we bij het doel van het gebruik van OP-registers. Er is een gigantische hoeveelheid bcalls om met OP's te rekenen.
Deze tabel is nog in opbouw: alle beschrijvingen met (?) zijn nog niet gecontroleerd.
_Plus1 | OP1 = OP1 + 1 | _Cube | OP1 = OP1³ |
---|---|---|---|
_Minus1 | OP1 = OP1 - 1 | _DToR | OP1 wordt omgezet van graden naar radialen (??) |
_FPAdd | OP1 = OP1 + OP2 | _RToD | OP1 wordt omgezet van radialen naar graden (??) |
_FPSub | OP1 = OP1 - OP2 | _LnX | OP1 = ln(OP1) (?) |
_FPMult | OP1 = OP1 × OP2 | _LogX | OP1 = log(OP1) (met grondtal 10) (?) |
_FPDiv | OP1 = OP1 ÷ OP2 | _Sin | OP1 = sin(OP1) (?) (OP1 in graden of radialen?) |
_FPRecip | OP1 = 1 ÷ OP1 | _Cos | OP1 = cos(OP1) (?) (OP1 in graden of radialen?) |
_FPSquare | OP1 = OP1² | _Tan | OP1 = tan(OP1) (?) (OP1 in graden of radialen?) |
_SqRoot | OP1 = √OP1 |
Er zijn nog veel meer bcalls om met OP's te rekenen; je vindt ze in ti83plus.inc.
Andere acties met OP-registers
bewerkenOpdracht
bewerkenMaak een programma dat π (=3,141592653589793) vermenigvuldigt met 2, en er daarna 2,37 vanaf haalt. Het resultaat moet daarna op het scherm worden geschreven.
Het antwoord staat achterin het boek.