Čo potrebujete na začatie programovania v assembleri RISC-V

Posledná aktualizácia: 08/10/2025
Autor: Isaac
  • 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.

RISC-V Assembler: Požiadavky a začiatok

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.

  Získajte súbory ISO systému Windows 8.1 [Nastavenie USB a DVD]

Ú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).

  Project Zomboid na Androide: Môžete si ho zahrať na mobile?

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.

  Ako nastaviť Bluetooth v systéme Windows 10

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.

Najlepšie programy na programovanie
Súvisiaci článok:
7 najlepších programov na programovanie