[SharpMZ] zvlastni chovani PIO-Z80

Michal Hucik - ORDOZ ordoz na ordoz.com
Pondělí Leden 30 13:24:45 CET 2017


Ahoj,

pokracuji ve zkoumani obvodu. Nyni se metodou hazeni bomb do rybnika 
snazim zjistit co nastane, kdyz se deji veci, ktere se bezne 
nepredpokladaji. Napr. kdyz procesor v IM2 dostane interrupt, nicmene 
PIO v danou chvili zadny cekajici interrupt v zasobe nema, nebo jej sice 
ma, ale je zrovna potlacen.

BTW k potlaceni interruptu muze zrejme dojit alespon dvema zpusoby:

1) klasicky nastavenim disable interrupt (0x03) - tohle ovsem neni ani 
tak zakazani interruptu, ale spise jeho zneviditelneni. Pokud se v dobe, 
kdy je nastaveno "disable" odehraje nejaka udalost, ktera je schopna 
vyvolat interrupt, tak jej PIO ve sve interni logice normalne zpracuje a 
port prejde do specialniho stavu "interrupt pending" ze ktereho uz jej 
nedostane nic jineho, nez to, ze dojde ke zviditelneni cekajiciho 
interruptu (0x83) a pak musi nasledovat jeho prevzeti procesorem, ktery 
to na sbernici oznami aktivaci signalu /M1 + /IORQ. Dalsi moznosti jak 
se v PIO zbavit cekajiciho interruptu je 4. bit v ICRW viz bod 2, nebo 
HW reset procesoru, ktery si PIO umi identifikovat.


2) zapsanim Interrupt Control Word ( xxxx 0111 ) ve kterem je 4. bit 
nastaven "1" - tim dojde k okamzitemu smazani pripadneho cekajiciho 
interruptu. Nasledne se ceka na zapis masky, dokud ji nezapiseme, tak se 
PIO ke vsem udalostem chova jako mrtvy brouk a interrupt nikdy 
nezaeviduje. Ve chvili kdy zapiseme masku (treba i stejnou jaka byla 
predtim), tak se provede inicializace stavu - nazveme to treba interrupt 
state scan. Tento scan se provadi rovnez pri inicializaci MODE3 ve 
chvili, kdy vlozime bajt s I/O maskou a take ve chvili, kdy CPU prevezme 
interrupt, uz neni aktivni /INT, ale je aktivni /IEO, tzn.,  ze CPU 
prave zacalo vykonavat rutinu interruptu a jeste se na sbernici 
neobjevilo RETI.

Zadnym jinym zpusobem se jiz cekajiciho interruptu nezbavite. Nepomuze 
ani zmena stavu na sledovanych bitech/pinech. Ani zmena mode. Ani zmena 
interrupt function, ci urovne LOW/HIGH.

Dalsi zajimavost: pokud je interrupt function "OR" a maska je nastavena 
sledovani stavu vice nez jednoho bitu/pinu, tak PIO musi vzdy na vsech 
techto pinech nejprve zaregistrovat uplny klidovy stav. Do te doby, nez 
k nemu dojde, tak zadna zmenova udalost na pinech nevyvola interrupt.

Napr.:

1) nastavime ICRW: IENABLE, OR, HIGH, MASK => 10110111 => 0xb7
2) ocekava se maska - nastavme citlivost na dolni 4 bity: 0xf0

Dejme tomu, ze ve chvili, kdy byla vlozena maska, tak na stupnich pinech 
nebylo nic "0000" - klidovy stav.

1) Dojde k nejake zmene "0001" a ta vyvola interrupt - PIO je ve stavu 
interrupt pending a zadne dalsi zmeny na pinech jej nezajimaji.
2) CPU prevezme interrupt - provede se scan stavu "0001"
3) V dobe kdy jeste neprislo RETI nastane dalsi zmena "0000" a za ni 
bude nasledovat treba "0010" - PIO prejde do stavu, ktery je podobny 
tomu "interrupt pending" s potlacenym int.
4) Ve chvili, kdy prijde RETI, tak PIO prejde do viditelneho "interrupt 
pending"... pomerne castou praktikou je zakoncovat rutinu sequenci EI, 
RETI a tak vlastne okamzite po RETI nasleduje opetovny skok na zacatek 
prerusovaci rutiny - pokud se to opakuje, tak se vlastne vubec 
nevykonava program, ale jen interrupti rutina (par takto fungujicich 
programu jsem na Sharpu videl)

Ovsem muze byt i takovyto vyvoj:

1) Dojde k nejake zmene z "0000" na "0001" a ta vyvola interrupt, ktery 
je procesorem prijat
2) V dobe kdy jeste neprislo RETI nastane dalsi zmena "0011" a treba "1010"
3) Ve chvili, kdy prijde RETI, tak PIO prejde do rezimu, kdy stale ceka 
na klidovy stav a urovne na sledovanych pinech mohou divocit jak chteji, 
dokud nenastane "0000", tak tohle radeni zadny dalsi interrupt nevyvola


Jak uz jsem na zacatku psal, tak se nyni snazim vyzkoumat neco ohledne 
zpracovani IM2 callbacku, ktery nema z pohledu PIO opodstatneni. V 
priloze je testovaci zdrojak, kterym si nejprve nastavim CTC, i8255 a 
PIOZ80. Nasledne jsem schopen zavolat interrupt iniciovany od CTC2, nebo 
kteroukoliv z bran A/B v PIOZ80.

Pokud je procesor v IM2 a vygeneruju interrupt z CTC2, tak se na 
sbernici ocekava LSB cast interrupt vektoru na kterem je ulozena adresa 
prerusovaci rutiny.
Pole s vektory jsem si ulozil od adresy 0x3000. Jeho rozptyl jde od 0x00 
- 0x100. Kdyz mam popsano cele pole vektoru hodnotou 0x00, tak musi IM2 
interrupt vykonat vzdy CALL 0x0000. Na teto adrese mam kod pro nastaveni 
modreho borderu a zastaveni programu.
Postupnym repisovanim obsahu v poli vektoru jsem zjistil, ze takto 
ziskany LSB je sice nejake hausnumero, NICMENE jak se zda, tak pro danou 
konfiguraci je toto ziskane cislo vzdy konstantni, coz mi prijde zajimave.
V kodu, ktery je v priloze je to hodnota 0x20, coz zpusobi, ze propgram 
konci s cervenym borderem. Prozatim jeste nevim jaky hazard tuto 
magickou hodnotu zpusobuje - vzpomente treba na magickou hodnotu 
posledniho bajtu, kterou prectete z datovky, kdyz se pokusite cist z 
nepripojeneho portu. Cislo v ziskane LSB se zmeni, kdyz realokuju cely 
program, ci zmenim nastaveni PIO. Parkrat se mi stalo, ze jsem obdrzel 
hodnotu, ktera odpovidala vectoru z brany A - mohlo se jednat i o 
nahodu, nicmene ted mne napada, ze tohle budu umet lehce proverit.

Pri experimentovani s polem vektoru a s takto nahodne ziskanym LSB se 
muze stat samozrejme i to, ze se strefi jen jeden bajt z vektoru, 
program se nekam vykoleji, nicmene nejakym zazrakem se dostane k rutine 
se zmenou barvy borderu. K odhaleni takoveho stavu mam na zacatku 
programu cca 10s wait s cernymi pruhy v borderu. V tech 10s si zapnu 
analyzer, ktery mi pak ukaze co se delo, kdyz prisel interrupt. Pokud se 
vykonalo jen par instukci a pak prislo /IORQ (border: 0x06cf) a HALT, 
ktery je lehce identifikovatelny, tak sel program spravnou cestou. Pokud 
vsak vidim, ze po prijeti INT se na sbernici vykonavalo more ruznych 
instrukci, tak to znamena, ze se vektor strefil jen do jednoho bajtu a 
program se vykolejil.

Pokud se vam bude chtit, tak vyzkousejte na Sharpu prilozeny MZF, 
pripadne si s pasmo nakompilujte vlastni. Pokud vam program skonci s 
cervernym borderem, tak je pravdepodobne, ze se u vas choval stejne jako 
u mne (pripadne ze se jen sikovnym zpusobem vykolejil :)

Michal
------------- další část ---------------

pio_pa_ctrl:    equ 0xfc
pio_pb_ctrl:    equ 0xfd
pio_pa_data:    equ 0xfe
pio_pb_data:    equ 0xff

pio_ctrl:    equ pio_pa_ctrl
pio_data:    equ pio_pa_data


prgstrtaddr: equ 0x2000

vectorarea:  equ 0x3000

msb_vector:  equ (vectorarea >> 8)

none_lsb_vector:   equ 0x20
pa_lsb_vector:   equ 0x50
pb_lsb_vector:   equ 0x60


    org ( prgstrtaddr - 0x80 )
    db  0x01
    ; 16 znaku + 0x0d
    db  "IM2 TEST        "
    db 0x0d
    dw (prgend - prgstart) ; size
    dw prgstart ; start
    dw prgstart ; exec

    org prgstrtaddr

prgstart:
    ; inicializace MZ800
    di
    im 2

    ld a,0x00 ; mz800 320x200 na 4A
    out (0xce),a

    ; dolni RAM
    out (0xe0),a

    ; inicializace CTC0
    ;call ctc0_out1
    ;call ctc0_out0
    call pio_pa4_0
;    call pio_pa4_1

    ; inicializace CTC2
    call ctc2_out0

    ; inicializujeme ruseni z 8255
    call pio8255_init

; zkusime vynechat inicializaci PIO-Z80
if 1
    ; PIO-Z80 - PA reset
    xor a
    out (pio_pa_data), a
    ld c,pio_pa_ctrl
    call pioz80_reset

    ; PIO-Z80 - PB reset
    xor a
    out (pio_pb_data), a
    ld c,pio_pb_ctrl
    call pioz80_reset
endif

    ; horni cast interrupt vectoru
    ;ld a,0x30
    ld a,msb_vector
    ld i,a

    ; PIO-Z80 vector
    ld a,0x50
    out (pio_pa_ctrl),a
    ld a,0x60
    out (pio_pb_ctrl),a

    ; povolime ruseni z PIO-Z80
    ld a,0x83
    ; zakazeme ruseni z PIO-Z80
;    ld a,0x03
    out (pio_pa_ctrl),a
    out (pio_pb_ctrl),a

    ; pripravime si prostor s vectory vsude 0x0000
    ld hl,vectorarea
    push hl
    pop de
    inc de
    xor a
    ld (hl),a
    ld bc,0x0100
    ldir

    ; na 0x0000: jp bordint1
    ld hl,bordint1
    ld a,0xc3
    ld ix,0x0000
    ld (ix + 0), a
    ld (ix + 1), l
    ld (ix + 2), h

; pokud tuto cast vynechame, tak vsechny vectory vedou na adresu 0x0000 (modry border)
if 1
    ; kdyz nam nikdo neda vector, tak se cte z adresy 0x..20 (proc???)
    ;
    ; cerveny border
    ld hl,bordint2
    ld ix,vectorarea + none_lsb_vector
    ld (ix + 0), l
    ld (ix + 1), h

    ; vector PIO-Z80 PA
    ;
    ; fialovy border
    ld hl,bordint3
    ld ix,vectorarea + pa_lsb_vector
    ld (ix + 0), l
    ld (ix + 1), h

    ; vector PIO-Z80 PB
    ;
    ; zeleny border
    ld hl,bordint4
    ld ix,vectorarea + pb_lsb_vector
    ld (ix + 0), l
    ld (ix + 1), h
endif

    ; dame si cas na spusteni sigma analyzeru
    call wait

    ; spousteci trigger analyzeru
    ld a, 0x00
    out (pio_pa_data), a
    out (pio_pb_data), a

    ei

if 0
    ; spustit INT z CTC0 (pres PIO-Z80 PA4 - pokud je povoleno)
    nop
    call pio_pa4_1
    call pio_pa4_0
    nop
endif

if 0
    ; spustit INT z PIO-Z80 PA
    nop
    ld a,0xff
    out (pio_pa_data),a

;    call pio_pa4_0
;    call pio_pa4_1

;    ld a,0x00
;    out (pio_pa_data),a
;    ld a,0xff
;    out (pio_pa_data),a

;    call pio_pa4_0
;    call pio_pa4_1

    nop
endif

if 0
    ; spustit INT z PIO-Z80 PB
    nop
    ld a,0xff
    out (pio_pb_data),a
    nop
endif

if 1
    ; spustit INT z CTC2
    nop
    call ctc2_out1
    call ctc2_out0
    nop
endif


stop:
    di
    halt

bordint1:
    ld a,0x01   ; modra
    jr setborder
bordint2:
    ld a,0x02   ; cervena
    jr setborder
bordint3:
    ld a,0x03   ; fialova
    jr setborder
bordint4:
    ld a,0x04   ; zelena
setborder:
    ld bc,0x06cf
    out (c),a
    di
    halt


wait:
    ld bc,0x06cf
    ld de,0x0000
    ld l,0x10 ; necelych 10 sekund
    xor a
wait_loop:
    cpl
    out (c), a
    dec e
    jr nz,wait_loop
    dec d
    jr nz,wait_loop
    dec l
    jr nz,wait_loop
    ret


;
; Celou branu nastavime do MODE3-OUT a interrupt povolime na vsechny piny.
; Interrupt budeme spoustet pomoci data output registru.
; Klidovy stav: 0x00
; Interrupt: cokoliv co neni 0x00
;
pioz80_reset:
;    xor a ; pokud se cekalo na masku, tak dokoncujeme jeji zapis, jinak nastavujeme vector
;    out (c),a
    ld a,0xcf ; mode3 + vsechny piny vystupni
    out (c),a
;    ld a,0x3f
    ld a,0x00
    out (c),a
    ld a,0xb7 ; povol ruseni, OR, HIGH, reset aktualnich preruseni + zapnuti sledovani vsech pinu
    out (c),a
;    ld a,0x6f
    ld a,0x00
    out (c),a
    ret

;
; v i8255 povolime volani interruptu z CTC2
;
pio8255_init:
    ld a,0x8a ; MODE0, PortA: out, PortC_up: in, PortB: in, PortC_down: out
    out (0xd3), a
    ld a, 0x05
    out (0xd3), a
    ret

ctc0_out0:
    ld a,0x30 ; CTC0, MODE0, LSB + MSB
    jr ctc_ctrl_wr
ctc0_out1:
    ld a,0x32 ; CTC0, MODE1, LSB + MSB
    jr ctc_ctrl_wr
ctc2_out0:
    ld a,0xb0 ; CTC2, MODE0, LSB + MSB
    jr ctc_ctrl_wr
ctc2_out1:
    ld a,0xb2 ; CTC2, MODE1, LSB + MSB
ctc_ctrl_wr:
    out (0xd7),a
    ret

; vystup z CTC0 do PIOZ80 PA4 je invertovany
pio_pa4_0:  equ ctc0_out1
pio_pa4_1:  equ ctc0_out0

prgend:
------------- další část ---------------
Netextová příloha byla odstraněna...
JmĂŠno: im2test.mzf
Typ: application/octet-stream
Velikost: 356 bytes
Popis: [Şådný popis není k dispozici]
Url : http://mail.ordoz.com/pipermail/sharpmz/attachments/20170130/b7fa8d19/attachment.obj 


Další informace o konferenci SharpMZ