2015-03-21 18 views
5

Próbuję utworzyć opóźnienie oprogramowania. Oto przykładowy program z tego, co robię:Z80 Software Delay

Address Data Opcode Comment  
    1800  06 LD, B Load register B with fix value 
    1801  “ “   Fixed value 
    1802  05 DEC, B Decrement value in register B 
    1803  C2 JP cc Jump to 1802 if value is not 0 
    1804  02 -  Address XX 
    1805  18 -  Address XX 

Moje pytanie brzmi: w jaki sposób można obliczyć wymaganą stałą wartość, aby załadować do rejestru B tak, że proces zmniejszanie wartości aż 0 trwa 2 sekundy?

W moim podręczniku danym czasie uruchomić instrukcji opiera się na CPU 4MHz ale procesor Z80 używam ma prędkość 1.8MHz. Masz pomysł, jak to obliczyć? Dzięki. PS tu jest ubytek (DEC) i skok (JP cc) instrukcje z podręcznika:

Instruction M Cycles T states 4 MHz E.t 
DEC r    1   4   1.00 
JP cc    3  10 (4,3,3) 2.50 

Odpowiedz

3

Jeśli przez 1.8MHz znaczy dokładnie 1.800.000 Hz, a następnie do uzyskania 2-sekundowego opóźnienia trzeba by opóźnić 3,600,000 T-stanów. Twoja obecna pętla opóźnienie trwa 14 T-stany za iteracji, co oznacza, że ​​wartość początkowa dla B musiałby być 3600000/14 == 257143, co oczywiście nie zmieści się w jednym bajcie.

Największa liczba iteracji, które można określić za pomocą rejestru 8-bitowego, wynosi 256, a do osiągnięcia 3 600 000 stanów T z 256 iteracjami, każda iteracja musiałaby przyjąć 14 062 T-stanów. To jeden wielki organizmpętla.

Jeśli używamy licznik 16-bitowy rzeczy zaczynają się nieco łatwiejsze. Przy 65 536 iteracjach potrzebujemy tylko 55 T-stanów na iterację, aby osiągnąć ogółem 3 600 000 stanów. Poniżej jest przykład co to może wyglądać tak:

; Clobbers A, B and C 
    ld  bc,#0 
1$: 
    bit  #0,a ; 8 
    bit  #0,a ; 8 
    bit  #0,a ; 8 
    and  a,#255 ; 7 
    dec  bc  ; 6 
    ld  a,c  ; 4 
    or  a,b  ; 4 
    jp  nz,1$ ; 10, total = 55 states/iteration 
    ; 65536 iterations * 55 states = 3604480 states = 2.00248 seconds 
+0

oops. Minęło trochę czasu odkąd skończyłem Z80. –

2

jestem kawałkiem dziwaka optymalizacji, więc tutaj jest mój przejdź za pomocą składni z których jestem najbardziej znany (od asemblera TASM i podobne) :

Instruction opcode timing ld bc,$EE9D ;01EE9D 10cc ex (sp),hl ;E3 19*(256C+B) ex (sp),hl ;E3 19*(256C+B) ex (sp),hl ;E3 19*(256C+B) ex (sp),hl ;E3 19*(256C+B) djnz $ ;10FA 13cc*(256C+B) - 5*C dec c ;0D 4*C jr nz,$-3 ;20F7 12*C-5

Kod ten jest 12 bajtów i 3600002 cykli zegara.

EDIT: Wygląda na to, że część mojej odpowiedzi zniknęła! Aby lepiej odpowiedzieć na twoje pytanie, Twój Z80 może przetwarzać 1800000 cykli zegarowych w ciągu jednej sekundy, więc potrzebujesz dwa razy więcej (3600000). Jeśli zsumować czasy podane w moim kodu, otrzymasz:

= 10 + (256C + B) (19 * 4 + 13) -5C + 4C + 12C-5

= 5 + (256C + B) 89 + 11 C

= 5 + 22795C + 89B

zatem kod czasowy jest w dużej mierze zależny od C 3600000/22795 wynosi 157, tak więc zainicjować C z 157 (0x9D). Po ponownym podłączeniu otrzymujemy B w przybliżeniu 237,9775, więc zaokrąglamy to do 238 (0xEE). Podłączenie tych elementów daje nasz ostateczny czas 3600002 cm3 lub około 2.000001 sekund. Zakłada się, że procesor działa dokładnie z częstotliwością 1,8 MHz, co jest bardzo mało prawdopodobne.

Jeśli możesz używać przerwań, z grubsza obliczyć, ile razy wystrzeliwuje na sekundę i użyć pętli podobnej do halt \ djnz $-1. Oszczędza to znacznie więcej pod względem zużycia energii.

+0

"Oszczędza to znacznie więcej pod względem zużycia energii". Nie jestem pewien, czy to stwierdzenie jest rzeczywiście prawdziwe, ponieważ HALT powtarza operacje NOP, dopóki nie wystąpi przerabianie masowalne. Nie sądziłem, że różne kody operacyjne powodują znacznie mniejszy lub większy pobór mocy niż inne. Może się mylę. –