Podmiana wartości ostatniego bajtu bez wstawki asm

0

Witam.

Mam teraz zagwostkę. Jak za pewne wielu z Was wie i to pewnie lepiej ode mnie, że w Assemblerze mamy na przykład rejestr EAX, który może wynosić na przykład $12345678, a wtedy rejestr AL wynosi $78. I tutaj posłużyłem się takim kodem jak poniżej aby nie wykonywać wstawki asm, a jedynie operować na zmiennych typu DWord i Byte. I tutaj pytanie, czy można to zrobić inaczej, bo docelowo kod ma być w aplikacji WinAPI i nie chce przerzucać za wiele kodu Borlanda z modułu SysUtils, no chyba że będę do tego zmuszony. Czyli chodzi o to czy jakoś inaczej można wstawić ostatni bajt do wartości DWord bez dokonywania żadnej operacji matymatycznej. Z góry dziękuję za wszelkie wskazówki. I wiem, że może głupie nazwy zmiennych, ale chodzi o zasadę działania.

procedure UpdateRegister(var BaseReg : DWord; SmallReg : Byte);
var
  HexStr, NewVal : string;
begin
  HexStr := IntToHex(BaseReg, 8);
  NewVal := IntToHex(SmallReg, 2);
  HexStr := Copy(HexStr, 1, 6) + NewVal;
  BaseReg := StrToInt('$' + HexStr);
end;
2
BaseReg:=(BaseReg and $FFFFFF00) or SmallReg;

Prościej się nie da.

0

Wersja 2:
BaseReg:=(((BaseReg)shr(8))shl(8))or(SmallReg);
Wersja 3:
BaseReg:=((BaseReg)xor(Byte(BaseReg)xor(SmallReg)));
Wersja 4: // ta akurat zgadza się matematycznie ale nie wiedzieć czemu nie działa.
BaseReg:=((BaseReg)or(SmallReg))and(not(Dword(SmallReg)));

0

Dziękuję bardzo za odpowiedzi. Bez Waszej pomocy bym sobie nie poradzil, bo noga ze mnie z matmy, a i operacje logiczne ogarniam tak sobie, jak widać. Skorzystam z rozwiązania, które podal pelsta, czyli...

procedure UpdateRegister(var BaseReg : DWord; SmallReg : Byte);
begin
  BaseReg := (BaseReg and $FFFFFF00) or SmallReg;
end;
0

Można też tak (odpowiednik asemblerowego EAX/AL, czyli bez operacji logicznych):

procedure UpdateRegister(var BaseReg : DWord; SmallReg : Byte);
var BaseTab:array[0..3] of Byte absolute BaseReg;
begin
  BaseTab[0]:=SmallReg;
end;
0

O fajny sposób, nie trzeba za dużo wiedzieć o operacjach logicznych, ale z opisu na: Absolute wynika, że w Delphi 8 i nowszych taki kod nie zadziała. Ja jednak mam i używam Delphi 7 Personal, także to mi się też przyda. Dziękuję.

0
procedure UpdateRegister(var BaseReg : DWord; SmallReg : Byte);
var
  BaseRegB: ^Byte;
begin
  BaseRegB := @BaseReg;
  BaseRegB^ := SmallReg;
end;
0

(PByte(@BaseReg))^:=SmallReg;

0

Spodziewałbym się identycznego kodu wynikowego dla wskaźników i dla absolute.

wynika, że w Delphi 8 i nowszych taki kod nie zadziała. Ja jednak mam i używam Delphi 7 Personal, także to mi się też przyda. Dziękuję.
Delphi 8 to w ogóle inne zwierzę (Delphi.Net). Nie sprawdzałem, ale w najnowszych powinno działać.

0

Pamiętajcie o kolejności bajtów, jak chcecie mieć przenośny kod to nie rzutujcie worda, dworda czy czegoś podobnego na tablicę bajtów. Rozwiązanie pelsty jest najlepsze.

pelsta napisał(a)

BaseReg:=(BaseReg and $FFFFFF00) or SmallReg;

0

Jeszcze raz dzięki wszystkim, a sposób Azarien też mi się bardzo przyda, bo w innym miejscu w moim programie potrzebuje pobrać "przedostatni bajt" wartości typu DWord, więc robię to tak i działa ok:

function GetH(BaseReg : DWord) : Byte;
var
  BaseArr : array[0..3] of Byte absolute BaseReg;
begin
  Result := BaseArr[1];
end;
0

Można to zrobić bez rzutowania na tablicę bajtów i taki sposób polecam. Nie mam środowiska do Delphi ani Pascala, więc zapodaję kod w C++:

#include <iostream>

int getByte(int x, int which) {
    return (x >> (which * 8)) & 0xFF;
}

void setByte(int *x, int which, int byte) {
    *x &= ~(255 << (which * 8));
    *x |= (byte & 0xFF) << (which * 8);
}

int main() {

    int x;
    setByte(&x, 0, 5);
    setByte(&x, 1, 8);
    std::cout << getByte(x, 0) << " " << getByte(x, 1);

    return 0;
}
0
 uses sysutils;
type wo=record case integer of
  0:(dw: dword);
  1:(LL,LH,HL,HH:byte);
  2:(LW, HW: word)
end;
 
var t:dword;
begin
  t:=$12345678;  writeln(hexstr(t,8));
  wo(t).HL:=$CD; writeln(hexstr(t,8));
  writeln(hexstr(we(t).hw,4));
end.

1 użytkowników online, w tym zalogowanych: 0, gości: 1