Tento dokument popisuje chování WAIT signálu (nWTGD, pin 93) v MZ-800 grafických režimech (DMD bit 3 = 0). Pro MZ-700 režim (DMD bit 3 = 1) viz 14-wait-nwtgd.md.
WAIT se generuje pro přístupy na 0x8000–0xBFFF (grafická VRAM). Registry WF (port CCH) a RF (port CDH) nemají vliv na WAIT.
Čtení nikdy nevyvolává WAIT a nikdy nepenalizuje následující přístup. CPU může číst VRAM kdykoliv, kolikrat chce, bez jakehokoliv omezení.
Zápis sam o sobe WAIT nedostane. Po zápisu vsak následuje horka fáze, během které další VRAM přístup dostane penalizaci:
| Režim | Délka horke fáze (od konce zápisu) |
|---|---|
| 320x200 (DMD=0x00, 0x02) | 32 CLK0 (~1.8 us) |
| 640x200 (DMD=0x04) | 17 CLK0 (~0.96 us) |
Pokud během horke fáze prijde další VRAM přístup (čtení nebo zápis), dostane WAIT. Počet WAIT T-stavu je stejný pro oba video režimy a závisí na typu přístupu:
| Přístup v horke fázi | WAIT penalizace |
|---|---|
| WRITE | 3–6 TW (15–30 CLK0) |
| READ | 6–9 TW (30–45 CLK0) |
1 TW = 1 WAIT T-stav = 5 CLK0 = jeden CPU cyklus navíc vlozeny Z80.
Rozptyl v ramci každého rozsahu je dan fazovym vztahem CPU přístupu vuci video fetch cyklů — viz sekce "Přesně určení poctu TW" nize.
Pokud horka fáze uplyne driv než prijde další přístup, žádný WAIT nenastane. Pokud je penalizovany přístup opet WRITE, následuje nova horka fáze se stejnymi pravidly.
LDIR provádí střídavě READ + WRITE. READ nepenalizuje, takže nasledny WRITE projde bez WAIT. Po WRITE následuje horka fáze, ale další VRAM přístup (READ další iterace) prijde až za ~70 CLK0, což je daleko za hranici horke fáze. LDIR do VRAM tedy běží v MZ-800 režimech bez jakychkoli WAITu.
Stejná WAIT hradlova logika (READ/WRITE detekci FF -> NAND -> WAIT FF) je použitá ve všech režimech. Rozdíl je v časování resetu detekci flip-flopu — v MZ-800 režimech je video fetch pipeline resetuje periodicky, v MZ-700 až na HBLN hranici.
Oba detekci FF se nastavuji při VRAM přístupu a resetuji video pipeline. Ale rychlost resetu se liší řádově:
| FF | Nastaven kdy | Reset v 320x200 | Reset v 640x200 |
|---|---|---|---|
| READ FF (xF615_141_13) | T2r (zacatek čtení) | ~3 CLK0 po T3f | ~4 CLK0 po T3f |
| WRITE FF (xF635_81_20) | T3f (konec zápisu) | ~32 CLK0 po T3f | ~17 CLK0 po T3f |
Mezi dvěma po sobe jdoucimi VRAM přístupy uplyne minimalne ~20 CLK0 (T3 prvniho cyklů + idle + T1+T2 druheho cyklů). READ FF (~3 CLK0) je v tu chvili davno resetovany. WRITE FF (~17-32 CLK0) nikoliv.
Oba přístupy zacinaji na stejnem casovem offsetu od predchoziho WRITE. Rozdíl je v tom, co se deje během WAIT stavu:
WAIT FF (xF645_141_12) je drzen v resetu když není aktivní VRAM přístup (nMREQ='1' nebo adresa mimo rozsah):
WAIT_FF.nRES = net_F302_50_7_out AND RST0_buf
net_F302_50_7_out = net_F302_51_6_out NAND net_F302_30_5_out
Proto se WAIT může aktivovat pouze během VRAM přístupu. Mezi přístupy je nWTGD vždy neaktivní ('1' / 'Z'), nezavisle na stavu detekci FF.
nRES = RST0_buf AND (xF635_141_14.nO OR NOT(net_F100_122_14_in))
Signál net_F100_122_14_in je odvozen od video fetch pipeline (dvojice FF xF642_131_12 a xF611_131_13 taktovanych CLK0). V MZ-800 režimech generuje velmi rychle reset pulzy (~3-4 CLK0 po T3f). V MZ-700 režimu se reset vyskytne pouze na HBLN boundary.
nRES = xF635_81_18.nO AND RST0_buf
xF635_81_18 je taktovan signálem odvozenym od video VRAM write strobe (nVRWR). Reset probíhá pomaleji než u READ FF — ~17-32 CLK0 po T3f (idle bus).
Faze | WR_FF.nO | RD_FF.O | NAND | WAIT_FF.nRES | nWTGD
---------|----------|---------|------|-------------|------
idle | 1 | 1 | 0 | 0 | 1 FF v resetu
W:T1f | 1 | 1 | 0 | 1 | 1 VRAM detect, nRES=1
W:T2r | 1 | 1 | 0 | 1 | 1 nWR padl
W:T3f | 1 | 1 | 0 | 0 | 1 cyklus skoncil
W:T3f+30 | 0 | 1 | 1 | 0 | 1 WR_FF set (po nWR rise)
idle2 | 0 | 1 | 1 | 0 | 1 NAND=1, ale WAIT FF v resetu
R:T1f | 0 | 1 | 1 | 1 | 1 VRAM detect, nRES=1
R:T2r | 0 | 0 | 1 | 1 | 0 WAIT FF zachytil D=1 -> WAIT!
R:TW04f | 0 | 0 | 1 | 1 | 0 wrFF_nR=0 (reset puls)
R:TW05r | 1 | 0 | 1 | 1 | 0 WR_FF resetovan
R:TW08r | 1 | 1 | 0 | 1 | 0 RD_FF resetovan, NAND=0
R:TW08f | 1 | 1 | 0 | 1 | 1 WAIT uvolnen (D=0)
Celkem: 8 TW (= 40 CLK0)
| Situace | WAIT? | Proč |
|---|---|---|
| LDIR do VRAM | Ne | READ nepenalizuje, W->R gap ~70 CLK0 > horka fáze |
| LD (HL),A + LD (HL),A | Hranicni v 320x200 | W->W gap ~30 CLK0, okno je 32 CLK0 |
| DEC/INC (HL) | Ne | Interní R+W, READ nepenalizuje |
| Jednorázový zápis | Ne | Nenasleduje další VRAM přístup vcas |
Počet TW je deterministicky — závisí na pozici penalizovaneho přístupu v řádku (v CLK0). Vzorec se opakuje s periodou:
80 CLK0 = lcm(16, 5)
kde 16 CLK0 = perioda video fetch column cyklů, 5 CLK0 = délka jednoho CPU T-stavu. Perioda 80 CLK0 je stejná pro oba video režimy i pro oba typy přístupu (W+R, W+W).
640x200 používá přesně stejnou 80-prvkovou tabulku jako 320x200, jen posunutou o 16 CLK0 (= 1 column period režimu 320x200):
TW_640(pos) = TW_320((pos + 16) mod 80)
Indexovano pozici prvniho WRITE v řádku (CLK0 mod 80):
WRITE+READ (6-9 TW):
fase: 0 1 2 3 4 5 6 7
01234567890123456789012345678901234567890123456789012345678901234567890123456789
W+R: 96999888887777766999898887877767996998888877777966998898877877667998998878877677
WRITE+WRITE (3-6 TW):
fase: 0 1 2 3 4 5 6 7
01234567890123456789012345678901234567890123456789012345678901234567890123456789
W+W: 33565554544434333665555544444333635565544544334335665545544344336635555544444336
Pro 640x200 se pouzije stejná tabulka s offsetem +16:
TW_640[i] = TW_320[(i + 16) % 80]
TW hodnota se mění v ramci 16 CLK0 video column cyklů — postupne klesa od maxima k minimu, pak skoci zpet:
Column phase (pos mod 16): 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
W+R typicka hodnota: 9 9 9 9 9 8 8 8 8 8 7 7 7 7 7 6
W+W typicka hodnota: 3 3 5 5 5 5 5 5 4 4 4 4 4 3 3 3
Na fazich 0-2 a 15 dochází k přechodu min->max, kde realna hodnota kolisa v sirsim rozsahu (napr. col 0 W+R: [6,7,9]).
Na fazich 3-14 je TW urceno prevazne column fázi (+-1 TW). Na fazich 5 (W+W=5), 7 (W+R=8), 10 (W+W=4) a 12 (W+R=7) je hodnota úplně stabilní (nulovy rozptyl).
// 80-prvkova lookup tabulka (indexovano pozici WRITE v radku)
static const uint8_t tw_wr[80] = {
9,6,9,9,9,8,8,8,8,8,7,7,7,7,7,6,
6,9,9,9,8,9,8,8,8,7,8,7,7,7,6,7,
9,9,6,9,9,8,8,8,8,8,7,7,7,7,7,9,
6,6,9,9,8,8,9,8,8,7,7,8,7,7,6,6,
7,9,9,8,9,9,8,8,7,8,8,7,7,6,7,7
};
static const uint8_t tw_ww[80] = {
3,3,5,6,5,5,5,4,5,4,4,4,3,4,3,3,
3,6,6,5,5,5,5,5,4,4,4,4,4,3,3,3,
6,3,5,5,6,5,5,4,4,5,4,4,3,3,4,3,
3,5,6,6,5,5,4,5,5,4,4,3,4,4,3,3,
6,6,3,5,5,5,5,5,4,4,4,4,4,3,3,6
};
int get_wait_tw(int write_clk0_pos, bool mode_640, bool second_is_write) {
int phase = write_clk0_pos % 80;
if (mode_640) phase = (phase + 16) % 80;
return second_is_write ? tw_ww[phase] : tw_wr[phase];
}
Poznámka: write_clk0_pos je pozice prvniho WRITE (T1r) v řádku.
V emulatoru kde sledujeme CLK0 čítač je to přímo hodnota čítače
v okamziku zahajeni zápisu.
Nedokumentovaný režim 0x03 ma stejnou délku horke fáze jako 320x200 (~32 CLK0). DRAM fetch pattern se ale liší — 0x03 používá 284 video čtení bez mystery reads (jako Frame B), zatímco 0x00/0x02 mají 78 video + 206 mystery. Delsi DRAM latence při visible free zápisu v 0x00/0x02 je zpusobena mystery reads, které v 0x03 chybí — proto 0x03 ma kratsí visible free latenci priblizne odpovídající 640x200 hodnotam.
Nedokumentovaný režim 0x07 ma identický DRAM fetch pattern jako 0x06 (182 video čtení, 0 mystery, 81 sloupců, shodné ČAS adresy). WAIT chování je identický s ostatnimi 640x200 režimy: - Horka fáze: ~17 CLK0 - W+R: 6-9 TW, W+W: 3-6 TW
Identický s MZ-700 textovym rezimem (DMD=0x08). WAIT se generuje pro adresy 0xC000-0xDFFF, viz 14-wait-nwtgd.md.
| DMD | Režim | Horka fáze | W+R | W+W | Mystery |
|---|---|---|---|---|---|
| 00H | 320/4c Frame A | 32 CLK0 | 6-9 TW | 3-6 TW | Ano (206) |
| 01H | 320/4c Frame B | 32 CLK0 | 6-9 TW | 3-6 TW | Ne |
| 02H | 320/16c | 32 CLK0 | 6-9 TW | 3-6 TW | Ano (206) |
| 03H | 320/nedok. | 32 CLK0 | 6-9 TW | 3-6 TW | Ne |
| 04H | 640/2c Frame A | 17 CLK0 | 6-9 TW | 3-6 TW | Ne |
| 05H | 640/2c Frame B | 17 CLK0 | 6-9 TW | 3-6 TW | Ne |
| 06H | 640/4c | 17 CLK0 | 6-9 TW | 3-6 TW | Ne |
| 07H | 640/nedok. | 17 CLK0 | 6-9 TW | 3-6 TW | Ne |
| 08H-0FH | MZ-700 text | do HBLN | ~89 TW | ~89 TW | — |
| Vlastnost | MZ-700 | MZ-800 |
|---|---|---|
| Adresový rozsah | 0xC000–0xDFFF | 0x8000–0xBFFF |
| READ penalizuje? | Ano (stejná logika jako WRITE) | Ne (RD_FF vychladne za 3 CLK0) |
| WRITE penalizuje? | Ano (do konce řádku) | Ano (17-32 CLK0) |
| WAIT po WRITE+READ | ~89 TW (do HBLN) | 6-9 TW |
| WAIT po WRITE+WRITE | ~89 TW (do HBLN) | 3-6 TW |
| Vliv pozice v řádku | Velky (brzsi = delsi WAIT) | Maly (~3 TW rozptyl) |
| Vliv WF/RF | Žádný | Žádný |
Simulace (HDL): Všechny hodnoty pochází z gate-level simulace
(GDG_core.vhd + cocotb testbenche test_mz800_propagation.py
a test_dmd_undocumented.py). Ověřeno:
- READ FF reset: ~3-4 CLK0 ve všech MZ-800 režimech (test_rdff_reset_period)
- WRITE FF reset: ~17 CLK0 (640x200), ~32 CLK0 (320x200) (test_reset_comparison)
- TW sweep na 201 pozicich CLK0 400-600: rozsahy 6-9 (W+R), 3-6 (W+W)
- TW rozsahy identické pro 320x200 i 640x200 (test_wr_period_sweep)
- Periodicita 80 CLK0 overena porovnanim pozic 400-479 vs 480-559 (identické)
- 640x200 vzorec = 320x200 vzorec rotovany o přesně 16 CLK0
- WF/RF registry bez vlivu (test_wf_rf_effect)
- Nedokumentované režimy 0x03 a 0x07: WAIT chování konzistentni
s odpovídajicimi oficialnimi režimy (test_cpu_wait_all_dmd)
Reálně HW: Ještě neověřeno.