logo elektroda
logo elektroda
X
logo elektroda
Adblock/uBlockOrigin/AdGuard mogą powodować znikanie niektórych postów z powodu nowej reguły.

[Assembler] [Assembler][Z80] Program do mnożenia 8-bitowych liczb z użyciem stosu

elo 28 Lis 2004 17:16 6010 4
  • #1 1020153
    elo
    Poziom 2  
    Posty: 2
    Witam, proszę o pomoc, mam do wkonania nastepujące zadanie:

    napisać program wykorzystując assembler procesora z80, który będzie mnożył 2 liczby 8-bitowe, wykorzystując stos do przechowywania. Mnożną można umieścić w rejestrze A, natomiast mnożnik w rejestrze B, (wynik w HL). Byłby ktoś w stanie napisać taki programik?? pozdro...

    rrally(_at_)interia.pl gg: 3909528

    Zamykam. - arnoldziq
  • #2 1020322
    jiwaniuk
    Poziom 31  
    Posty: 1393
    Pomógł: 142
    Ocena: 145
    Taki program mógłby wyglądać tak:
    Mnożna: rejestr E
    Mnożnik: rejestr A
    Wynik: rejestr HL

    LD HL,0000 ;inicjacja wyniku
    LD B,08 ;licznik pętli
    LD D,00 ;zerowanie bardziej znaczącego bajtu DE
    NXBIT ADD HL,HL ;przesunięcie wyniku w lewo
    RLA ;sprawdzenie cyfry monożnika
    JR NC, FIN ;opuszczenie zera
    ADD HL,DE ;dodanie mnoznej
    FIN DJNZ NXBIT ;powrót do początku petli
    RET

    Rejestr B jest używany przez rozkaz DJNZ jako licznik pętli, dlatego mnozna jest w rejestrze E.

    NXBIT i FIN to są etykiety, reszta pisana dużymi literami to mnemoniki Z80.

    Powinno zadziałać.

    Pozdrawiam wszystkich

    jjanek
  • #3 1020442
    elo
    Poziom 2  
    Posty: 2
    OK, a nie trzeba tam na początku dać ORG 100, jakby to wyglądało w całości do HLT (czy coś) :) ?? zaczynam dopiero z assemblerem :/
  • #4 1020647
    Akane
    Poziom 27  
    Posty: 638
    Pomógł: 144
    Ocena: 33
    witam i podziwiam :)

    nie chce mi się wyciągać ZX z szafki i znowu gapić się w ten zielony monitor :)
    Dzięki Sinclairowi za Spectruma ! gdyby nie ten komputer to nie znałbym się na mikroelektronice. Rok temu przesiadłem się na PCta, i przekładam swoje programy na intelowskie mnemoniki
    '25 * 255
    
    	ORG 0        ; jeśli to "samoróba"
    	ORG 32768    ; jeśli to ZX Spectrum :)
    
    	LD HL, 25
    	LD DE, 0
    	LD A, 255
    	LD B, 8     ; 8 przebiegów pętli dla 8-io bitowego mnożnika
    
    NextBit:
    
    	RRA         ; test bitu 0
    	JC Nieparzyste
    
    	ADD HL, HL  ; A było parzyste : A=A/2 HL=2HL
    	JR dalej
    
    Nieparzyste:
    
    	ADD A,A     ; A=A-1  DE=DE+HL
    	EX DE,HL
    	ADD HL,DE
    	EX DE,HL
    
    Dalej:
    
    	DJNZ NextBit
    
    	ADD HL,DE
    ;wynik w HL
    jest to szybki algorytm mnożenia - liczba przebiegów pętli jest liniowo zależna od ilości bitów mnożnej

    na początku mnożnik wpisujemy do wyniku i zaczynamy z koksem:
    jeśli mnożna jest parzysta to mnożymy wynik przez 2, a mnożną dzielimy przez 2
    w przeciwnym razie aktualny wynik dodajemy do podręcznej pamięci (DE) a mnożną zmniejszamy o jeden
    powtażamy to 8 razy (bo mnożymy przez liczbę ośmio-bitową) i na końcu dodajemy do wyniku tą podręczną pamięć

    może po kodzie tego nie widać że zmniejszam mnożną o 1, ale patrz:
    RRA - dzieli A przez 2 i jeśli A było nieparzyste (21/2 = 10) to flaga C się ustawia i program skacze do rozkazu ADD A,A (10+10) czyli A=20 - więc A jest mniejsze o 1 niż poprzednio

    tego algorytmu mnożenia użyłem do obliczania silnii na PC i wyniki są zadowalające (liczenie w kodzie BCD amd 2800+):
    1000! - 0.078s 2568 cyfr
    10000! - 13s 35660 cyfr
    50000! - 7min 213237 cyfr
    75000! - 19min 333061 cyfr
    podczas gdy Z80 @4MHz obliczał 1000! chyba w 30minut :d ale szybciej od Amigi 600 :d:d

    można i tak:
    LD   HL,0
    LD   DE, mnożna
    LD   B,mnożnik
    
    loop:
    ADD  HL,DE
    DJNZ loop

    tylko nie wiem po co stos do tego pakować ? To ma działać jak winapi?
    PUSH mnożna
    PUSH mnożnik
    CALL pomnóż
    POP wynik
    POP HL  ;adres powrotny
    EXX ; wymiana rejestrów HL DE i BC na "zapasowe"
    POP HL
    POP DE
    LD A,E
    [mnożenie]
    PUSH HL  ;wynik na stos
    EXX  ; oddaj stare rejestry
    JP (HL) ; pseudo RET


    teraz coś dla PCmaniaków: mnożenie długich liczb po intelowsku
    CHAR a[0xFFFFF], b[0xFFFFF] /* 2097150 cyfr dla wyniku */ 
    'zerowanie tabel 
    RtlZeroMemory(&a, 0xFFFFF) 
    RtlZeroMemory(&b, 0xFFFFF) 
    'mnożymy 40000 * 7 
    a[0]=7 
    UINT BC, LenA /* LenA to ilość bajtów wyniku */ 
    BC = 40000 
    LenA = 1 
    'start 
    'NASM assembler IBasic PRO 
    
         _asm 
             MOV  eax,[$BC]  ;eax = 40000 
    LoopDo: 
    
             MOV  ebx,eax 
             AND  ebx,1 
             JZ   RLCA            ; jump if BC & 1 = 0 
    
             DEC  eax             ; mul-- 
             PUSH eax 
    
    ;************************* 
    AddAtoB: 
                MOV  ecx,[LenA]   ; Counter 
                MOV  edx,$b 
                MOV  ebx,$a 
                CLC               ; Clear Carry 
          LaddAB: 
                MOV  al,[edx]     ; Get 2 bytes from b[n] 
                ADC  al,[ebx]     ; Add a[n] 
                DAA               ; BCD correction 
                MOV  [edx],al     ; Store in b[n] 
                INC  edx 
                INC  ebx 
                LOOP LaddAB       ; 'next n' 
    
                JNC  Lrlcaexit 
                INC  dword[edx]   ; if Carry then add one digit 
                JMP  Lrlcaexit 
    ;************************* 
    RLCA: 
             SHR eax,1            ; mul = mul >> 1 
             PUSH eax 
    
    ;************************* 
                MOV  ecx,[LenA]   ; Counter 
                MOV  ebx,$a 
                CLC               ; Clear Carry 
          Lrlca: 
                MOV  al,[ebx]     ; Get 2 bytes from a[n] 
                ADC  al,al        ; bytes *2 + Carry 
                DAA               ; BCD correction 
                MOV  [ebx],al     ; Store in a[n] 
                INC  ebx          ; n++ 
                LOOP Lrlca        ; 'next n' 
    
                JNC  Lrlcaexit 
                INC  dword[ebx]   ; if Carry then add one digit 
                INC  dword[$LenA] ; and inc number of digits 
    ;************************* 
    Lrlcaexit: 
    
             POP  eax 
             CMP  eax,1 
             JA  LoopDo           ;   until BC>1 
    
    ;************************* 
    AddBtoA: 
                MOV  ecx,[LenA]   ; Counter 
                MOV  edx,$a 
                MOV  ebx,$b 
                CLC               ; Clear Carry 
          LaddBA: 
                MOV  al,[edx]     ; Get 2 bytes from a[n] 
                ADC  al,[ebx]     ; Add bytes from b[n] 
                DAA               ; BCD correction 
                MOV  [edx],al     ; Store in a[n] 
                INC  edx          ; n++ 
                INC  ebx 
                LOOP LaddBA       ; 'next n' 
    
                JNC  LaddBAexit 
                INC  dword[edx]   ; if Carry then add one digit 
                INC  dword[$LenA] ; and inc number of digits 
    LaddBAexit: 
             _endasm
  • #5 1020709
    jiwaniuk
    Poziom 31  
    Posty: 1393
    Pomógł: 142
    Ocena: 145
    elo
    Ja podałem tylko program bez oprawy "asemblerowej" lub "komputerowej". Zależnie od tego, gdzie będziesz to odpalał, tak musisz ten program "ubrać" w sterowanie (adres początkowy, ewentualnie zmienić nazwy etykiet (ilość znaków) i wprowadzić inne polecenia specyficzne dla uruchamiacza).

    Pozdrawiam wszystkich

    jjanek
REKLAMA