Wielobajtowe NOP-y
From Atariki
| Wersja z dnia 21:20, 27 gru 2007 Xxl (Dyskusja | wkład) ← Previous diff |
Aktualna wersja KMK (Dyskusja | wkład) |
||
| Linia 1: | Linia 1: | ||
| - | Na stronie znajdują się metody pozwalające skrócić kod, często kosztem szybkości działania programu. | + | == Rozkaz BIT == |
| + | Rozkazy ''BIT abs'' (trzybajtowy: $2C ll hh) i ''BIT zp'' (dwubajtowy: $24 hh) nie modyfikują zawartości pamięci ani rejestrów (z wyjątkiem rejestru statusu 6502), więc mogą być użyte jako legalne, wielobajtowe NOP-y do zamaskowania (przeskoczenia) dowolnego rozkazu jedno- lub dwubajtowego. | ||
| - | '''1. Wartość w rejestrze A,X,Y zależy od parametru.''' | + | Na ogół maskowane są w ten sposób rozkazy ładujące ośmiobitowe stałe do rejestrów. Technikę tę stosuje się najczęściej w podprogramach, w których kod główny spełnia różne funkcje w zależności od stałego parametru przekazanego w akumulatorze, a punkty wejścia wywoływane są za pośrednictwem jakiejś tablicy adresów. Zamiast: |
| - | przykład: IF zmienna=dana THEN A=dana1 ELSE A=dana2 - badane mogą być inne relacje zmienna - dana. | + | <pre> |
| + | E0 LDA #$00 | ||
| + | BEQ EXEC | ||
| + | E1 LDA #$01 | ||
| + | BNE EXEC | ||
| + | EFF LDA #$FF | ||
| + | EXEC ... | ||
| + | </pre> | ||
| - | standardowo: | + | piszemy: |
| - | + | ||
| - | LDA zmienna | + | |
| - | CMP dana | + | |
| - | BNE _1 | + | |
| - | LDA #dana1 | + | |
| - | BNE _2 ; BEQ | + | |
| - | _1 LDA #dana2 | + | |
| - | _2 ... | + | |
| - | można zapisać również tak: | + | <pre> |
| + | E0 LDA #$00 | ||
| + | .BYTE $2C | ||
| + | E1 LDA #$01 | ||
| + | .BYTE $2C | ||
| + | EFF LDA #$FF | ||
| + | EXEC ... | ||
| + | </pre> | ||
| - | LDA zmienna | + | Dzięki pozbyciu się skoków w tym przykładzie zaoszczędzono dwa bajty. Z tego prostego triku nagminnie korzysta kod [[SpartaDOS X]] celem zaoszczędzenia pamięci RAM. |
| - | CMP dana | + | |
| - | BNE _1+1 | + | '''Stosując ten trik trzeba pamiętać, że maskowany rozkaz wraz z argumentem stanowi adres dla rozkazu BIT, a ten generuje odczyt. Np. użyta w powyższym przykładzie sekwencja ''.BYTE $2C / LDA #$FF'' ($2C, $A9, $FF) w przypadku wykonania w całości zostanie zinterpretowana przez procesor jako ''BIT $FFA9'' powodując odczytanie bajtu spod wymienionego adresu. W przypadku trafienia w ten sposób w rejestr sprzętowy wrażliwy na odczyt będą kłopoty. Takie rejestry mogą się znajdować na stronie $D5 (obszar przeznaczony dla kartridży)'''. Z tego względu trzeba unikać maskowania rozkazów, których drugi bajt (argument) ma wartość z zakresu $D0-$D7, zwłaszcza $D1 i $D5. |
| - | LDA #dana2 | + | |
| - | _1 BIT $xxA9 ; $xx - dana1, $A9 kod rozkazu LDA | + | Inne zastosowanie to załadowanie rejestru stałą w zależności od zmiennego parametru (gdy nie opłaca się zastosowanie tabeli). Przykład w pseudokodzie: ''IF zmienna=dana THEN A=dana1 ELSE A=dana2'' - badane mogą być inne relacje zmienna - dana. |
| + | |||
| + | Zamiast: | ||
| + | |||
| + | <pre> | ||
| + | LDA zmienna | ||
| + | CMP dana | ||
| + | BNE _1 | ||
| + | LDA #dana1 | ||
| + | BNE _2 ; lub BEQ | ||
| + | _1 LDA #dana2 | ||
| + | _2 ... | ||
| + | </pre> | ||
| + | |||
| + | można zapisać tak: | ||
| + | <pre> | ||
| + | LDA zmienna | ||
| + | CMP dana | ||
| + | BNE _1 | ||
| + | LDA #dana1 | ||
| + | .BYTE $2C | ||
| + | _1 LDA #dana2 | ||
| + | </pre> | ||
| + | |||
| + | == Rozkazy odgałęzień == | ||
| + | |||
| + | W rzadkich przypadkach, kiedy w danym miejscu programu konkretne znaczniki CPU są ustalone, można w opisany powyżej sposób użyć rozkazu odgałęzienia Bxx zamiast rozkazu ''BIT zp'' do zamaskowania następującego rozkazu jednobajtowego. Zysk polega na zaoszczędzeniu 1 cyklu pracy CPU (przez uniknięcie zbędnego dostępu do pamięci) oraz uniknięciu modyfikacji stanu jego rejestrów (poza, oczywiście, PC). | ||
| + | |||
| + | Zamiast: | ||
| + | |||
| + | <pre> | ||
| + | ON SEC | ||
| + | .BYTE $24 ;BIT | ||
| + | OFF CLC | ||
| + | </pre> | ||
| + | |||
| + | można napisać: | ||
| + | |||
| + | <pre> | ||
| + | ON SEC | ||
| + | .BYTE $90 ;BCC | ||
| + | OFF CLC | ||
| + | </pre> | ||
| + | |||
| + | [[Kategoria:Niezbędnik kodera]] | ||
Aktualna wersja
Rozkaz BIT
Rozkazy BIT abs (trzybajtowy: $2C ll hh) i BIT zp (dwubajtowy: $24 hh) nie modyfikują zawartości pamięci ani rejestrów (z wyjątkiem rejestru statusu 6502), więc mogą być użyte jako legalne, wielobajtowe NOP-y do zamaskowania (przeskoczenia) dowolnego rozkazu jedno- lub dwubajtowego.
Na ogół maskowane są w ten sposób rozkazy ładujące ośmiobitowe stałe do rejestrów. Technikę tę stosuje się najczęściej w podprogramach, w których kod główny spełnia różne funkcje w zależności od stałego parametru przekazanego w akumulatorze, a punkty wejścia wywoływane są za pośrednictwem jakiejś tablicy adresów. Zamiast:
E0 LDA #$00
BEQ EXEC
E1 LDA #$01
BNE EXEC
EFF LDA #$FF
EXEC ...
piszemy:
E0 LDA #$00
.BYTE $2C
E1 LDA #$01
.BYTE $2C
EFF LDA #$FF
EXEC ...
Dzięki pozbyciu się skoków w tym przykładzie zaoszczędzono dwa bajty. Z tego prostego triku nagminnie korzysta kod SpartaDOS X celem zaoszczędzenia pamięci RAM.
Stosując ten trik trzeba pamiętać, że maskowany rozkaz wraz z argumentem stanowi adres dla rozkazu BIT, a ten generuje odczyt. Np. użyta w powyższym przykładzie sekwencja .BYTE $2C / LDA #$FF ($2C, $A9, $FF) w przypadku wykonania w całości zostanie zinterpretowana przez procesor jako BIT $FFA9 powodując odczytanie bajtu spod wymienionego adresu. W przypadku trafienia w ten sposób w rejestr sprzętowy wrażliwy na odczyt będą kłopoty. Takie rejestry mogą się znajdować na stronie $D5 (obszar przeznaczony dla kartridży). Z tego względu trzeba unikać maskowania rozkazów, których drugi bajt (argument) ma wartość z zakresu $D0-$D7, zwłaszcza $D1 i $D5.
Inne zastosowanie to załadowanie rejestru stałą w zależności od zmiennego parametru (gdy nie opłaca się zastosowanie tabeli). Przykład w pseudokodzie: IF zmienna=dana THEN A=dana1 ELSE A=dana2 - badane mogą być inne relacje zmienna - dana.
Zamiast:
LDA zmienna
CMP dana
BNE _1
LDA #dana1
BNE _2 ; lub BEQ
_1 LDA #dana2
_2 ...
można zapisać tak:
LDA zmienna
CMP dana
BNE _1
LDA #dana1
.BYTE $2C
_1 LDA #dana2
Rozkazy odgałęzień
W rzadkich przypadkach, kiedy w danym miejscu programu konkretne znaczniki CPU są ustalone, można w opisany powyżej sposób użyć rozkazu odgałęzienia Bxx zamiast rozkazu BIT zp do zamaskowania następującego rozkazu jednobajtowego. Zysk polega na zaoszczędzeniu 1 cyklu pracy CPU (przez uniknięcie zbędnego dostępu do pamięci) oraz uniknięciu modyfikacji stanu jego rejestrów (poza, oczywiście, PC).
Zamiast:
ON SEC
.BYTE $24 ;BIT
OFF CLC
można napisać:
ON SEC
.BYTE $90 ;BCC
OFF CLC
