26

prosciej by bylo by podzielic cala pamiec na bloki 0x4000
wtedy 2 najstarsze bity adresu wybieraja z tablicy 2 wskaznikow do okreslonych blokow,
a w zaleznosci od ustawinia portb, mozna by podmieniac w tej tablicy wskaznik do bloku
odpowiedzialnego za xms odpowiednim wskaznikiem do poszczegolnych bankow xms...
czyli adresowanie poszczegolnych komorek pamieci mozna by realizowac jako:

dana = *(tablica_blokow[adres>>14]+adres&0x3fff);

przy czym przy przesunieciu moglem cos pomiszac ;)
oczywiscie przy wykryciu zapisu do portb adres tablica_blokow[2] musialaby byc aktualizowany
na wskaznik do odpowiedniego banq...

az sprawdze jak to teraz jest obslugiwane w atari800 ;)
w ten sposob mozna tez poszatkowac pamiec na miejsze fragmenty...

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

27

Uproszczenie indeksowania pamięci, które założyłem w swojej teorii. To tylko luźna myśl póki co ;)

28

alex: Ja tu nie widzę żadnego uproszczenia.

W Atari800 wiekszosc dostepu do pamieci jest opakowana makrami zdefiniowanymi w memory.h, wiec zmiana organizacji pamieci nie powinna nastreczac wiekszych problemow. Nalezy tylko osobno uwzglednic dostep do kodu 6502 w cpu.c oraz dostep do roznych rodzajow danych w antic.c.

Swego czasu w Atari800 bylo tzw. Paged Memory, gdzie dla kazdej strony przestrzeni adresowej (256 bajtow)
byly wskazniki: funkcja odczytujaca, funkcja zapisujaca, wskaznik na pamiec. Obecnie mozna sobie przekompilowac Atari800 tylko z Paged Attrib, gdzie mamy funkcje: odczytującą i zapisującą dla każdej strony pamięci, które to tablice zastępują normalnie używaną tablicę attrib[65536] zawierającą wartości: RAM, ROM, HARDWARE.

Moje pomysły są dwa:

1. Dostęp do danych w dodatkowej pamięci zrobić przez funkcje, podobnie jak dostęp do chipów.
Możnaby użyć tego zarówno z Paged Attrib jak i bez. Kod w Anticu już uwzględnia inne od 6502 ustawienie dostępu do $4000-$7fff dla danych ekranu, wystarczy tam więc mała przeróbka. Stosunkowo niedawno dorobiłem możliwość kompilacji cpu.c tak, aby zamiast adresu PC trzymany był wskaźnik do pamięci.
O dziwo testy wykazały, że nieco spowalnia to emulację. Jednak przydałoby się, gdyby ustawiać ten wskaźnik
tak, aby wskazywał na pamięć rozszerzoną.

2. Użyć sprzętowego mechanizmu stronicowania, który powszechnie występuje w nowoczesnych prockach. Istnieje możliwość mapowania przestrzeni adresowej w pamięć fizyczną stronami o wielkości zazwyczaj 4 KB. A więc tutaj pasowałoby w sam raz. Niestety nie słyszałem, aby jakikolwiek system operacyjny (DOS nie jest systemem operacyjnym) był na tyle wspaniałomyślny, aby dawać procesowi użytkownika możliwość modyfikowania tablicy stron. Trzebaby więc wykombinować albo znaleźć jakieś dodatkowo instalowane sterowniki, które taką możliwość dadzą. Nie muszę chyba dodawać, że jest to rozwiązanie całkowicie nieprzenośne między systemami operacyjnymi i architekturami sprzętu.

https://www.youtube.com/watch?v=jofNR_WkoCE

29

Pogubilem sie.
Czy to co piszecie pomoze mi odpalac lepiej emulator Atari na PPC?

30

Nie, zmieniliśmy temat na przyspieszenie emulacji przełączania dodatkowej pamięci.

https://www.youtube.com/watch?v=jofNR_WkoCE

31

czyli temat dotyczy rowniez przyspiszania emulacji na PocketPC (wara od skrotu PPC - te procesory nie umarly, co widac na przykladzie konsol do gier)

co do dostepu do pamieci - przedstawiony przezemnie powyzej (post #26) sposob latwo mozna by przerobic na odpowiednie makra i tak jak napisalem dostosowac do mniejszego rozmiaru fragmentow pamieci (np. wielkosci strony...).

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

32

Twój sposób nakłada na dostęp do każdego bajtu narzut: przesunięcie bitowe, odczyt z tablicy i and (x86 mają indeksowanie z dodawaniem dwóch rejestrów). Anda możnaby uniknąć odpowiednio modyfikując wartości w tablicy. Popatrz na mojego posta #23: dodatkowe operacje są dla każdego bajtu kodu 6502 i nie możesz używać
dostępu 16-bitowego (czyli zamiast instrukcji wczytującej 16 bitów mamy dwie instrukcje czytające po 8,
przesunięcie i dodanie).

Wygląda na to, że mój sposób 2 da się zrealizować przy pomocy funkcji mmap(). Wg wstępnych prób dopał nie jest powalający (ten mmap trochę trwa).

https://www.youtube.com/watch?v=jofNR_WkoCE

33 Ostatnio edytowany przez jellonek (2005-11-04 00:20:04)

w sumie jesli popatrzyc na to calosciowo to mamy:
- (opcjonalne sprawdzenie czy nie dobieramy sie do segmentow xms, lub sprzetowych rejestrow)
- odczyt danej
- shr
- and
- suma
- kolejny (wlasciwy) odczyt danej z wyliczonego adresu...
co jest kilkukrotnie wolniesze od bezposredniego odczytu, przy pomocy jakiegostam makra z memory.h
ale, znowusz, cholernie upraszcza zarowno obsluge xms (i rejestrow sprzetowych)

co do czytania 16to bitowego, to przy little endian, dla czego nie skorzystac z
union adres {
byte high;
byte low;
};
i odpowiedniego ,,cast''a ?

czyli np.:
union adres costam;
costam.low = memory(0x600);
costam.high = memory(0x601);
memory(0x602) = memory((word) costam);

przyjmujac ze makro (funkcja) memory, jako parametr, przyjmuje przesuniecie wzgledem obszaru
emulowanej pamieci...

dodatkowo w wypadq x86 zawsze dodatkowo moza skorzystac z ladowania:
mov ax, [baza_pamieci+adres]
swap ax (lub xchg)
nie za bardzo pamienam mnemonika (chodzi o zamiane warosci ah, z al)
zawsze to bedzie szybsze niz uzywanie (adres>>8)+(adres&0xff << 8) (co jest oczywiscie bardziej - portable)

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

34 Ostatnio edytowany przez Fox (2005-11-04 00:34:02)

Nie wiem, co to ten "odczyt danej", ale po "shr" a przed "and" jest odczyt wskaźnika z tablicy.
Nie bardzo widzę, co ma Twoja metoda do rejestrów sprzętowych.

Ten "union" jest pozbawiony sensu: dwa bajty pod tym samym adresem.

Żeby zamienić kolejność bajtów w ax należałoby zrobić np. "rol ax, 8" (wolne jak diabli), ale wcale nie ma takiej potrzeby, bo przecież x86 jest little endian jak 6502.

Na little endian Atari800 używa teraz (*(UWORD *) (memory + adres)).
Jednak gdy przestrzeń adresowa będzie porozrzucana w różne obszary to nie jest to najlepszy pomysł:
wyobraź sobie dostęp do słowa pod adresem 0x3fff lub 0x7fff.

https://www.youtube.com/watch?v=jofNR_WkoCE

35

po pijaq pisalem to glupotami walilem (jak i tera ;) )
miast union pewni struct powinno byc (tez mi roznica :D )

czy tak, czy inaczej - przyklady przez ciebie zacytowane (0x3fff, 0x7fff)
zgasily moje ewenementy momentalnie...

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

36

Chciałem zaznaczyć, że temat dotyczy emulatora na platformę PocketPC także wpływ zmian na wydajność procesorów x86 jest tutaj bez znaczenia.

A tak na marginesie to przyśpieszanie pamięci choć ważne jest na dalszym planie. Proponuję skupić się na skompilowaniu ostatniej wersji tak, żeby dało sie ją uruchomić na PPC no i poprawić błędy klawiatury.

Ja to sie uda zrobić to będzie sę można skupić (i potestować rzeczywiste efekty) na zmianie organizacji pamięci :)

37 Ostatnio edytowany przez miker (2005-11-05 09:00:49)

alex napisał/a:

No właśnie - Stehlik :) Nic mi niestety nie odpowiedział... :(

No to trza mu zrobić POLAND na st(r)once! ;)

A na serio - ruszyło coś?

I Ty zostaniesz big endianem...

38

Alex: większość zgłoszonych tu pomysłów na optymalizację nie zależy od platformy.
Jeśli chodzi o skompilowanie i poprawienie błędów, to napisałeś już do Kostasa?

https://www.youtube.com/watch?v=jofNR_WkoCE

39

fox: tak z ciekawosci spytam

Fox napisał/a:

Żeby zamienić kolejność bajtów w ax należałoby zrobić np. "rol ax, 8" (wolne jak diabli)

czy:

xchg al, ah

nie bylo by szybsze?

oczywiscie w tym przypadku jest niepotrzebne, tak tylko pytam... (pod x86 brak tablic timingow, moze sprawdzales?)

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

40

Wedle mojej wiedzy, takie "xchg" byłoby dużo szybsze na 286 i starszych,
a dużo wolniejsze na Pentium Pro i nowszych (gdzie AH jest fizycznie
osobnym rejestrem od AX i stosowana jest emulacja w celu utrzymania
wstecznej zgodności). Na nowych prockach prawdopodobnie najszybsze będzie:

mov edx, eax
shl eax, 8
shr edx, 8
and eax, 0FFFFh
add eax, edx
https://www.youtube.com/watch?v=jofNR_WkoCE

41

To jest w Intelu szybsze niż ROL? O tempora ...

KMK
? HEX$(6670358)

42

Nie widzę w tym nic nadzwyczajnego. "rol" jest bardzo rzadko używaną instrukcją (szczególnie że nie ma odpowiednika w C), więc nie ma sensu jej optymalizować w sprzęcie. Za to użyte przeze mnie instrukcje są często spotykane i mogą być wykonywane równolegle w różnych potokach.

Większość RISCów pewnie nie ma wcale ROLa (przynajmniej nie 16-bitowego), więc trzeba robić podobnie kilkoma instrukcjami.

https://www.youtube.com/watch?v=jofNR_WkoCE

43

Rzadko może i być wykorzystywana, ale to i tak jest bizarre, że jeden obrót ma być wolniejszy niż pięć rozkazów, z których na dodatek dwa to przesunięcie.

Na Intelu się nie znam - i jak widzę, nie ma czego żałować - ale konstrukcje C typu ((a >> 8)|(a << 8)) kompilatory na Motoroli - konkretnie gcc z całą pewnością - przekładają właśnie na rol.w #8,rejestr i wszyscy są zadowoleni.

KMK
? HEX$(6670358)

44

Panowie! :) Jak już zapewne wiecie nowa wersja Atari800 jest skompilowana na Pocketa :) Niestety zawiera znane błędy (niedziałający shift, control, wolna pamięć) :(

Usiłowałem skompilowac źródła według wskazówek Kostasa ale niestety eVC++ 4.0 wywala mi od 32 do 452 błędów (w zależności od ułożenia plików w podkatalogach ze źródłami). Nie mam bladego pojęcia co jest nie tak :( Większość błędów dotyczy braku możliwości znalezienia plików przez kompilator mimio, iż te pliki sa i to na miejscu. A nawet jak wszystko zgram do jednego katalogu to i tak nic nie daje. Jeśli ktoś ma jakies propozycje - czekam.

45

podeslij na prv loga z bledami...

The UNIX Guru`s view of Sex:
unzip; strip; touch; finger; mount; fsck; more; yes; umount; sleep

46

A czy ta nowa wersja dziala SZYBCIEJ? Bo nie mam chwilowo mozliwosci sprawdzic.

47 Ostatnio edytowany przez seban (2006-01-06 15:57:09)

Hej!

Ponieważ czytając w/w posty napotkałem na wypowiedź Fox'a w której stwierdził iż:

Fox napisał/a:

Wedle mojej wiedzy, takie "xchg" byłoby dużo szybsze na 286 i starszych,
a dużo wolniejsze na Pentium Pro i nowszych (gdzie AH jest fizycznie
osobnym rejestrem od AX i stosowana jest emulacja w celu utrzymania
wstecznej zgodności). Na nowych prockach prawdopodobnie najszybsze będzie:

mov edx, eax
shl eax, 8
shr edx, 8
and eax, 0FFFFh
add eax, edx

szczrze mówiąc zwątpiłem iż ROL może być aż tak wolny... i że 5 instrukcji będzie szybsze niż jeden ROL, powoli zaczołem popadać w paranoje iż świat staje na głowie :D i że może czas zacząć sadzić marchewkę... ale coś mnie tkneło, ale ponieważ na X86 to się trochę znałem ale do generacji powiedzmy 486, zapytałem kogoś kto ma większe pojęcie o architekturze X86 ode mnie... w tym wypadku trafiło na SoTe, a ponieważ biedak jest nieco zapracowany to pozwolę sobie go tu zacytować (żeby nie było za jego zgodą):

SoTe napisał co następuje:

Nie za bardzo mam czas, aby tworzyć sobie konto na AA, zeby odpisaczeby odpisac, ale mozesz napisac fox'owi ze ta cala procedurka od zwyklego rol'a będzie wolniejsza z kilku powodów:

Przede wszystkim dlatego ze uzyl 2 rejestrow, to powoduje "registry stall". dzieje sie to wtedy gdy jakas instrukcja uzywająca rejestru (w tym wypadku add eax, edx) czeka na wynik poprzedniej instrukcji (w tym wypadku and eax, 0FFFh)

Jesli chca uzyskac zwykla zamiane 2 bajtow, to najlepiej bedzie uzyc "rol ax,8". ponadto najnowszy visual 2005, taką konstrukcję (a>>8) | (a<<8), zamienia wlasnie na pojedynczego "rol ax,8". nie jestem w stanie sprawdzic poprzednich wersji kompilatora bo ich nie mam

uzycie "rol ax,8" jest dlatego najszybsze, ze:

a) uzywa jednego rejestru i jednej instrukcji

b) rol r,m jest zaliczany do rozkazów ALU, a to oznacza ze na nowych P4 (3-4 letnich i nowszych) rol ax,8 zajmie 0.5 cykla
   (jednostka ALU jest popędzana w tych procesorach zegarem 2x szybszym niz reszta procesora)

ufff... i tyle :) wiec jak sie okazuje z intelem nie jest aż tak źle, jak myślałem :)

48

Racja, ROL się ślimaczył tylko na 186 i 286:

ROL     Rotate bits left

    operands    bytes   8088    186     286     386     486     Pentium
    reg, 1       2       2       2       2       3       3       1   PU
    mem, 1    2+d(0,2)  23+EA   15       7       7       4       3   PU
    reg, cl      2       8+4n    5+n    5+n      3       3       4   NP
    mem, cl   2+d(0,2) 28+EA+4n 17+n    8+n      7       4       4   NP
    reg, imm     3       -       5+n    5+n      3       2       1   PU
    mem, imm  3+d(0,2)   -      17+n    8+n      7       4       3   PU*

       * = not pairable if there is a displacement and immediate

Za to RCL (czyli ROL z 6502) wygląda, że jeszcze w Pentium miał złożoność liniową:

RCL     Rotate bits left with CF

    operands    bytes   8088    186     286     386     486     Pentium
    reg, 1       2       2       2       2       9       3       1   PU
    mem, 1    2+d(0,2)  23+EA   15       7      10       4       3   PU
    reg, cl      2       8+4n    5+n    5+n      9      8-30    7-24 NP
    mem, cl   2+d(0,2) 28+EA+4n 17+n    8+n     10      9-31    9-26 NP
    reg, imm     3       -       5+n    5+n      9      8-30    8-25 NP
    mem, imm  3+d(0,2)   -      17+n    8+n     10      9-31   10-27 NP

Jeszcze XCHG dla ciekawskich:

XCHG    Exchange register/memory with register

     operands   bytes   8088    186     286     386     486     Pentium
     reg, reg    2       4       4       3       3       3       3   NP
     reg, mem  2+d(0-2)  25+EA  17       5       5       5       3   NP
     mem, reg  2+d(0-2)  25+EA  17       5       5       5       3   NP

     acc, reg    1       3       3       3       3       3       2   NP
     reg, acc    1       3       3       3       3       3       2   NP

     in above: acc = AX or EAX only

(zaczerpnięte z http://security-protocols.com/programmi … pcode.html)

https://www.youtube.com/watch?v=jofNR_WkoCE

49

Gdyby ktoś sądził, że "XCHG AL, AH" będzie szybsze od ciągu tych 5 instrukcji:
http://www.codingnow.com/file/pentopt.htm#19_1

https://www.youtube.com/watch?v=jofNR_WkoCE

50 Ostatnio edytowany przez AdamSoTe (2006-01-09 17:41:30)

No tak, ale te dokumenty dotyczą czasów pentium MMX. Po wprowadzeniu (bodajże P3 albo może p4 ) zmienił się sposób optymalizacji. Różnica jest taka, że nie ma już jednostek dekodujących D0, D1, D2. Teraz procesor to jest zestaw kilku microprocesorów o różnym przeznaczeniu. Np. są 2 jednostki ALU z podwojnym zegarem, jednostki FPU move, FPU Execute, integer operation, memory load, memory save. Kazdy rozkaz zajmuje jedna lub kilka jednostek, przy czym wykonywanie jest niezalezne... tzn. ze jezeli mamy:

mov eax, [memory]
add ebx, ecx
mov ecx, edx
mov edx, ebp
fadd
imul
....

to rozkaz mov eax,[memory] moze zostac wykonany na koncu tej listy rozkazow, bo uzywa jednostki memory load, ktora jest najwolniejsza. Ale poniewaz pozniejsze rozkazy nie potrzebuja wyniku operacji, to moga byc wykonywane dalej. To czy jakiś rozkaz się wykona od razu czy będzie czekać na swoją kolej, zależy przedewszystkim od dwoch czynników:
1) czy jednostka wykonawcza jest zajęta czy wolna
2) czy trzeba czekać na wynik poprzedniej operacji

w przypadku 2) rozkazy
add edx, ecx
mov ecx, eax
nie beda sie blokowac gdyz wynik pierwszej operacji jest zabisany w edx, natomiast ecx jest "wolny" od razu (sluzy tylko na wstepie jako źródło wartości).

Co do punktu 1) to trzeba przeczytać dokument intela "IA-32 Intel? Architecture Optimization Reference Manual", ftp://download.intel.com/design/Pentium … 896612.pdf tam jest lista rozkazów z wypiską których jednostek wykonawczych one używaja.

Aha, no i jeszcze jest coś takiego jak latency i throughput. Latency oznacza ile cykli trzeba czekać na wynik, natomiast throughput ile cykli potrzeba aby wykonać/zdekodować kolejną instrukcję.

Dla przykładu ów ROL ma 0.5 throughput (następna instrukcja może zostać zdekodowana i przekazana do wykonania) po 0.5 cykla, natomiast ma 1 cykl latency (czyli wynik jest znany po 1 cyklu). a 1 cykl dlatego ze wykonanie tej instukcji jest w jednostce integer operation ktora chodzi na zegarze procesora (a nie na x2 jak jednostki ALU).

[Edit]

Jeszcze odnośnie instrukcji XCHG AL, AH. Wykonuje się ona "zawsze" 1.5 cykla (latency) i ma 1 cykl throughput. ROL AX,8 wykonuje się 1 cykl na większości procesorów, albo 4 cykle (to jest tylko na rodzinie procesorów 0xF2). Ponadto nie występuje tutaj coś takiego jak "problem emulacji rejestrów", bo jest wykorzystywana tylko część rejestru a nie całość. Jedyne co może wystąpić to "partial registry stall" albo "registry stall", czyli np.:

rol eax, 8
mov al, ah

druga instrukcja, czeka na wynik pierwszej, gdyż wartość 'ah' jest zależna od wykonania poprzedniej instrukcji. Bynajmniej nie wynika to z podziału rejestrów. Problem pojawia się jedynie w sytuacji gdy chcemy użyć rejestru, który wcześniej posłużył jako rejestr docelowy.

Ze scenariusza do polskiej gry:
"Ten Twój kumple może na żywo komentować, gęsto ci się dzieje."
Co autor miał na myśli ?