- Zahŕňa RV32I: registre, ABI a riadenie toku s eCall.
- Cvičenie s Jupiterom a cvičenia: zápor, faktory, reťazce, rekurzia.
- Hlavný krížový reťazec nástrojov, scenár linkovanie a ladenie pomocou objdump.
Ak vás zaujíma assembler a máte pocit, že RISC-V je tou správnou cestou, ste na správnom mieste. Začať s ASM na RISC-V je dostupnejšie, ako sa zdá Ak rozumiete nástrojom, modelu programovanie a niektoré kľúčové pravidlá architektúry.
V nasledujúcich riadkoch som skombinoval to najlepšie z viacerých zdrojov: cvičenia so simulátormi typu Jupiter, konvencie základného repertoáru RV32I, príklady slučiek a rekurzie, systémové volania a dokonca aj pohľad na návrh CPU RISC-V vo VHDL (s ALU, riadením pamäte a stavovým automatom), plus prehľad skriptov naprieč reťazcami nástrojov a prepájaním.
Čo je assembler RISC-V a ako sa líši od strojového jazyka?
Hoci sú obaja pripojení k technické vybavenie, Strojový jazyk je čisto binárny (jednotky a nuly) ktoré CPU interpretuje priamo, zatiaľ čo assembler používa mnemotechnické pomôcky a symboly čitateľnejšie ako assembler, potom sa preloží do binárneho formátu.
RISC-V definuje otvorený ISA s veľmi čistým základným repertoárom. Profil RV32I (32-bitový) obsahuje 39 používateľských inštrukcií. s pozoruhodnou ortogonalitou, oddeľujúcou prístup k pamäti od čistého výpočtu a s vynikajúcou podporou v GCC/LLVM.
Záznamy, dohody a vstupný bod
V RV32I máte 32 registrov na všeobecné použitie (x0–x31) 32-bitový; x0 sa vždy číta ako 0 a nedá sa doň zapisovať. Aliasy ako a0–a7 (argumenty), t0–t6 (dočasné) alebo s0–s11 (uložené) sú tiež užitočné na sledovanie ABI.
V závislosti od prostredia alebo simulátora môže program začať na konkrétnom označení. V Jupiteri programy začínajú na globálnom tagu __start., ktorý musíte deklarovať ako viditeľný (napríklad s príponou .globl), aby ste označili vstupný bod.
L značky končia dvojbodkou, môžete vložiť iba jednu inštrukciu na riadok a komentáre je možné začínať znakom # alebo ;, takže ich assembler ignoruje.
Nástroje a simulátory: Jupiter a základný pracovný postup
Na cvičenie bez komplikácií máte Simulátor/assembler Jupitera, grafický nástroj inšpirovaný systémami SPIM/MARS/VENUS, ktorý umožňuje úpravu, zostavovanie a vykonávanie v jednom prostredí.
V Jupiteri môžete vytvárať, upravovať a mazať súbory na karte Editor. Po uložení zostavte s F3 a spustite ladiť tok inštrukcií po inštrukciách, pomocou pohľadov na registre a pamäť na pochopenie stavu stroja.
Programy musia končiť volaním prostredia: nastavenie ukončenia hovoru a0 s kódom 10 (ukončenie). V RISC-V sú e-volania ekvivalentom systémových volaní alebo pascí do prostredia/systému.
Minimálna štruktúra programu a systémové volania
Typická štruktúra v akademických príkladoch definuje východiskový bod, vykonáva prácu a končí elektronickým volaním (ecall). Argumenty eCall sa zvyčajne pohybujú v a0–a2 a volič služieb v a7 v závislosti od prostredia.
V jednom Linux Napríklad v RISC-V môžete vypísať pomocou systémového volania write a ukončiť ho s príslušným kódom. Pre zápis sa používajú a0 (fd), a1 (buffer), a2 (length) a a7 s číslom služby.Nakoniec sa a0 nastaví na návratový kód a a7 na číslo ukončenia.
# Ejemplo mínimo (Linux RISC-V) para escribir y salir
.global _start
_start:
addi a0, x0, 1 # fd = 1 (stdout)
la a1, msg # a1 = &msg
addi a2, x0, 12 # a2 = longitud
addi a7, x0, 64 # write
ecall
addi a0, x0, 0 # return code
addi a7, x0, 93 # exit
ecall
.data
msg: .ascii "Hola mundo\n"
Ak pracujete mimo Linuxu, napríklad v vzdelávacie simulátory s vlastnou službou IoT, zmeňte číslo elektronického volania a registre podľa dokumentácie k prostrediu.
Úvodné cvičenia, ktoré vám pomôžu zvyknúť si na podmienkové výrazy, cykly a pamäť
Typickým rozcvičením je zistiť, či je celé číslo záporné. Môžete vrátiť 0, ak je kladná hodnota, a 1, ak je záporná.; s RV32I, porovnanie s 0 a nastavenie na menej ako rieši problém jednou premyslenou inštrukciou.
Ďalším veľmi užitočným cvičením je vymenovať činiteľov čísla: prechádza od 1 do n, vypíše deliteľov a vráti, koľko ich boloPrecvičíte si podmienené vetvenie, delenie (alebo opakované odčítanie) a slučky so sčítaním a porovnávaním.
Práca s reťazcami vás núti spravovať pamäť: Navštívte každý znak reťazca v pamäti a na mieste preveďte malé písmená na veľké. ak sa zmestia do rozsahu ASCII. Po dokončení vráti pôvodnú adresu reťazca.
Slučky, funkcie a rekurzia: faktoriál, Fibonacciho a Hanojská veža
Pri navrhovaní slučiek myslite na tri bloky: podmienku, telo a krok. S beq/bne/bge a bezpodmienečnými skokmi jal/j sa zostavujú while/for bez tajomstva, spoliehajúc sa na doplnenia a porovnania.
.text
.globl __start
__start:
li t0, 0 # i
li t1, 10 # max
cond:
bge t0, t1, end # si i >= max, salta
# cuerpo: usar a0/a1 segun servicio IO del entorno
addi t0, t0, 1 # i++
j cond
end:
li a0, 10
ecall
Pri volaní funkcií rešpektujte ABI: ušetrite, ak budete reťaziť viac hovorov, zachová s0–s11 , ak ich upravíte, a použije zásobník s sp pohybujúcim sa v násobkoch slova.
Faktoriál je klasická rekurzia: základný prípad n==0 vráti 1; inak zavolajte factorial(n-1) a vynásobte n. Chráňte ra a registre uložené na zásobníku pred volaním a obnovte ich po návrate.
factorial:
beq a0, x0, base
addi sp, sp, -8
sw ra, 4(sp)
sw s0, 0(sp)
mv s0, a0
addi a0, a0, -1
jal factorial
mul a0, a0, s0
lw s0, 0(sp)
lw ra, 4(sp)
addi sp, sp, 8
jr ra
base:
li a0, 1
jr ra
Fibonacci je užitočný na precvičovanie oboch rekurzia s dvoma volaniami ako efektívna iteratívna verzia s akumulátorovými premennými. A ak chcete problém s riadením toku a parametrov, preložte riešenie do assembleru Hanojské veže so štyrmi argumentmi: disky, zdroj, cieľ a pomocná veža; rešpektuje poradie volaní a zobrazuje každý pohyb.
Prístup k pamäti, polia a manipulácia s reťazcami
V RISC-V sa prístup k pamäti vykonáva pomocou príkazov load/store: lw/sw pre slová, lh/sh pre polslová a lb/sb pre bajty, s variantmi so znamienkom alebo bez znamienka v nábojoch (lb vs lbu, lh vs lhu).
Na prechádzanie celočíselnými poľami použite 4-bajtové posuny na index; pre textové reťazce, posúva sa bajt po bajte, kým nenájde terminátor ak to konvencia vyžaduje (napr. \0). Nezabudnite podľa potreby uložiť základné adresy a s ukazovateľmi zaobchádzať pomocou addi/auipc/la.
Návrh CPU RV32I od nuly: Prehľad na vysokej úrovni
Ak máte chuť sa pustiť do kremíka, vzdelávací projekt vybuduje CPU RV32I vo VHDL, syntetizovateľné v FPGA Nízky až stredný rozsah. Zahŕňa programovú ROM, dátovú RAM a jednoduchý GPIO na rozsvietenie LED diódy.
Jadro implementuje základný repertoár (bez rozšírení M/A/C alebo CSR), používa 32-bitovú adresovú zbernicu a umožňuje 8-/16-/32-bitový prístup k pamäti so znamienkovým rozšírením, kde je to vhodné. Dizajn jasne oddeľuje registre, ALU, pamäťový radič a stavový automat.
ALU, posuny a myšlienka „oneskoreného načítania“
ALU je opísaná kombinovane s operáciami ako napríklad sčítanie, odčítanie, XOR, OR, AND, porovnávanie (so znamienkom a bez znamienka) a logické/aritmetické posuny.
Na ušetrenie LUT v FPGA sú implementované viacbitové posuny iterácia 1-bitových posunov riadených stavovým automatomSpotrebujete niekoľko cyklov, ale znížite logické zdroje.
V synchrónnych obvodoch sa pozorujú zmeny na hranách hodinových signálov. Koncept „oneskoreného zaťaženia“ pripomína, že to, čo vyberie multiplexor, ovplyvňuje register v ďalšom cykle., čo je kľúčový aspekt pri návrhu stavového automatu na načítanie-dekódovanie-spustenie.
Radič a mapa pamäte: ROM, RAM a GPIO
Pamäťový blok integruje ROM a RAM do súvislého priestoru, zjednodušenie rozhrania procesoraRiadiaca jednotka prijíma AddressIn (32 bitov), DataIn, šírku (bajt/polovica/slovo), signál rozšírenia znamienka, WE (čítanie/zápis) a Start na iniciovanie transakcií.
Keď je operácia ukončená, ReadyOut je nastavený na 1 a ak bol prečítaný, DataOut obsahuje dáta (s rozšíreným znamienkom, keď sa o ne požiada). Ak boli zapísané, dáta zostanú v RAM.
Príklad praktickej mapy: ROM od 0x0000 do 0x0FFF, bajt GPIO na adrese 0x1000 (bit 0 pre pin) a RAM od 0x1001 do 0x1FFFS týmto môžete vytvoriť blikač zápisom a prepínaním výstupného bitu.
Registre, multiplexory a stavové automaty
CPU definuje 32 registrov všeobecného účelu, ktoré sú inicializované pomocou polí vo VHDL, s dekodér vybrať cieľ zápisu z ALU a zvyšok ponechať.
Multiplexory riadia vstupy ALU (operandy a operácie), signály do pamäťového radiča (šírky, adresa, riadenie spustenia a čítanie/zápis) a špeciálne registre: PC, IR a pomocný čítač pre iteratívne posuny.
Štátny stroj začína s obnoviť, načíta inštrukciu, na ktorú ukazuje PC (4-bajtové čítanie), po pripravení sa načíta do IR a prejde k vykonávacím uzlom: ALU (jedna inštrukcia v 1 cykle okrem posunov), načítanie/uloženie, vetvenia a skoky, okrem špeciálnych inštrukcií, ako napríklad ebreak.
Cross-toolchain, prepojenie a ladenie
Na generovanie binárnych súborov RV32I použite Krížový GCC (cieľ riscv32-none-elf)Kompilujete zdrojové kódy C/C++/ASM, prepojíte ich so skriptom, ktorý definuje mapu pamäte, a skonvertujete výstup do formy, ktorú očakáva vaša ROM/FPGA.
Jednoduchý hook skript môže umiestniť .text v ROM od 0x0000 a .data v RAM od 0x1004 (ak sú 0x1000–0x1003 obsadené registrami GPIO). Spúšťacia rutina môže byť „nahá“ a umiestniť ukazovateľ zásobníka na konci RAM (napr. 0x1FFC) pred volaním funkcie main.
/* Mapa simple
* ROM: 0x00000000 - 0x00000FFF
* GPIO: 0x00001000 - 0x00001003
* RAM: 0x00001004 - 0x00001FFF
*/
SECTIONS {
. = 0x00000000;
.text : { *(.startup) *(.text) *(.text.*) *(.rodata*) }
. = 0x00001004;
.data : { *(.data) *(.data.*) }
}
S riscv32-none-elf-objdump môžete rozoberte ELF a skontrolujte adresynapríklad uvidíte topánka na adrese 0x00000000 s inštrukciami ako lui/addi/jal a prechodom do vášho hlavného adresára. Pre simuláciu VHDL generuje GHDL stopy, ktoré môžete otvoriť pomocou GtkWave.
Po overení v simulácii preneste návrh na FPGA (Quartus alebo iný nástrojový reťazec). Ak je RAM odvodená ako interné bloky a kód je jasný RTL, mali by ste syntetizovať bez prekvapení, a to aj na skúsených zariadeniach.
Praktické pripomienky a typické chyby pri začiatkoch
Nezabudni na to x0 je vždy nula; zápis doň nemá žiadny účinok a čítanie vráti 0. Využite to vo svoj prospech pri sčítavaní, porovnávaní a čistení registra.
Keď implementujete funkcie, uložiť záznamy ra a sN, ktoré upravítea spravuje zásobník pomocou sčítaní/odčítaní zarovnaných podľa slov do sp. Po návrate obnoví v opačnom poradí a preskočí s jr ra.
V simulátoroch ako Jupiter to overte __start je globálny a ukončíte ho pomocou ecall správne (a0=10 pre ukončenie). Ak sa niečo nespustí, skontrolujte návestie, globalitu a prekompilujte (F3).
V cvičeniach s IO, rešpektovať protokol prostredia: ktoré registre nesú parametre, číslo služby a či sa očakáva adresa alebo okamžitá hodnota. Použite dokumentáciu simulátora alebo operačného systému.
Vďaka prehľadnej základni ISA (RV32I, registre a ABI), pohodlnému simulátoru ako Jupiter a rastúcemu počtu príkladov (záporné, faktory, veľké písmená, slučky, faktoriál, Fibonacci a Hanoi) prestáva byť assembler RISC-V múrom a stáva sa šťavnatým terénom pre pochopenie myslenia CPU. A ak sa odvážite prejsť na VHDL, uvidíte, ako do seba zapadajú ALU, pamäť a riadenie.od načítavania inštrukcií a lenivého načítavania až po pamäťové rozhrania a mapu s ROM, RAM a GPIO, ktorá vám umožňuje blikať LED diódou pomocou vášho vlastného procesora.
Vášnivý spisovateľ o svete bajtov a technológií všeobecne. Milujem zdieľanie svojich vedomostí prostredníctvom písania, a to je to, čo urobím v tomto blogu, ukážem vám všetko najzaujímavejšie o gadgetoch, softvéri, hardvéri, technologických trendoch a ďalších. Mojím cieľom je pomôcť vám orientovať sa v digitálnom svete jednoduchým a zábavným spôsobom.