Jelenleg az I/O port eseteben az aszinkron olvasas miatt egy kombinacios logikai halozat eredmenyet latja a CPU ugyanabban az orajel-ciklusban mint amikor ott omaga eloallitja a cimet. Ez egy ketlepeses instruction pipeline esen - ahol a ebben a masodik stage-ben tortenik az execution es a writeback is - mar okozhat merheto lassulast, meghat nem is elegans. Mindezek mellett persze az egesznek legnagyobb hatranya az lett a gyakorlatban hogy egy I/O portra megirt periferia (UART, timer, CRC accelerator, barmi) nem csereszabatos, azaz az adatmemoriat kihajto buszra nem lehetett railleszteni valtoztatas nelkul amennyiben ugy hozta (volna) a szukseg.
A tanulsag kis HDL-ezes es programozgatas utan az lett hogy ezen harom tulajdonsag, miszerint:
- kiszamithatoan es mindig pontosan egy oraciklus alatt vegrehajthato AVR I/O muveletek;
- teljesen szinkron I/O busz; es
- single-port memorianak megfeleltetheto I/O busz
kozul pontosan maximum kettot valosithatunk meg de a harom dolog egyszerre nem fog menni. A jelenleg elerheto/letoltheto AVR SoC verzio az a "teljesen szinkron I/O busz" megkotest dobta el, a mostani fejlesztoi valtozatban/forkban pedig a "single-port memorianak megfelelo I/O busz" kitetelt dobtam el. Igy az I/O portra nemcsak egy 6 bit szeles cim, hanem ket 6 bit szeles cim is kimegy, kulon cimvezeteke van az olvasasi illetve az irasi ciklusnak. Amennyiben ezt a dual port periferiat szeretnenk az adatbuszra kotni (ami single port) akkor persze a ket cim kozositheto hiszen az adatbuszon egy orajel alatt vagy csak irasi vagy csak olvasasi muvelet tud zajlani. Igy a periferia-modulok is ujrafelhasznalhatoak meg erezhetoen gyorsabb is lett a rendszer (a kiserleti Lattice FPGA-n kb 15%-os gyorsulassal).
A dolog hattere az az hogy egy
out 0x2A, rxx
in ryy, 0x2A
vagy egy
out 0x2A, rxx
in ryy, 0x2B
utasitas-sorozat eseten, teljesen szinkron I/O buszt feltetelezve az elso OUT utasitas irasi ciklusa illetve a masodik IN utasitas olvasasi ciklusa egyidoben tortenik. Persze ilyesmi aprosagokra is kell figyelni a periferia "gyartojanak" hogy a szinkron iras + szinkron olvasas az write-through legyen (mint pl a fenti elso pelda eseteben is ha a port address az OUT-nal es az OUT-ot azonnal koveto IN-nel ugyanaz), de erre halistennek a gyakorlatban nagyon keves esetben kell tenyleg figyelnunk. A masodik peldan meg latszik hogy miert kell dual port busz a periferiak fele (hiszen egyidoben a CPU mind a 0x2A, mind a 0x2B cimmel is operal).
Vegkonkluzio: egyelore nincs. Vagy hasznaljunk RISC-V-t. Ja hogy ott meg prediktalhato oraciklus-szamok nem lesznek.
- apal blogja
- A hozzászóláshoz be kell jelentkezni
- 295 megtekintés
Hozzászólások
Ha a 2. és 3. tulajdonsághoz ragaszkodsz, akkor azt (halványan) érteni vélem, hogy 1 órajel-ciklusban egy "in"-nek nem lesz meg az eredménye, tehát az utasításvégrehajtás blokkolódni fog, és várni fogsz a bejövő adatra -- de miért nem determinisztikus, hogy az adat mennyi órajel-ciklus alatt érkezik meg? Valamint felső becslés nem elegendő az "in" futásidejére?
További (zöldfülű) kérdésem: ha az 1. és 3. tulajdonságot választod (= "jelenleg elérhető AVR SoC"), akkor konkrétan mi az az adat, amit az "in" 1 órajel-cikluson belül visszaad ("kombinációs logikai hálózat eredménye")?
- A hozzászóláshoz be kell jelentkezni
Igenigen, a determinisztikussag az megoldhato, pl hogy az IN/OUT legyen ugyanaz mint az LD/ST (azaz 2-2 oraciklus). A feltetel/hangsuly inkabb azon van hogy ezeknek egy oraciklus alatt kell lemennie es nem ketto. Tartani akarom magam a klasszik AVR-hez ilyenertelemben (is), szoval az elso tulajdonsag az ezert lenne fontos.
A masodik tulajdonsag az most annyit takar hogy jelenleg (az opencore-os verzioban) kombinacios logikai halozat valasztja ki a kimeneti regiszter erteket a periferiaban:
/* I/O read: */
reg [7:0] io_do_data;
always @(*) begin
casex (io_a)
2'b00: io_do_data = TCNT[7:0];
2'b01: io_do_data = TTMP[7:0];
2'b10: io_do_data = TCR;
2'b11: io_do_data = TSR;
endcase
end
assign io_do = io_re ? io_do_data : 8'b00000000;
Ugye ez nem elegans, mert ez nem egy szinkron memoria. Raadasul az olvasas (io_re) megvaltoztathatja az allapotat is a rendszernek. Egy UART-nal egyertelmu hogy miert (kiszedi az adatot a receive FIFO-bol), de meg egy ilyen timer-nel is ahol 16 bites regisztereket kell atomi modon olvasni:
always @(posedge clk) begin
if (io_we & ~io_re) begin
if ( io_a==2'b01 ) TTMP <= io_di;
if ( io_a==2'b10 ) TCR <= io_di;
end else if ( io_re ) begin
if ( io_a==2'b00 )
TTMP <= TCNT[15:8];
end
end
Es hogy egy if ( io_re ) feltetel van itt is meg ott is... hát... :)
- A hozzászóláshoz be kell jelentkezni
Nem vagyok biztos benne, de rémlik, hogy az AVR az órajel mindkét élére csinál valamit. Ezért tud 1 órajel alatt megcsinálni dolgokat, ami igazából két lépés. Nem ez hiányzik nálad? Csak így messziről beleugatva.
- A hozzászóláshoz be kell jelentkezni
Hm... ez lehet, jo kerdes hogy a gyarto hogysmint csinalta ezeket... Nekem ezalpajan (23. oldal) ugy tunik hogy csak felfuto elre csinal valamit. De persze siman lehet hogy valamifele trukk van benne...
- A hozzászóláshoz be kell jelentkezni
elso OUT utasitas irasi ciklusa illetve a masodik IN utasitas olvasasi ciklusa egyidoben tortenik.
Ez a valódi AVR esetén így van? Mi ennek az értelme? Ha szinkron memóriát akarsz használni ilyen 1 ciklusos írás/olvasásra, adj a BRAM-nak negált órajelet.
- A hozzászóláshoz be kell jelentkezni