msm
2017-04-20 22:18

Znudzony 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:

  1. Wykonywany program to prosta pętla a=2; while (true) { a += 1}
  2. 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!)
  3. 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)
  4. 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
  5. 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).
  6. 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.
  7. 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...

akrasuski1

Phi... niski poziom to lutowanie cpu z pojedynczych tranzystorów :P

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 ;)

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.

msm

@J0ras: można i tak. Jak rozpiszesz cały procesor na kartce to szacunek :P @Shalom me irl.

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.

msm

@alagner hmm, to popatrzę na SystemC kiedyś. Nie wygląda tak źle po dokładniejszym przyrzeniu się - pamiętam że kiedyś czytałem sporo negatywnych opinii i tym sie sugerowałem. Verilog jasne - bardzo dobry jest, po prostu coś trzeba było wybrać a VHDL sie wydawał przyjaźniejszy.

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.

Alag

@alagner: Altera to teraz już z logo Intel :) ale czy ciekawsze? Zależy co zamierzamy zrobić. U @msm w kodzie nie widziałem żadnych specjalnych komponentów na daną platformę

bednarz

Proszę Cie... o 1... nie wyjeżdżaj z tego kraju :)

alagner

@Alag jeszcze kwestia co kto lubi. Ja akurat pracowałem na jednym i drugim i narzędzia Altery zdecydowanie bardziej mi przypasowały.