Çfarë ju nevojitet për të filluar programimin në ASSEMBLERIN RISC-V

Përditësimi i fundit: 08/10/2025
Author: Isaac
  • Përfshin RV32I: regjistra, ABI dhe kontroll të rrjedhës me ecall.
  • Praktikë me Jupiterin dhe ushtrime: negativ, faktorë, zinxhirë, rekursion.
  • Zinxhir mjetesh kryesore me kryq, dorëshkrim lidhja dhe debugging me objdump.

Asambleri RISC-V: Kërkesat dhe Fillimi

Nëse jeni kuriozë për assemblerin dhe mendoni se RISC-V është zgjidhja e duhur, keni ardhur në vendin e duhur. Fillimi me ASM në RISC-V është më i përballueshëm nga sa duket Nëse i kuptoni mjetet, modelin e programimi dhe disa rregulla kryesore të arkitekturës.

Në rreshtat e mëposhtëm kam kombinuar më të mirat e disa burimeve: praktikat me simulatorët e tipit Jupiter, konventat e repertorit bazë RV32I, shembuj të lakut dhe rekursionit, thirrje sistemi, dhe madje edhe një vështrim në projektimin e CPU-së RISC-V në VHDL (me ALU, kontroll të memories dhe makinë gjendjeje), plus një përmbledhje të zinxhirit të mjeteve ndërthurëse dhe skripteve të lidhjes.

Çfarë është asembleri RISC-V dhe si ndryshon ai nga gjuha e makinës?

Edhe pse të dyja janë të lidhura me hardware, Gjuha e makinës është binare e pastër (njëshe dhe zero) të cilën CPU e interpreton drejtpërdrejt, ndërsa asembleri përdor mnemonikë dhe simbolet Më i lexueshëm se një asembler, pastaj përkthehet në binar.

RISC-V përcakton një ISA të hapur me një repertor bazë shumë të pastër. Profili RV32I (32-bit) përfshin 39 udhëzime përdoruesi me ortogonalitet të jashtëzakonshëm, duke ndarë aksesin në memorie nga llogaritja e pastër, dhe me mbështetje të shkëlqyer në GCC/LLVM.

Regjistrimet, marrëveshjet dhe pika e hyrjes

Në RV32I keni 32 regjistra për qëllime të përgjithshme (x0–x31) 32-bit; x0 lexohet gjithmonë si 0 dhe nuk mund të shkruhet në të. Emra të tillë si a0–a7 (argumente), t0–t6 (të përkohshëm) ose s0–s11 ​​​​(të ruajtur) janë gjithashtu të dobishëm për ndjekjen e ABI-t.

Në varësi të mjedisit ose simulatorit, programi mund të fillojë në një etiketë specifike. Në Jupiter, programet fillojnë në etiketën globale __start., të cilën duhet ta deklaroni si të dukshme (për shembull, me .globl) për të shënuar pikën e hyrjes.

L etiketat mbarojnë me dy pika, mund të vendosni vetëm një udhëzim për rresht dhe komentet mund të fillojnë me # ose ; kështu që asembleri i injoron ato.

Mjete dhe Simulues: Jupiter dhe Rrjedha Bazë e Punës

Për të praktikuar pa ndërlikime, ju keni Simulues/montues Jupiteri, një mjet grafik i frymëzuar nga SPIM/MARS/VENUS që lehtëson redaktimin, montimin dhe ekzekutimin në një mjedis të vetëm.

Në Jupiter mund të krijoni, modifikoni dhe fshini skedarë në skedën Redaktor. Pas ruajtjes, montoni me F3 dhe ekzekutoni për të debuguar instruksionin e rrjedhës pas instruksioni, duke përdorur pamjet e regjistrit dhe të memories për të kuptuar gjendjen e makinës.

Programet duhet të përfundojnë me një thirrje drejtuar mjedisit: dalje nga thirrja duke vendosur a0 me kodin 10 (dalje). Në RISC-V, thirrjet elektronike janë ekuivalente me thirrjet e sistemit ose kurthe për mjedisin/sistemin.

Struktura minimale e një programi dhe thirrjet e sistemit

Struktura tipike në shembujt akademikë përcakton një pikënisje, kryen punën dhe përfundon me një thirrje elektronike. Argumentet e thirrjes elektronike zakonisht udhëtojnë në a0–a2 dhe përzgjedhësi i shërbimit në a7, në varësi të mjedisit.

Në një Linux Për shembull, në RISC-V mund të printoni me thirrjen sistemore të shkrimit dhe të dilni me kodin e duhur. Për shkrim përdoren a0 (fd), a1 (buffer), a2 (gjatësia) dhe a7 me numrin e shërbimit.Së fundmi, a0 caktohet si kod kthimi dhe a7 si numër daljeje.

# 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"

Nëse punoni jashtë Linux-it, si p.sh. në simulatorë edukativë me shërbimin e tyre IoT, ndryshoni numrin e thirrjes elektronike dhe regjistron sipas dokumentacionit të mjedisit.

  Merrni skedarët ISO të Windows 8.1 [Konfigurimi i USB dhe DVD]

Ushtrime fillestare për t'ju ndihmuar të ndiheni rehat me kushtet, ciklet dhe kujtesën

Një ngrohje tipike është të zbulosh nëse një numër i plotë është negativ. Mund të ktheni 0 nëse është pozitiv dhe 1 nëse është negativ.; me RV32I, një krahasim me 0 dhe një set-on-less-se zgjidh problemin në një udhëzim të vetëm të menduar mirë.

Një ushtrim tjetër shumë i dobishëm është renditja e faktorëve të një numri: kalon nga 1 në n, shtyp pjesëtuesit dhe kthen numrin e tyre.Do të ushtroheni me degët kushtëzuese, pjesëtimin (ose zbritjen e përsëritur) dhe sythet me mbledhje dhe krahasim.

Puna me vargje ju detyron të menaxhoni kujtesën: Vizitoni çdo karakter të një vargu në memorie dhe konvertoni në vend shkronjat e vogla në shkronja të mëdha. nëse ato përshtaten brenda diapazonit ASCII. Pas përfundimit, kthen adresën origjinale të vargut.

Cikle, funksione dhe rekursion: faktorial, Fibonacci dhe Kulla e Hanoit

Kur hartoni sythe, mendoni për tre blloqe: gjendjen, trupin dhe hapin. Me beq/bne/bge dhe kërcime të pakushtëzuara jal/j ndërsa/for ndërtohen pa mister, duke u mbështetur në shtesa dhe krahasime.

.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

Në thirrjet e funksioneve, respektoni ABI-n: kurseni nëse do të bëni më shumë thirrje zinxhir, ruan s0–s11 ​​​​nëse i modifikoni ato dhe përdor pirgun me sp që lëviz në shumëfisha të një fjale.

Faktoriali është rekursioni klasik: rasti bazë n==0 kthen 1; përndryshe, thirr faktorial(n-1) dhe shumëzo me n. Mbro regjistrat ra dhe të ruajtur në stivë para thirrjes dhe rivendosi ato pas kthimit.

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 është i dobishëm për të praktikuar të dyja rekursion me dy thirrje si një version efikas iterativ me variabla akumuluese. Dhe nëse dëshironi një sfidë të kontrollit të rrjedhës dhe parametrave, përkthejeni një zgjidhje në assembler. Kullat e Hanoit me katër argumente: disqe, burim, destinacion dhe kullë ndihmëse; respekton rendin e thirrjeve dhe shfaq çdo lëvizje.

Qasja në memorie, vargjet dhe manipulimi i vargjeve

Në RISC-V, qasja në memorie bëhet me ngarkim/ruajtje: lw/sw për fjalët, lh/sh për gjysmëfjalët dhe lb/sb për bajtet, me variante me ose pa shenjë në akuza (lb kundrejt lbu, lh kundrejt lhu).

  Project Zomboid në Android: A mund ta luani në celular?

Për të përshkuar vargje numrash të plotë, përdorni zhvendosje 4-bajtëshe për indeks; për vargjet e tekstit, përparon bajt pas bajt derisa të gjejë terminatorin nëse konventa e kërkon këtë (p.sh., \0). Mos harroni të ruani adresat bazë dhe të trajtoni treguesit me addi/auipc/la sipas rastit.

Projektimi i një CPU RV32I nga e para: Një përmbledhje e nivelit të lartë

Nëse keni dëshirë të merreni me silikonin, një projekt edukativ ndërton një CPU RV32I në VHDL, e sintetizueshme në FPGA Gamë e ulët-mesme. Përfshin ROM programi, RAM të dhënash dhe një GPIO të thjeshtë për ndriçimin e një LED.

Bërthama zbaton repertorin bazë (pa zgjerime M/A/C ose CSR), përdor një autobus adresash 32-bitësh dhe lejon akses në memorien e zgjeruar me shenjë 8-/16-/32-bit kur është e përshtatshme. Dizajni ndan qartë regjistrat, ALU-në, kontrolluesin e memories dhe makinën e gjendjes.

ALU, ndërrimet dhe ideja e "ngarkesës së vonuar"

ALU përshkruhet në mënyrë të kombinuar me operacione të tilla si mbledhje, zbritje, XOR, OSE, DHE, krahasime (me shenjë dhe pa shenjë) dhe zhvendosje logjike/aritmetike.

Për të ruajtur LUT-të në FPGA, zbatohen zhvendosje me shumë bit. duke iteruar ndërrime 1-bitëshe të kontrolluara nga makina e gjendjes: ju konsumoni disa cikle, por zvogëloni burimet logjike.

Në qarqet sinkrone, ndryshimet vërehen në skajet e orës. Koncepti i "ngarkesës së vonuar" kujton se ajo që zgjidhet nga një multipleksues ndikon në regjistër në ciklin tjetër., një aspekt kyç gjatë projektimit të makinës shtetërore fetch-decode-execute.

Kontrolluesi dhe harta e memories: ROM, RAM dhe GPIO

Një bllok memorieje integron ROM dhe RAM në një hapësirë ​​të vazhdueshme, thjeshtimi i ndërfaqes së procesoritKontrolluesi merr AddressIn (32 bit), DataIn, gjerësinë (bajt/gjysmë/fjalë), sinjalin e zgjerimit të shenjës, WE (lexim/shkrim) dhe Start për të filluar transaksionet.

Kur operacioni të ketë mbaruar, ReadyOut është vendosur në 1 dhe, nëse është lexuar, DataOut përmban të dhënat (me shenjë të zgjeruar kur kërkohet). Nëse janë shkruar, të dhënat mbeten në RAM.

Një shembull i një harte praktike: ROM nga 0x0000 në 0x0FFF, një bajt GPIO në 0x1000 (bit 0 për një pin) dhe RAM nga 0x1001 në 0x1FFFMe këtë mund të krijoni një sinjalizues duke shkruar dhe aktivizuar/çaktivizuar bitin e daljes.

Regjistrat, multiplekserët dhe makinat e gjendjes

CPU përcakton 32 regjistra për qëllime të përgjithshme të instancuar me vargje në VHDL, me një dekodues për të zgjedhur destinacionin e shkrimit nga ALU dhe për të mbajtur pjesën tjetër.

Multiplekserët kontrollojnë hyrjet e ALU-së (operandët dhe operacionet), sinjalet për kontrolluesin e memories (gjerësitë, adresa, kontrolli i fillimit dhe leximi/shkrimi) dhe regjistrat specialë: PC, IR dhe një numërues ndihmës për zhvendosjet iterative.

Makina shtetërore fillon me rivendosni, merr instruksionin e treguar nga PC (lexim 4-bajtësh), ngarkohet në IR kur është gati dhe i kalon nyjeve të ekzekutimit: ALU (një instruksion në 1 cikël përveç zhvendosjeve), ngarkim/ruajtje, degëzime dhe kërcime, përveç instruksioneve speciale si ebreak.

  Si të konfiguroni Bluetooth në Windows 10

Zinxhiri i mjeteve të kryqëzuara, lidhja dhe debuggimi

Për të gjeneruar binare RV32I, përdorni një Kryq i GCC-së (target riscv32-none-elf)Ju kompiloni burimet C/C++/ASM, lidheni me një skript që përcakton hartën e memories dhe e konvertoni rezultatin në formën që pret ROM/FPGA juaj.

Një skript i thjeshtë me grep mund të vendosë .text në ROM nga 0x0000 dhe .data në RAM nga 0x1004 (nëse 0x1000–0x1003 është i zënë nga regjistrat GPIO). Rutina e nisjes mund të jetë "e zhveshur" dhe të vendosë treguesi i stekut në fund të RAM-it (p.sh. 0x1FFC) para se të telefononi kryesorin.

/* Mapa simple
 * ROM: 0x00000000 - 0x00000FFF
 * GPIO: 0x00001000 - 0x00001003
 * RAM: 0x00001004 - 0x00001FFF
 */
SECTIONS {
  . = 0x00000000;
  .text : { *(.startup) *(.text) *(.text.*) *(.rodata*) }
  . = 0x00001004;
  .data : { *(.data) *(.data.*) }
}

Me riscv32-none-elf-objdump ju mundeni çmontoni ELF-in dhe kontrolloni adresat; për shembull, do të shihni boot në 0x00000000 me udhëzime si lui/addi/jal dhe kalimin në skedarin tuaj kryesor. Për simulimin VHDL, GHDL gjeneron gjurmë që mund t'i hapni me GtkWave.

Pas verifikimit në simulim, çojeni dizajnin në një FPGA (Quartus ose ndonjë zinxhir tjetër mjetesh). Nëse RAM-i nxirret si blloqe të brendshme dhe kodi është i qartë RTL, duhet të sintetizoni pa surpriza, madje edhe në pajisjet veterane.

Kujtesa praktike dhe gabime tipike kur filloni

Mos harroni se x0 është gjithmonë zero; shkrimi në të nuk ka efekt dhe leximi i tij kthen 0. Përdoreni këtë në avantazhin tuaj në shtesa, krahasime dhe pastrime të regjistrit.

Kur zbatoni veçoritë, ruani të dhënat ra dhe sN që modifikoni, dhe menaxhon pirgun me mbledhje/zbritje të rreshtuara sipas fjalëve në sp. Pas kthimit, ai e rikthen në rend të kundërt dhe kërcen me jr ra.

Në simulatorët si Jupiteri, kontrolloni që __start është global dhe e përfundoni me ecall e saktë (a0=10 për të dalë). Nëse diçka nuk fillon, kontrolloni etiketën, globalitetin dhe rikompiloni (F3).

Në ushtrimet me IO, respektoni protokollin e mjedisit: cilët regjistra mbartin parametra, numrin e shërbimit dhe nëse pritet një adresë apo vlerë e menjëhershme. Përdorni simulatorin ose dokumentacionin e sistemit operativ.

Me një bazë të qartë ISA (RV32I, regjistra dhe ABI), një simulator të rehatshëm si Jupiter dhe shembuj në rritje (negativë, faktorë, shkronja të mëdha, sythe, faktorial, Fibonacci dhe Hanoi), asembleri RISC-V pushon së qeni një mur dhe bëhet një terren i dobishëm për të kuptuar se si mendon një CPU. Dhe nëse guxoni të kaloni në VHDL, do të shihni se si ALU, memoria dhe kontrolli përshtaten së bashku.nga marrja e udhëzimeve dhe ngarkimi i ngadaltë te ndërfaqet e memories dhe një hartë me ROM, RAM dhe GPIO që ju lejon të ndizni një LED me procesorin tuaj.

Programet më të mira për të programuar
Artikulli i lidhur:
7 programet më të mira për të programuar