- Укључује RV32I: регистре, ABI и контролу протока са е-позивом.
- Вежба са Јупитером и вежбе: негативно, фактори, ланци, рекурзија.
- Мастер крос алат, скрипта Повезивање и дебаговање помоћу objdump-а.
Ако сте радознали у вези са асемблером и сматрате да је 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 услугом, промените број за е-позив и регистре у складу са документацијом о окружењу.
Почетне вежбе које ће вам помоћи да се удобно са условним изразима, петљама и меморијом
Типично загревање је откривање да ли је цео број негативан. Можете вратити 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.
Крос-ланац алата, повезивање и дебаговање
Да бисте генерисали 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 која вам омогућава да трепћете ЛЕД диодом помоћу сопственог процесора.
Страствени писац о свету бајтова и технологије уопште. Волим да делим своје знање кроз писање, и то је оно што ћу радити на овом блогу, показивати вам све најзанимљивије ствари о гаџетима, софтверу, хардверу, технолошким трендовима и још много тога. Мој циљ је да вам помогнем да се крећете у дигиталном свету на једноставан и забаван начин.