Intel 8080 kit

Kącik dla elektroniki retro - układy, urządzenia, podzespoły, literatura itp.
tapy
User
User
Posty: 139
Rejestracja: niedziela 14 kwie 2019, 17:09
Kontaktowanie:

Re: Intel 8080 kit

Postautor: tapy » poniedziałek 12 paź 2026, 17:02

Bardziej miałem na myśli pełne 16-bit, więc osobiście poszedłbym w stronę V50, bo jeszcze jest dostępny (V40 też niczego sobie, to taki V20 na sterydach). Dlaczego taki kaprys? Optymalizuję port Basic z Z80 na Z8000, męcząc "testem" Mandelbrot i po zmianach wyszło mi, że Z8002 taktowany 6MHz deklasuje V20 z zegarem 10MHz zarówno w trybie 8080 jak i x86. Dlatego chcę sprawdzić czy to jest wina 8-bitowej szyny, czy te procesory są naprawdę aż tak "biedne", czy może moja optymalizacja jest lepsza, niż oryginalny soft Microsoft na x86. To dużo pytań, bez odpowiedzi.

Awatar użytkownika
Zegar
User
User
Posty: 347
Rejestracja: wtorek 02 lip 2019, 14:42

Re: Intel 8080 kit

Postautor: Zegar » poniedziałek 12 paź 2026, 18:41

tapy pisze:Bardziej miałem na myśli pełne 16-bit, więc osobiście poszedłbym w stronę V50, bo jeszcze jest dostępny (V40 też niczego sobie, to taki V20 na sterydach).

V50 to już mikrokontroler z peryferiami w środku. Odpowiednikiem 8086 jest V30. Mam nawet płytę z PC/XT z tym procesorem. Fajnie byłoby znowu się pobawić. Niestety padła mi klawiatura XT, więc jest mały kłopot. ;)
"If A = success, then the formula is A = X + Y + Z.
X is work. Y is play. Z is keep your mouth shut."
A. Einstein

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1345
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Intel 8080 kit

Postautor: gaweł » środa 14 paź 2026, 21:45

ik8080_il41.png


Obsługa układu 8255

Wspomniany układ jest bardzo popularnym programowalnym portem równoległym. Zawiera w sobie dwa porty PORTA oraz PORTB jako porty 8-bitowe, które można skonfigurować do pracy jako wejście albo jako wyjście (oba w sposób niezależny). Do tego dochodzi kolejny port (PORTC), który może być podzielony na dwa 4-bitowe, z których każda połówka ma możliwość niezależnego skonfigurowania kierunku pracy. Dodatkowo istnieje możliwość manipulowania pojedynczymi bitami PORTC. Nad tym wszystkim „panuje” rejestr sterujący: zapisy do tego rejestru definiują tryb i kierunek pracy jak również odpowiednie zapisy manipulują pojedynczymi bitami (w zakresie ustawienia na stan jedynki jak i zera). Te dwa podstawowe rodzaje poleceń są rozróżniane jednym bitem w wysyłanych do portu kontrolnego danych: najbardziej znaczący bit = 1 to zapis dotyczący trybu i kierunku pracy wszystkich portów. W sytuacji gdy ten bit = 0, zapis dotyczy ustawienia/zerowania wskazanego bitu PORTC. Ta cecha została wykorzystana w obsłudze alfanumerycznego wyświetlacza LCD jak i do obsługi klawiatury. PORTA i połowa PORTC obsługuje moduł LCD, PORTB i druga połowa PORTC obsługuje klawiaturę matrycową. W przypadku modułu LCD, kierunek pracy PORTA jest konfigurowany w zależności od potrzeb (zapis danych oraz poleceń do LCD to wyjście, odczyt statusu LCD to wejście). Dolna połowa PORTC obsługuje linie sterujące LCD (RS, RW i E). Do obsługi klawiatury, PORTB jest wczytującym stan kolumn klawiatury (zawsze wejściem) oraz druga połowa PORTC wymusza stan na liniach rzędów klawiatury (zawsze wyjściem).
ik8080_il42.png

Konfiguracja portów to zapis mvi a , 080h + P8255A_out… , gdzie zawsze jest ustawiony najbardziej znaczący bit (80h) i definiuje kierunki pracy portów w zależności od potrzeb. Port 8255 jest identyfikowany w systemie przez adresy w przestrzeni adresowej IO (LCDPort i KBDPort mają ten sam adres, a istnienie dwóch identyfikatorów zwiększa jedynie czytelność programu źródłowego).

Kod: Zaznacz cały

LCDPort                 .equ    0A0h
KBDPort                 .equ    0A0h

( . . . )

P8255PortA              .equ    0
P8255PortB              .equ    1
P8255PortC              .equ    2
P8255Control            .equ    3


Kod: Zaznacz cały

P8255A_out              .equ    0000000b
P8255A_inp              .equ    0010000b
P8255B_out              .equ    0000000b
P8255B_inp              .equ    0000010b
P8255CL_out             .equ    0000000b
P8255CH_out             .equ    0000000b
P8255CL_inp             .equ    0000001b
P8255CH_inp             .equ    0001000b

( . . . )

SetLCDOutputDataBus                        ;procedure SetLCDOutputDataBus ;
                                           ;begin (* SetLCDOutputDataBus *)
                                           ; LCDPort.PortA := <output> ;
        mvi     a , 080h + P8255A_out + P8255B_inp + P8255CL_out + P8255CH_out
        out     LCDPort + P8255Control     ;
        ret                                ;end (* SetLCDOutputDataBus *) ;
;*******************************************
SetLCDInputDataBus                         ;procedure SetLCDInputDataBus ;
                                           ;begin (* SetLCDInputDataBus *)
                                           ; LCDPort.PortA := <input> ;
        mvi     a , 080h + P8255A_inp + P8255B_inp + P8255CL_out + P8255CH_out
        out     LCDPort + P8255Control     ;
        ret                                ;end (* SetLCDInputDataBus *) ;

Linie sterujące modułem LCD (RS, RW i E) są obsługiwane przez połowę PORTC (jako wyjście) jako niezależne sterowaniu odpowiednimi liniami.
ik8080_il43.png

Kod: Zaznacz cały

SetLCDEBit              .equ    00000101b
ClrLCDEBit              .equ    00000100b
SetLCDRWBit             .equ    00000011b
ClrLCDRWBit             .equ    00000010b
SetLCDRSBit             .equ    00000001b
ClrLCDRSBit             .equ    00000000b

( . . . )

EPulse                                     ;procedure EPulse ;
                                           ;begin (* EPulse *)
        mvi     a , SetLCDEBit             ; LCDPort.PortC[E]:= 1 ;
        out     LCDPort + P8255Control     ;
        call    LCDDelay                   ; LCDDelay ;
        mvi     a , ClrLCDEBit             ; LCDPort.PortC[E]:= 0 ;
        out     LCDPort + P8255Control     ;
        ret                                ;end (* EPulse *) ;
;*******************************************
LCDOutC                                    ;procedure LCDOutC ( Data[A] : byte ) ;
                                           ;begin (* LCDOutC *)
        push    psw                        ;
        call    SetLCDOutputDataBus        ; SetLCDOutputDataBus ;
        mvi     a , ClrLCDRSBit            ; LCDPort.PortC[RS]:= 0 ;
        out     LCDPort + P8255Control     ;
        mvi     a , ClrLCDRWBit            ; LCDPort.PortC[RW]:= 0 ;
        out     LCDPort + P8255Control     ;
        pop     psw                        ;
        out     LCDPort + P8255PortA       ; LCDPort.PortA := Data ;
        call    EPulse                     ; EPulse ;
        ret                                ;end (* LCDOutC *) ;

Jeżeli chodzi o klawiaturę, to cyklicznie w przerwaniach od czasu poszukiwany jest naciśnięty klawisz. Po wymuszeniu stanu na liniach rzędów wczytywany jest stan kolumn.

Kod: Zaznacz cały

HardvSetRowKbd                             ;procedure HardvSetRowKbd ( Row[A] : byte ) ;
                                           ;begin (* HardvSetRowKbd *)
                                           ; case KbdModInstance.RowCounter of
        lda     KbdModInstance + KbdModInstanceT.RowCounter
        cpi     0                          ;  0 :
        jnz     HvdSeRSrv_1                ;
        mvi     a , 00001000b              ;   KBDPort.PortC[4] := 0 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001011b              ;   KBDPort.PortC[5] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001101b              ;   KBDPort.PortC[6] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001111b              ;   KBDPort.PortC[7] := 1 ;
        out     KBDPort + P8255Control     ;
        jmp     HvdSeRSrv_0                ;
HvdSeRSrv_1                                ;
        cpi     1                          ;  1 :
        jnz     HvdSeRSrv_2                ;
        mvi     a , 00001001b              ;   KBDPort.PortC[4] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001010b              ;   KBDPort.PortC[5] := 0 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001101b              ;   KBDPort.PortC[6] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001111b              ;   KBDPort.PortC[7] := 1 ;
        out     KBDPort + P8255Control     ;
        jmp     HvdSeRSrv_0                ;
HvdSeRSrv_2                                ;
        cpi     2                          ;  2 :
        jnz     HvdSeRSrv_3                ;
        mvi     a , 00001001b              ;   KBDPort.PortC[4] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001011b              ;   KBDPort.PortC[5] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001100b              ;   KBDPort.PortC[6] := 0 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001111b              ;   KBDPort.PortC[7] := 1 ;
        out     KBDPort + P8255Control     ;
        jmp     HvdSeRSrv_0                ;
HvdSeRSrv_3                                ;
        cpi     3                          ;  3 :
        jnz     HvdSeRSrv_4                ;
        mvi     a , 00001001b              ;   KBDPort.PortC[4] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001011b              ;   KBDPort.PortC[5] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001101b              ;   KBDPort.PortC[6] := 1 ;
        out     KBDPort + P8255Control     ;
        mvi     a , 00001110b              ;   KBDPort.PortC[7] := 0 ;
        out     KBDPort + P8255Control     ;
        jmp     HvdSeRSrv_0                ;
HvdSeRSrv_4                                ; end (* case *) ;
HvdSeRSrv_0                                ;
        ret                                ;end (* HardvSetRowKbd *) ;

( . . . )

HardvInpKbd                                ;function HardvInpKbd : byte[A] ;
                                           ;begin (* HardvInpKbd *)
        in      KBDPort + P8255PortB       ; HardvInpKbd := KBDPort.PortB ;
        ret                                ;end (* HardvInpKbd *) ;


ik8080_il44.png
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse

Awatar użytkownika
gaweł
Geek
Geek
Posty: 1345
Rejestracja: wtorek 24 sty 2017, 22:05
Lokalizacja: Białystok

Re: Intel 8080 kit

Postautor: gaweł » poniedziałek 19 paź 2026, 23:02

ik8080_il51.png


Obsługa układu 8250

8250 to układ obsługi transmisji szeregowej z wbudowanym wewnątrz generatorem sygnału taktującego transmisją. Zawiera wewnątrz również podzielnik by uzyskać oczekiwaną prędkość transmisji. W obecnym zastosowaniu układ obsługuje jedynie przesyłanie danych (operowanie liniami modemowymi nie jest aktywowane → wejściowe dla 8250 na schemacie są sprzętowo wysterowane do stanu aktywnego). Nie zaistnieje możliwość zgłoszenia przerwania w wyniku zmian tych linii modemowych (poza tym programowo konfiguruje się ten kontroler jakie generuje on generuje).
ik8080_il52.png

Przed rozpoczęciem transmisji należy go odpowiednio skonfigurować. Realizuje to funkcja UARTHardwareInit z jednym parametrem, gdzie do akumulatora należy wpisać podzielnik determinujący prędkość transmisji (dla 9600 bps wynosi on 12). Dodatkowo należy wyczyścić kolejki FIFO nadajnika oraz odbiornika.

Kod: Zaznacz cały

SerialSpeed9600         .equ    12
( . . . )
     mvi  a , SerialSpeed9600 ; UARTHardwareInit ( SerialSpeed9600 ) ;
     call UARTHardwareInit    ;
     call ResetSerialFifo     ; ResetSerialFifo ;
( . . . )
ResetSerialFifo               ;procedure ResetSerialFifo ;
                              ;begin (* ResetSerialFifo *)
     mvi     a , 0            ; UARTReciev . CycFr := 0 ;
     sta     UARTReciev + RXDRecT.CycFr
     sta     UARTReciev + RXDRecT.CycTo
                              ; UARTReciev . CycTo := 0 ;
     sta     UARTTransm + TXDRecT.CycFr
                              ; UARTTransm . CycFr := 0 ;
     sta     UARTTransm + TXDRecT.CycTo
                              ; UARTTransm . CycTo := 0 ;
     mvi     a , IdleState    ; UARTTransm . State := IdleState ;
     sta     UARTTransm + TXDRecT.State
     ret                      ;end (* ResetSerialFifo *) ;

Zainicjowanie kontrolera 8250 do pracy wymaga wpisania podzielnika prędkości, trybu transmisji, ustawienia wyjściowych linii modemowych oraz określenia jakie przerwania są zgłaszane do 8259. Układ jest 7-komórkowy w przestrzeni adresowej, toteż poszczególne rejestry mają indywidualne adresy w obrębie 8250. Wpisanie podzielnika jest trochę „pokrętne”: w pierwszej kolejności należy wpisać do rejestru sterującego LineControlRegister (ten sam, który służy do określenia trybu transmisji) liczbę 80 hex (ma być ustawiony najbardziej znaczący bit). W kolejnym kroku wpisać do DataRegister (ten sam, do którego wysyła się i odbiera dane szeregowe) część młodszą podzielnika oraz do InterruptEnRegister (ten sam, w którym specyfikuje się generowane przerwania) część starszą (ogólnie podzielnik jest 16-bitowy a do uzyskania prędkości 600 .. 115200 bps jest on jednobajtowy). Później konfiguruje się tryb transmisji, tu używany jest N81 → 8 bitów, bez parzystości i jednym bitem stopu (słowo sterujące w żadnej kombinacji nie zawiera ustawionego najwyższego bitu, więc 8250 nie rozpozna tego zapisu jako późniejszy wpis podzielnika). Przed włączeniem przerwań warto wygarnąć z rejestrów śmieci (aktywacja może spowodować natychmiastowe wygenerowanie przerwania). Na koniec wpis do rejestru InterruptEnRegister określa jakie przerwania generuje 8250 (tu są od nadajnika oraz odbiornika).

Kod: Zaznacz cały

DataRegister            .equ    0
InterruptEnRegister     .equ    1
InterruptIdRegister     .equ    2
LineControlRegister     .equ    3
ModemControlRegister    .equ    4
LineStatusRegister      .equ    5
ModemStatusRegister     .equ    6
( . . . )
N81Mode                 .equ    03h
( . . . )
UARTHardwareInit         ;procedure UARTHardwareInit
                                     ( SerialSpeed[a] : byte ) ;
                         ;begin (* UARTHardwareInit *)
        push    psw      ;
                         ; (* ustawienie w UART rozszerzenia
                         ;   adresowego do zaprogramowania predkosci *)
        mvi     a , 80h  ; Serial8250+LineControlRegister := 80h ;
        out     Serial8250 + LineControlRegister
                         ; (* mlodszy bajt podzielnika predkosci *)
        pop     psw      ; Serial8250+DataRegister := SerialSpeed ;
        out     Serial8250 + DataRegister  ;
                         ; (* starszy bajt podzielnika predkosci *)
        mvi     a , 0    ; Serial8250+InterruptEnRegister := 0 ;
        out     Serial8250 + InterruptEnRegister
                         ; (* zaprogramowania trybu N81Mode *)
        mvi     a , N81Mode
                         ; Serial8250+LineControlRegister := N81Mode ;
        out     Serial8250 + LineControlRegister
                         ; (* zaprogramowania stanu linii modemowych→
                         ;    wszystkie do stanu aktywnego *)
        mvi     a , 0bh  ; Serial8250+ModemControlRegister := 0BH ;
        out     Serial8250 + ModemControlRegister
                         ; (* wygarniecie smieci z roznych rejestrow *)
                         ; ? := Serial8250 + LineStatusRegister ;
        in      Serial8250 + LineStatusRegister
                         ; ? := Serial8250 + ModemControlRegister ;
        in      Serial8250 + ModemControlRegister
                         ; ? := Serial8250 + DataRegister ;
        in      Serial8250 + DataRegister
                         ; ? := Serial8250 + InterruptIdRegister ;
        in      Serial8250 + InterruptIdRegister
                         ; (* zezwolenie dla UART na przerwania od:
                         ;    nadajnik + odbiornik *)
        mvi     a , 03h  ; Serial8250 + InterruptEnRegister ; := 03H ;
        out     Serial8250 + InterruptEnRegister
        ret              ;end (* UARTHardwareInit *) ;

Układ 8250 zgłasza jeden sygnał przerwania (do 8259), jednak by rozpoznać przyczynę przerwania należy wczytać rejestr InterruptIdRegister, gdzie na bitach jest określona przyczyna przerwania. Obsługa przerwania to:

Kod: Zaznacz cały

SerialInterruptService         ;ISR SerialInterruptService ;
                               ; var
                               ;   IIR     : byte ;
                               ;   Port    : byte ;
                               ;begin (* SerialInterruptService *)
        push    psw            ;
        push    b              ;
        push    d              ;
        push    h              ;
SerIntSrv_0                    ; repeat
                               ;  IIR := Serial8250+InterruptIdRegister & 07h ;
        in      Serial8250 + InterruptIdRegister
        ani     07h            ;  if ( IIR & 0x01 ) = 0 then
        cpi     1              ;
        jz      SerIntSrv_5    ;   begin
        rrc                    ;    IIR := IIR >> 1 ;
        ani     03h            ;
                               ;    case IIR of
        cpi     0              ;     0 : (* 0 0 - Modem status *)
        jnz     SerIntSrv_1    ;
                               ;      Port := Serial8250 + ModemStatusRegister ;
        in      Serial8250 + ModemStatusRegister
        jmp     SerIntSrv_0    ;
SerIntSrv_1                    ;     1 : (* 0 1 - transmitter *)
        cpi     1              ;
        jnz     SerIntSrv_2    ;
        lda     UARTTransm + TXDRecT.CycFr
                               ;      if UARTTransm.CycFr = UARTTransm.CycTo then
        lxi     h , UARTTransm + TXDRecT.CycTo
        cmp     m              ;
        jnz     SerIntSrv_11   ;
        mvi     a , IdleState  ;       UARTTransm.State := IdleState ;
        sta     UARTTransm + TXDRecT.State
        jmp     SerIntSrv_0    ;
SerIntSrv_11                   ;      else
                               ;       begin
        lda     UARTTransm + TXDRecT.CycFr
                               ;        Serial8250+DataRegister:= UARTTransm.Buffer[UARTTransm.CycFr] ;
        mov     c , a          ;
        mvi     b , 0          ;
        lxi     h , UARTTransm + TXDRecT.Buffer
        dad     b              ;
        mov     a , m          ;
        out     Serial8250 + DataRegister
                               ;        UARTTransm.CycFr:= UARTTransm.CycFr+1 ;
        lxi     h , UARTTransm + TXDRecT.CycFr
        mov     a , m          ;
        inr     a              ;
        ani     TXDBuffSize - 1;        UARTTransm.CycFr:=UARTTransm.CycFr mod TXDBuffSize ;
        mov     m , a          ;
        jmp     SerIntSrv_0    ;       end ;
SerIntSrv_2                    ;
        cpi     2              ;     2 : (* 1 0 - reciever *)
        jnz     SerIntSrv_3    ;      begin
        lda     UARTReciev + RXDRecT.CycTo
                               ;       UARTReciev.Buffer[UARTReciev.CycTo]:= Serial8250+DataRegister ;
        mov     c , a          ;
        mvi     b , 0          ;
        lxi     h , UARTReciev + RXDRecT.Buffer
        dad     b              ;
        in      Serial8250 + DataRegister
        mov     m , a          ;
                               ;       UARTReciev.CycTo:=UARTReciev.CycTo+1 ;
        lxi     h , UARTReciev + RXDRecT.CycTo
        mov     a , m          ;
        inr     a              ;
        ani     RXDBuffSize - 1;       UARTReciev.CycTo:=UARTReciev.CycTo mod RXDBuffSize ;
        mov     m , a          ;
        jmp     SerIntSrv_0    ;      end ;
SerIntSrv_3                    ;
        cpi     3              ;     3 : (* 1 1 - error *)
        jnz     SerIntSrv_0    ;
                               ;       Port := Serial8250 + LineStatusRegister ;
        in      Serial8250 + LineStatusRegister
        jmp     SerIntSrv_0    ;    end (* case *) ;
                               ;   end
                               ;  else
                               ;   exit ;
                               ; until false ;
SerIntSrv_5                    ;
        mvi     a , 20h        ; end of irq
        out     Controller8259 ;
        pop     h              ;
        pop     d              ;
        pop     b              ;
        pop     psw            ;
        ei                     ;
        ret                    ;

Kontroler transmisji szeregowej opiera się o kolejki FIFO w zakresie nadawania oraz odbierania danych. Ich konstrukcje są następujące:

Kod: Zaznacz cały

IdleState       .equ        0
BusyState       .equ        1
;-------------------------------------------
TXDBuffSize     .equ        128
RXDBuffSize     .equ        16
;-------------------------------------------
TXDRecT         .struct           ; TXDRecT = record
        CycFr   .byte             ;    CycFr  : byte ;
        CycTo   .byte             ;    CycTo  : byte ;
        State   .byte             ;    State  : byte ;
        Buffer  .byte TXDBuffSize ;    Buffer : array [ 0 .. TXDBuffSize - 1 ] of byte ;
                .endstruct        ;  end (* record *) ;
;-------------------------------------------
RXDRecT         .struct           ; RXDRecT = record
        CycFr   .byte             ;    CycFr  : byte ;
        CycTo   .byte             ;    CycTo  : byte ;
        Buffer  .byte RXDBuffSize ;    Buffer : array [ 0 .. RXDBuffSize - 1 ] of byte ;
                .endstruct        ;  end (* record *) ;
;-------------------------------------------
( . . . )
        .org    RAMSpace
UARTTransm      .TXDRecT
UARTReciev      .RXDRecT

Odbiór danych z 8250 wchodzi do UARTRecv bezwarunkowo (najwyżej dane się nadpiszą), realizacja znajduje się w powyższej funkcji obsługi przerwania. Z tą kolejką FIFO związane są dwie funkcja: sprawdzenia, czy w FIFO są dane do odczytania (SerialDataPresent) oraz odczytanie kolejnego bajtu (GetSerial).

Kod: Zaznacz cały

SerialDataPresent              ;function SerialDataPresent : boolean ;
                               ;begin (* SerialDataPresent *)
                               ; if UARTTransm.CycFr = UARTTransm.CycTo then
        lxi     h , UARTTransm + TXDRecT.CycFr
        mov     a , m          ;
        lxi     h , UARTTransm + TXDRecT.CycTo
        cmp     m              ;
        jnz     SerDatPre_0    ;
        mvi     a , 0          ;  SerialDataPresent := false
        ret                    ; esle
SerDatPre_0                    ;
        mvi     a , 1          ;  SerialDataPresent := true ;
        ret                    ;end (* SerialDataPresent *) ;
;*******************************
GetSerial                      ;function GetSerial : byte[a] ;
                               ;var
                               ; Ch[e] : byte ;
                               ;begin (* GetSerial *)
                               ; Ch:=UARTTransm.Buffer[UARTTransm.CycFr] ;
        lda     UARTTransm + TXDRecT.CycFr
        mov     c , a          ;
        mvi     b , 0          ;
        lxi     h , UARTTransm + TXDRecT.Buffer
        dad     b              ;
        mov     e , m          ;
                               ; UARTTransm.CycFr:=(UARTTransm.CycFr+1) mod RXDBuffSize ;
        lxi     h , UARTTransm + TXDRecT.CycFr
        mov     a , m          ;
        inr     a              ;
        ani     RXDBuffSize - 1;
        mov     m , a          ;
        mov     a , e          ; GetSerial := Ch ;
        ret                    ;end (* GetSerial *) ;

Nadawanie danych do 8250 jest realizowane przez SendSerial. Jeżeli UART nie pracuje, to pierwszy znak trafia bezpośrednio do 8250 (z odnotowaniem, że jest on już zajęty), kolejne dane trafiają do kolejki FIFO. Zawsze jest sprawdzane, czy jest miejsce w FIFO na zapis nowych danych. Jeżeli jest, następuje zapis do FIFO. W przeciwnym wypadku realizowane jest oczekiwanie do chwili, gdy w buforze pojawi się wolne miejsce (w wyniku wygarniania danych z tej kolejki przez obsługę przerwania).

Kod: Zaznacz cały

SendSerial                           ;procedure SendSerial ( SerialCh : byte ) ;
                                     ;var
                                     ; NextInx : byte ;
                                     ;begin (* SendSerial *)
        di                           ; DisableInt ;
        push    psw                  ;
                                     ; if UARTTransm . State = IdleState then
        lxi     h , UARTTransm + TXDRecT.State
        mov     a , m                ;
        cpi     IdleState            ;
        jnz     SeSer_1              ;  begin
        mvi     a , BusyState        ;   UARTTransm . State := BusyState ;
        mov     m , a                ;
        pop     psw                  ;
                                     ;   Serial8250 + DataRegister := SerialCh ;
        out     Serial8250 + DataRegister
        ei                           ;   EnableInt ;
        ret                          ;   exit ;
                                     ;  end ;
SeSer_1                              ; repeat
                                     ;  NextInx:=(UARTTransm.CycTo+1) mod TXDBuffSize ;
        lda     UARTTransm + TXDRecT.CycTo
        inr     a                    ;
        ani     TXDBuffSize - 1      ;
                                     ;  if NextInx <> UARTTrans . CycFr then
        lxi     h , UARTTransm + TXDRecT.CycFr
        cmp     m                    ;
        jz      SeSer_2              ;   begin
                                     ;    UARTTrans.Buffer[UARTTrans.CycTo]:=SerialCh ;
        lda     UARTTransm + TXDRecT.CycTo
        mov     c , a                ;
        mvi     b , 0                ;
        lxi     h , UARTTransm + TXDRecT.Buffer
        dad     b                    ;
        pop     psw                  ;
        mov     m , a                ;
                                     ;    UARTTransm.CycTo:=(UARTTransm.CycTo+1) mod TXDBuffSize ;
        lxi     h , UARTTransm + TXDRecT.CycTo
        mov     a , m                ;
        inr     a                    ;
        ani     TXDBuffSize - 1      ;
        mov     m , a                ;
        ei                           ;    EnableInt ;
        ret                          ;    exit ;
SeSer_2                              ;   end ;
        ei                           ;  EnableInt ;
        nop                          ;  Nop ;
        nop                          ;  Nop ;
        nop                          ;  Nop ;
        di                           ;  EisableInt ;
        jmp     SeSer_1              ; until false ;
                                     ;end (* SendSerial *) ;
( . . . )
SendSerialString                     ;procedure SendSerialString ( String[hl] : array of byte ) ;
                                     ;var
                                     ; Data : byte ;
                                     ; Inx  : byte ;
                                     ;begin (* SendSerialString *)
                                     ; Inx := 0 ;
SeSerStr_0                           ; repeat
        mov     a , m                ;  Data = String [ Inx ] ;
        inx     h                    ;  Inx := Inx + 1 ;
        cpi     0                    ;  if Data = 0 then
        jnz     SeSerStr_1           ;
        ret                          ;   exit ;
SeSerStr_1                           ;
        push    h                    ;
        call    SendSerial           ;  SendSerial ( Data ) ;
        pop     h                    ;
        jmp     SeSerStr_0           ; until false ;
                                     ;end (* SendSerialString *) ;

Prezentacja działania obsługi układu 8250 to:

Kod: Zaznacz cały

SerialHello   .defb  "Zestaw edukacyjny z procesorem Intel 8080", 0Dh, 0Ah, 0
( . . . )
   lxi     h , SerialHello    ; SendSerialString ( SerialHello ) ;
   call   SendSerialString    ;

I zadziałało:
ik8080_il53.png

Na obecnym etapie wiadomo, że cały zestaw jest technicznie sprawny (test pamięci RAM również przechodzi z tym samym algorytmem co w poprzedniej iteracji). Teraz zostało trochę potrudzić się nad „systemem operacyjnym”.
Nie masz wymaganych uprawnień, aby zobaczyć pliki załączone do tego posta.

Prawdziwe słowa nie są przyjemne. Przyjemne słowa nie są prawdziwe.
Lao Tse


Wróć do „Retro”

Kto jest online

Użytkownicy przeglądający to forum: Obecnie na forum nie ma żadnego zarejestrowanego użytkownika i 1 gość