msm
2017-04-20 22:18Znudzony abstrakcjami w Javie? Uważasz że C to język wysokiego poziomu? Pisanie w asemblerze jest dla Ciebie za proste? Kod maszynowy czytasz jak prozę, a tablicę opkodów znasz lepiej niż tabliczkę mnożenia?
Może czas zejść poziom niżej?
Przez święta stwierdziłem że koniec z tymi silikonowymi abstrakcjami, i czas stworzyć własne (proste) CPU- przy pomocy FPGA.
Na screenie wynik działania prostego programu, zdefiniowanego przez statyczny RAM:
signal Memory: MemoryStore := (
0 => X"0302", -- LDL A, 2
1 => X"0401", -- LDL B, 1
2 => X"2334", -- ADD A, B
3 => X"0E02", -- JMP 02
others => X"0000"
);
Kilka słów wytłumaczenia:
- Wykonywany program to prosta pętla
a=2; while (true) { a += 1}
- Architektura jest 16bitowa, czyli rejestry mają po 16 bitów. Co ciekawe, technicznie w mojej architekturze bajty też są 16bitowe (najmniejsza adresowalna jednostka pamięci to 16 bitów!)
- Format instrukcji jest bardzo prosty, wręcz trywialny: pierwszy nibble to opcode (typ operacji), drugi to rejestr docelowy, pozostały bajt to albo dwa rejestry źródlowe albo stała:
0 -> LDL A Imm16 (load low 8 bits of register) 1 -> LDH A Imm16 (load high 8 bits of register) 2 -> ADD A B C (A = B + C) 3 -> SUB A B C (A = B - C) 4 -> MUL A B C (A = B * C) 5 -> DIV A B C (A = B / C) 6 -> XOR A B C (A = B ^ C) 7 -> OR A B C (A = B | C) 8 -> AND A B C (A = B & C) 9 -> CMV A B C (if ((C & FLAGS) != 0) { A = B; }) A -> LDM A B Imm8 (A = RAM[A + C]) B -> STM A B Imm8 (RAM[A + C] = B)
- Instruction pointer to normalny rejestr (o numerze 14) (tak jak w ARM, inaczej niż w x86), więc zapis do rejestru 0xE jest równoważny skokowi. Jeszcze nie zaimplementowane, ale w planach rejestry to:
0 -> NULL (jak w MIPS - zawsze zero) 1-13 -> general purpose registers 14 -> instruction pointer 15 -> flags
- Procesor zajmuje 5 cykli na opcode (patrz na screenie: state, clock):
FETCH -> DECODE -> REGREAD -> ARITH -> WRITEBACK
. W planach jest skrócenie tego (format instrukcji jest prosty, więc DECODE jest niepotrzebne) i dodanie superskalarności (wykonywanie 2 instrukcji na raz). - Na potrzeby testów stworzylem też własny RAM - ot, magia FPGA (było to zaskakująco proste). Na drugim (prostszym) screenie, wynik testu RAMu.
- Jeśli ktoś się nudzi, kod wrzuciłem na githuba: https://github.com/msm-code/msm-processing-unit. Nie jest to najaktualniejsza wersja, ale przynajmneij działa.
Morał: Można niżej niż asembler. Można niżej niż kod maszynowy. ...czy warto? Na pewno napisanie własnego procesora to ciekawe doświadczenie :P. Nie udało mi się go jeszcze wypalić na fizycznej płytce (posiadam takową - programowalną tylko z tego obrzydliwego xilinxa), razem z memory-mapped IO, ale prędzej czy później...
grzesiek51114
@msm zostaje Ci jeszcze tylko zaprojektować CPU w Minecrafcie i będziesz mógł nazwać siebie wszechprogramistą ;) ...albo wielkim elektronikiem jak w Panu Kleksie ;)
Shalom
@msm https://www.youtube.com/watch?v=MNyG-xu-7SQ tak sobie ciebie teraz wyobrażam! :P
alagner
Czemu nie w Verilogu albo SystemC (aczkolwiek nie wiem czy ten ostatni jest syntezowalny)?
J0ras
Ja kiedyś robiłem na kartce papieru moduł za pomocą metody karnaugha, ale widzę, że vhdl jest do tego bardziej przystosowany.
msm
@alagner: Nad verilogiem się zastanawiałem chwilę. Ostatecznie wybrałem VHDL bo miałem z nim trochę doświadczenia już z kiedyś, oraz wydaje się prostszy dla programisty. A SystemC i podobnych celowo unikałem, bo za bardzo chowają abstrakcję i nie wiadomo co się dzieje pod spodem (a chciałem w miarę nisko zejść)! No i z tego co wiem syntetyzuje sie z nich mało wydajny kod.
alagner
@msm w SystemC akurat spokojnie można też nisko pisać, aczkolwiek jak uczyłem się go (matko, kiedy to było, stara dupa jestem ;)) to nie dawało się opisów w nim zaimplementować w sprzęcie, był jedynie do modelowania. Co do Veriloga - obecnie jest praktycznie tak samo dojrzały jak VHDL a ma sporo fajnych narzędzi do weryfikacji. A sprzęt wygenerowany po syntezie w obu jest raczej podobny (poza rocket science i benchmarkami oczywiście), miałem okazję robić tester interfejsu VGA w jednym i drugim i wyszło 1:1 to samo. Problem leży bardziej w totalnie kijowych optymalizatorach i słabości narzędzi, przez co trzeba serio pisać kod zgodny z tym co się syntezować, faktycznie optymalizować wcześnie i nie cudować z abstrakcjami. Także metoda Karnaugha (@J0ras) wcale nie jest taka bezsensowna, jest wręcz dobrym dodatkiem, bo automatyczne optymalizatory lubią się pogubić czasem.
stryku
Gratki (: też kiedyś myślałem, żeby zrobić coś jeszcze niżej ale do vhdl mnie studia zniechęciły. Może kiedyś
Alag
Dlaczego nie lubisz w Xilinx? Mam pozytywne doświadczenia. Czego używasz do edycji kodu?
Po odpaleniu takiego projektu z procesorem na FPGA, komputer przestał być "magiczny" dla mnie :)
alagner
@Alag bo Altera i Lattice mają ciekawsze układy? @msm tak na luzie bardziej: https://www.youtube.com/watch?v=gM2hnra55Hs
MuadibAtrides
Jest taki kurs "from nand to tetris". Opowiada o tym, że jesteśmy programistą z bramkami nand i bardzo chcemy pograć w tetrisa. Tłumaczy jak wyjść z pojedyńczej bramki, zrobić cpu, zaprogramować asm, poziom ciut wyższego poziomu i w.końcu tetrisa. W nagrodę zagramy w tetrisa. Tak jakoś mi się skojarzyło z rym kursem.
akrasuski1
Phi... niski poziom to lutowanie cpu z pojedynczych tranzystorów :P