Шта вам је потребно да бисте почели да програмирате у RISC-V асемблеру

Последње ажурирање: 08/10/2025
Аутор: Исак
  • Укључује RV32I: регистре, ABI и контролу протока са е-позивом.
  • Вежба са Јупитером и вежбе: негативно, фактори, ланци, рекурзија.
  • Мастер крос алат, скрипта Повезивање и дебаговање помоћу objdump-а.

RISC-V асемблер: Захтеви и почетак рада

Ако сте радознали у вези са асемблером и сматрате да је RISC-V прави пут, дошли сте на право место. Почетак рада са ASM-ом на RISC-V је приступачнији него што се чини Ако разумете алате, модел програмирање и нека кључна правила архитектуре.

У следећим редовима сам комбиновао најбоље из неколико извора: вежбе са симулаторима типа Јупитер, конвенције основног репертоара RV32I, примери петљи и рекурзије, системски позиви, па чак и поглед на дизајн RISC-V процесора у VHDL-у (са ALU, контролом меморије и машином стања), плус преглед крос-ланца алата и скрипти за повезивање.

Шта је RISC-V асемблер и како се разликује од машинског језика?

Иако су обоје везани за хардвер, Машински језик је чисти бинарни (јединице и нуле) које процесор директно интерпретира, док асемблер користи мнемотехнику и симбола читљивији од асемблера, а затим се преводи у бинарни формат.

RISC-V дефинише отворени ISA са веома чистим основним репертоаром. RV32I (32-битни) профил укључује 39 корисничких инструкција са изванредном ортогоналношћу, одвајајући приступ меморији од чистог израчунавања, и са одличном подршком у GCC/LLVM.

Записи, споразуми и улазна тачка

У RV32I имате 32 регистра опште намене (x0–x31) 32-битна; x0 се увек чита као 0 и не може се уписивати у њега. Алијаси као што су a0–a7 (аргументи), t0–t6 (привремене вредности) или s0–s11 ​​​​(сачуване вредности) су такође корисни за праћење ABI-ја.

У зависности од окружења или симулатора, програм може почети на одређеној ознаци. У Јупитеру, програми почињу са глобалном ознаком __start., коју морате декларисати као видљиву (на пример, са .globl) да бисте означили улазну тачку.

Тхе ознаке се завршавају двотачком, можете ставити само једну инструкцију по линији, а коментари могу почети са # или ;, тако да их асемблер игнорише.

Алати и симулатори: Јупитер и основни ток рада

Да бисте вежбали без компликација, имате Јупитеров симулатор/асемблер, графички алат инспирисан SPIM/MARS/VENUS-ом који олакшава уређивање, склапање и извршавање у једном окружењу.

У Јупитеру можете креирати, уређивати и брисати датотеке на картици Уређивач. Након чувања, асемблирајте помоћу F3 и покрените да се отклоне грешке тока инструкција по инструкција, користећи прегледе регистара и меморије да би се разумело стање машине.

Програми морају да се завршавају позивом окружења: подешавање излазног позива a0 са кодом 10 (излаз). У RISC-V, е-позиви су еквивалентни системским позивима или замкама ка окружењу/систему.

Минимална структура програма и системски позиви

Типична структура у академским примерима дефинише почетну тачку, обавља посао и завршава се е-позивом. Аргументи е-позива обично путују у a0–a2 и селектор сервиса у a7, у зависности од окружења.

У једном линук На пример, у RISC-V режиму можете да испишете помоћу системског позива `write` и изађете са одговарајућим кодом. За писање се користе a0 (fd), a1 (бафер), a2 (дужина) и a7 са бројем сервиса.Коначно, a0 се поставља на повратни код, а a7 на излазни број.

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

Ако радите ван Линукса, као што је образовни симулатори са сопственом IoT услугом, промените број за е-позив и регистре у складу са документацијом о окружењу.

  Набавите Виндовс 8.1 ИСО датотеке [УСБ и ДВД подешавање]

Почетне вежбе које ће вам помоћи да се удобно са условним изразима, петљама и меморијом

Типично загревање је откривање да ли је цео број негативан. Можете вратити 0 ако је позитиван и 1 ако је негативан.; са RV32I, поређење са 0 и постављање на мање од решава проблем једном добро осмишљеном инструкцијом.

Још једна веома корисна вежба је навођење чинилаца броја: прелази од 1 до n, исписује делитеље и враћа колико их је билоВежбаћете условне гране, дељење (или поновљено одузимање) и петље са сабирањем и поређењем.

Рад са стринговима вас приморава да управљате меморијом: Посетите сваки знак низа у меморији и на лицу места претворите мала слова у велика ако се уклапају у ASCII опсег. Након завршетка, враћа оригиналну адресу стринга.

Петље, функције и рекурзија: факторијел, Фибоначијева и Ханојска кула

Приликом дизајнирања петљи, размислите о три блока: услов, тело и корак. Са beq/bne/bge и безусловним скоковима jal/j while/for се граде без мистерије, ослањајући се на допуне и поређења.

.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

Приликом позива функција, поштујте ABI: сачувај ако ћеш ланчано упућивати више позива, чува s0–s11 ​​​​ако их модификујете и користи стек са sp који се креће у вишекратницима речи.

Факторијал је класична рекурзија: основни случај n==0 враћа 1; у супротном, позовите factorial(n-1) и помножите са n. Заштитите ra и регистре сачуване на стеку пре позива и вратите их по повратку.

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

Фибоначијев је користан за вежбање оба рекурзија са два позива као ефикасна итеративна верзија са акумулаторским променљивим. А ако желите изазов контроле тока и параметара, преведите решење на асемблерски језик Ханојске куле са четири аргумента: дискови, извор, одредиште и помоћни торањ; ​​поштује редослед позива и приказује свако кретање.

Приступ меморији, низови и манипулација стринговима

У RISC-V, приступ меморији се врши помоћу команде load/store: lw/sw за речи, lh/sh за полуречи и lb/sb за бајтове, са означеним или неозначеним варијантама у набојима (lb наспрам lbu, lh наспрам lhu).

  Пројецт Зомбоид на Андроиду: Можете ли да га играте на мобилном телефону?

За прелазак кроз целобројне низове користите офсете од 4 бајта по индексу; за текстуалне стрингове, напредује бајт по бајт док не пронађе терминатор ако конвенција то захтева (нпр., \0). Не заборавите да сачувате основне адресе и рукујете показивачима са addi/auipc/la по потреби.

Дизајнирање RV32I процесора од нуле: Општи преглед

Ако желите да се спустите на силицијум, образовни пројекат гради RV32I CPU у VHDL-у, синтетизујући у FPGA Нижи-средњи опсег. Укључује програмски ROM, RAM меморију за податке и једноставан GPIO за осветљавање ЛЕД диоде.

Језгро имплементира основни репертоар (без M/A/C екстензија или CSR-ова), користи 32-битну адресну магистралу и омогућава 8-/16-/32-битни приступ меморији са проширеним знаком где је то потребно. Дизајн јасно раздваја регистре, АЛУ, контролер меморије и машину стања.

ALU, смене и идеја „одложеног учитавања“

АЛУ је описана комбиновано са операцијама као што су сабирање, одузимање, XOR, OR, AND, поређења (са и без знака) и логичке/аритметички помаци.

Да би се уштеделе LUT-ови у FPGA, имплементирани су вишебитни помераји итерирање једнобитних померања контролисаних машином стањаТрошите неколико циклуса, али смањујете логичке ресурсе.

У синхроним колима, промене се примећују на ивицама такта. Концепт „одложеног оптерећења“ подсећа да оно што је одабрано мултиплексером утиче на регистар у следећем циклусу., кључни аспект при пројектовању машине стања за преузимање-декодирање-извршавање.

Контролер меморије и мапа: ROM, RAM и GPIO

Блок меморије интегрише ROM и RAM меморију у непрекидни простор, поједностављивање интерфејса процесораКонтролер прима AddressIn (32 бита), DataIn, ширину (бајт/половина/реч), сигнал за проширење знака, WE (читање/писање) и Start за покретање трансакција.

Када се операција заврши, ReadyOut је подешен на 1 и, ако је прочитан, DataOut садржи податке (проширене знаком када се захтева). Ако су записани, подаци остају у RAM меморији.

Пример практичне мапе: РОМ од 0x0000 до 0x0FFF, GPIO бајт на 0x1000 (бит 0 на пину) и РАМ меморија од 0x1001 до 0x1FFFОвим можете направити трептај тако што ћете уписати и променити излазни бит.

Регистри, мултиплексери и машине стања

CPU дефинише 32 регистра опште намене инстанцираних низовима у VHDL-у, са децодифицадор да изабере одредиште за писање из АЛУ-а и задржи остатак.

Мултиплексери управљају ALU улазима (операндима и операцијама), сигнали ка контролеру меморије (ширине, адреса, контрола покретања и читање/писање) и специјални регистри: PC, IR и помоћни бројач за итеративне помаке.

Државна машина почиње са ресетовање, преузима инструкцију на коју указује PC (читање од 4 бајта), учитава се у IR када је спреман и прослеђује се извршним чворовима: ALU (једна инструкција у 1 циклусу осим за померања), учитавање/чување, гране и скокови, поред посебних инструкција као што је ebreak.

  Како да подесите Блуетоотх у оперативном систему Виндовс 10

Крос-ланац алата, повезивање и дебаговање

Да бисте генерисали RV32I бинарне датотеке, користите Унакрсни GCC (циљ riscv32-none-elf)Компајлирате C/C++/ASM изворне кодове, повезујете их са скриптом која дефинише мапу меморије и конвертујете излаз у облик који ваш ROM/FPGA очекује.

Једноставан скрипт за закачивање може да постави .текст у РОМ-у од 0x0000 и .подаци у РАМ меморији од 0x1004 (ако је 0x1000–0x1003 заузето ГПИО регистрима). Рутина покретања може бити „гола“ и поставити показивач стека на крају RAM меморије (нпр. 0x1FFC) пре него што позовете главну функцију.

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

Са riscv32-none-elf-objdump можете раставите ЕЛФ и проверите адресе; на пример, видећете боот на адреси 0x00000000 са инструкцијама као што су lui/addi/jal и прелазом на ваш главни. За VHDL симулацију, GHDL генерише трагове које можете отворити помоћу GtkWave.

Након верификације у симулацији, пренесите дизајн на FPGA (Quartus или други алатни ланац). Ако се RAM меморија закључује као интерни блокови и код је јасан RTL, требало би да синтетизујете без изненађења, чак и на искусним уређајима.

Практични подсетници и типичне грешке на почетку

Не заборавите да x0 је увек нула; писање у њега нема никаквог ефекта, а читање враћа 0. Искористите ово у своју корист приликом сабирања, поређења и чишћења регистра.

Када имплементирате функције, сачувајте ra и sN записе које измените, и управља стеком са сабирањима/одузимањима поравнатим по речима до sp. По повратку, враћа се обрнутим редоследом и скаче са jr ra.

У симулаторима попут Јупитера, проверите то __start је глобално и завршава се са ecall исправно (a0=10 за излаз). Ако се нешто не покрене, проверите ознаку, глобалност и поново компајлирајте (F3).

У вежбама са IO, поштујте протокол животне средине: који регистри носе параметре, број сервиса и да ли се очекује адреса или непосредна вредност. Користите симулатор или документацију оперативног система.

Са јасном ISA базом (RV32I, регистри и ABI), удобним симулатором попут Јупитера и све већим бројем примера (негативно, фактори, велика слова, петље, факторијел, Фибоначијев и Ханој), RISC-V асемблер престаје да буде зид и постаје сочан терен за разумевање како CPU размишља. А ако се усудите да пређете на VHDL, видећете како се ALU, меморија и управљање уклапају.од преузимања инструкција и лењег учитавања до меморијских интерфејса и мапе са ROM, RAM и GPIO која вам омогућава да трепћете ЛЕД диодом помоћу сопственог процесора.

Најбољи програми за програмирање
Повезани чланак:
7 најбољих програма за програмирање