РЕДАКТИРОВАТЬ только что получил мою доску rev.
Вы можете посмотреть в руководстве по началу работы, чтобы увидеть, как определить доску, используя их песочницу. Но это не обязательно, если у вас есть (gnu) набор инструментов, который поддерживает rv32i или больше, чем этот rv32imac, вы можете создавать программы без других внешних зависимостей.
Сама цепочка инструментов не знает одну плату от другой, одну микросхему от другой.
В документации Sifive говорится:
Плата HiFive1 Rev B поставляется с модифицируемым загрузчикомв начале SPI Flash (0x20000000). В конце выполнения этой программы ядро переходит к основной пользовательской части кода в 0x20010000.
И это критическая информация, которая нам нужна, плюс адресное пространство для памяти в карте памяти для части 0x80000000 0x4000байт sram.
novectors.s
.globl _start
_start:
lui x2,0x80004
jal notmain
j .
.globl dummy
dummy:
ret
.globl PUT32
PUT32:
sw x11,(x10)
ret
.globl GET32
GET32:
lw x10,(x10)
ret
notmain.c
void PUT32( unsigned int, unsigned int);
unsigned int GET32 ( unsigned int );
void dummy ( unsigned int );
#define GPIOBASE 0x10012000
#define GPIO_VALUE (GPIOBASE+0x00)
#define GPIO_INPUT_EN (GPIOBASE+0x04)
#define GPIO_OUTPUT_EN (GPIOBASE+0x08)
#define GPIO_PORT (GPIOBASE+0x0C)
#define GPIO_PUE (GPIOBASE+0x10)
#define GPIO_OUT_XOR (GPIOBASE+0x40)
int notmain ( void )
{
unsigned int rx;
PUT32(GPIO_OUTPUT_EN,(1<<19)|(1<<21)|(1<<22));
PUT32(GPIO_PORT,(1<<19)|(1<<21)|(1<<22));
PUT32(GPIO_OUT_XOR,0);
while(1)
{
PUT32(GPIO_PORT,(1<<19)|(1<<21)|(1<<22));
for(rx=0;rx<2000000;rx++) dummy(rx);
PUT32(GPIO_PORT,0);
for(rx=0;rx<2000000;rx++) dummy(rx);
}
return(0);
}
memmap
MEMORY
{
rom : ORIGIN = 0x20010000, LENGTH = 0x1000
ram : ORIGIN = 0x80000000, LENGTH = 0x4000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
build
riscv32-none-elf-as -march=rv32imac -mabi=ilp32 novectors.s -o novectors.o
riscv32-none-elf-gcc -march=rv32imac -mabi=ilp32 -Wall -O2 -nostdlib -nostartfiles -ffreestanding -c notmain.c -o notmain.o
riscv32-none-elf-ld novectors.o notmain.o -T memmap -o notmain.elf
riscv32-none-elf-objdump -D notmain.elf > notmain.list
riscv32-none-elf-objcopy notmain.elf -O ihex notmain.hex
riscv32-none-elf-objcopy notmain.elf -O binary notmain.bin
Теперь теоретически вы можете использовать riscv64-unknown-elf, о котором они говорят, даже если они хотят собрать для rv32, а не rv64 ... Я тоже могу попробовать ...
notmain.list
Disassembly of section .text:
20010000 <_start>:
20010000: 80004137 lui x2,0x80004
20010004: 010000ef jal x1,20010014 <notmain>
20010008: a001 j 20010008 <_start+0x8>
2001000a <dummy>:
2001000a: 8082 ret
2001000c <PUT32>:
2001000c: c10c sw x11,0(x10)
2001000e: 8082 ret
20010010 <GET32>:
20010010: 4108 lw x10,0(x10)
20010012: 8082 ret
20010014 <notmain>:
20010014: 1141 addi x2,x2,-16
20010016: c04a sw x18,0(x2)
20010018: 10012937 lui x18,0x10012
2001001c: 00890513 addi x10,x18,8 # 10012008 <_start-0xfffdff8>
20010020: 006805b7 lui x11,0x680
20010024: c606 sw x1,12(x2)
20010026: c226 sw x9,4(x2)
20010028: c422 sw x8,8(x2)
2001002a: 37cd jal 2001000c <PUT32>
2001002c: 00c90513 addi x10,x18,12
20010030: 006805b7 lui x11,0x680
20010034: 3fe1 jal 2001000c <PUT32>
20010036: 04090513 addi x10,x18,64
2001003a: 4581 li x11,0
2001003c: 001e84b7 lui x9,0x1e8
20010040: 37f1 jal 2001000c <PUT32>
20010042: 0931 addi x18,x18,12
20010044: 48048493 addi x9,x9,1152 # 1e8480 <_start-0x1fe27b80>
20010048: 006805b7 lui x11,0x680
2001004c: 854a mv x10,x18
2001004e: 3f7d jal 2001000c <PUT32>
20010050: 4401 li x8,0
20010052: 8522 mv x10,x8
20010054: 0405 addi x8,x8,1
20010056: 3f55 jal 2001000a <dummy>
20010058: fe941de3 bne x8,x9,20010052 <notmain+0x3e>
2001005c: 4581 li x11,0
2001005e: 854a mv x10,x18
20010060: 3775 jal 2001000c <PUT32>
20010062: 4401 li x8,0
20010064: 8522 mv x10,x8
20010066: 0405 addi x8,x8,1
20010068: 374d jal 2001000a <dummy>
2001006a: fe941de3 bne x8,x9,20010064 <notmain+0x50>
2001006e: bfe9 j 20010048 <notmain+0x34>
Важно проверить, прежде чем пытаться загрузить программу на устройство, наш желаемый код ввода, первые инструкции novectors.s должны быть в 0x20010000 для этой платы / чипа в комплекте (заводской загрузчик). И это.
notmain.hex
:020000042001D9
:1000000037410080EF00000101A082800CC1828096
:100010000841828041114AC0372901101305890027
:10002000B705680006C626C222C4CD371305C9002D
:10003000B7056800E13F130509048145B7841E0038
:10004000F137310993840448B70568004A857D3F3C
:10005000014422850504553FE31D94FE81454A85F0
:1000600075370144228505044D37E31D94FEE9BF31
:0400000520010000D6
:00000001FF
скопируйте notmain.hex на подключенный носитель HiFive. Теперь это заняло у меня час или два, пытаясь выяснить, что такое шестнадцатеричный файл, когда я начал, здесь это не сработало. скачал их sdk, выкопанный, который нашел elf2hex, но это был плохой касательный, который был для работы с fpga. Разобрался, и все, что они делают, это riscv ... objcopy -O ihex, как и я, попробовал еще раз. И теперь это работает. Я получаю fail.txt, говоря, что он не мог подключиться к процессору раньше. Не знаю, что я делал или не делал, чтобы сделать эту работу.
Теоретически вы можете вырезать и вставить вышеупомянутый шестнадцатеричный файл, сохранить его и скопировать. Почему ни у кого нет примера шестнадцатеричного файла, вам нужно правильно установить 75 специальных вещей и запустить сборку, а не предоставлять здесь полный пример с промежуточными файлами. Я, конечно, сделаю это в моих примерах для этой платформы. Или, по крайней мере, тот, что приведен выше.
Вместо их мигающего радужного светодиода, приведенный выше заставит его мигать «белым» с регулярной частотой.
Примечание: светодиоды горят одинаковоЛинии GPIO на оборотной плате, загрузчик приземляется по другому адресу 0x20400000, чем rev b 0x20010000. Таким образом, то же самое можно построить для доски объявлений с этим одним изменением карты памяти.
Если вы или читатель хотите вернуться к версии a, если она есть, это модифицированный openocd, который на момент написания этой статьи находился в проекте github riscv user riscv-openocd. обычный ./bootstrap, ./configure, make для получения инструментов и в директории tcl есть файл конфигурации riscv openocd, показанный выше
interface ftdi
ftdi_device_desc "Dual RS232-HS"
ftdi_vid_pid 0x0403 0x6010
был ключом, доска rev2 lsusb:
Bus 001 Device 018: ID 1366:1051 SEGGER
и нет совпадений с этими значениями pid / vid в конфигурационных файлах openocd. Приводим к прочтению большей части руководства по началу работы.
Первый ответ / перед редактированием выше
У меня есть оригинальная доска hifive1, как вы получили rev b?
В любом случае ...
Для исходной платы руководство по началу работы говорит следующее:
Плата HiFive1 поставляется с модифицируемым загрузчиком при запуске SPI Flash (0x20000000). В конце выполнения этой программы ядро переходит к основной пользовательской части кода в 0x20400000.
Для платы rev b это говорит:
Плата HiFive1 Rev B поставляется смодифицируемый загрузчик при запуске SPI Flash (0x20000000). В конце выполнения этой программы ядро переходит к основной пользовательской части кода в 0x20010000.
Обе микросхемы показывают 0x80000000 для оперативной памяти и 0x20000000 для (внешней) вспышки. Предположим, что это интерфейс, на котором они поместили флешку на плату rev B.
Первая программа.
novectors.s
.globl _start
_start:
lui x2,0x80004
jal notmain
sbreak
j .
.globl dummy
dummy:
ret
notmain.c
void dummy ( unsigned int );
int notmain ( void )
{
unsigned int ra;
for(ra=0;;ra++) dummy(ra);
return(0);
}
memmap
MEMORY
{
ram : ORIGIN = 0x80000000, LENGTH = 0x4000
}
SECTIONS
{
.text : { *(.text*) } > ram
.rodata : { *(.rodata*) } > ram
.bss : { *(.bss*) } > ram
}
build
riscv32-none-elf-as -march=rv32i -mabi=ilp32 novectors.s -o novectors.o
riscv32-none-elf-gcc -march=rv32i -mabi=ilp32 -Wall -O2 -nostdlib -nostartfiles -ffreestanding -c notmain.c -o notmain.o
riscv32-none-elf-ld novectors.o notmain.o -T memmap -o notmain.elf
riscv32-none-elf-objdump -D notmain.elf > notmain.list
riscv32-none-elf-objcopy notmain.elf -O binary notmain.bin
теоретически вы можете использовать riscv32-что угодно-что угодно (riscv32-unknown-elf и т. Д.). Поскольку этот код достаточно универсален. Также обратите внимание, что я использую минимальный rv32i, вы, вероятно, можете использовать rv32imac для всей энчилады.
Проверьте разборку:
Disassembly of section .text:
80000000 <_start>:
80000000: 80004137 lui x2,0x80004
80000004: 010000ef jal x1,80000014 <notmain>
80000008: 00100073 ebreak
8000000c: 0000006f j 8000000c <_start+0xc>
80000010 <dummy>:
80000010: 00008067 ret
80000014 <notmain>:
80000014: ff010113 addi x2,x2,-16 # 80003ff0 <notmain+0x3fdc>
80000018: 00812423 sw x8,8(x2)
8000001c: 00112623 sw x1,12(x2)
80000020: 00000413 li x8,0
80000024: 00040513 mv x10,x8
80000028: fe9ff0ef jal x1,80000010 <dummy>
8000002c: 00140413 addi x8,x8,1
80000030: ff5ff06f j 80000024 <notmain+0x10>
в случае rv32i это все 32-битные инструкции, и это нормально. Эта программа предназначена для загрузки в оперативную память и запуска там с отладчиком, я использую openocd и telnet в.
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
Open On-Chip Debugger
Затем
halt
load_image notmain.elf
resume 0x80000000
в окне telnet
Затем вы можете снова остановиться.
80000024: 00040513 mv x10,x8
80000028: fe9ff0ef jal x1,80000010 <dummy>
8000002c: 00140413 addi x8,x8,1
80000030: ff5ff06f j 80000024 <notmain+0x10>
вы можете проверить либо x8, либо x10, чтобы увидеть, что он насчитал
resume
halt
, и снова изучить регистры, которые они должны были увеличить. Первая программа работает, продолжает работать.
Вторая программа использует этот скрипт компоновщика вместо
memmap
MEMORY
{
rom : ORIGIN = 0x20010000, LENGTH = 0x4000
ram : ORIGIN = 0x80000000, LENGTH = 0x4000
}
SECTIONS
{
.text : { *(.text*) } > rom
.rodata : { *(.rodata*) } > rom
.bss : { *(.bss*) } > ram
}
проверка разборки.
Disassembly of section .text:
20010000 <_start>:
20010000: 80004137 lui x2,0x80004
20010004: 010000ef jal x1,20010014 <notmain>
20010008: 00100073 ebreak
2001000c: 0000006f j 2001000c <_start+0xc>
20010010 <dummy>:
20010010: 00008067 ret
20010014 <notmain>:
20010014: ff010113 addi x2,x2,-16 # 80003ff0 <notmain+0x5fff3fdc>
20010018: 00812423 sw x8,8(x2)
2001001c: 00112623 sw x1,12(x2)
20010020: 00000413 li x8,0
20010024: 00040513 mv x10,x8
20010028: fe9ff0ef jal x1,20010010 <dummy>
2001002c: 00140413 addi x8,x8,1
20010030: ff5ff06f j 20010024 <notmain+0x10>
Появляетсябыть независимым от позиции, поэтому он должен был просто работать, как это было с другим скриптом компоновщика, но лучше использовать правильные адреса.
Мои заметки говорят:
flash protect 0 64 last off
program notmain.elf verify
resume 0x20010000
И теперь вы должны быть в состояниидля сброса или выключения питания платы, подключитесь к openocd таким способом, который не сбрасывает (или делает, если хотите), и тогда вам не нужно загружать что-либо, что он должен был запустить их загрузчик, который затем запустил ваш загрузчик по этому адресу (прыгнул к нему)как они упоминают). Изучите r8 или r10 (r10 для этого abi - первый переданный параметр, поэтому, даже если ваш gcc собирается с использованием чего-то отличного от r8, r10 все равно должен отражать счетчик) resume, halt, reg, resume, halt, reg ...
Прежде чем перезаписать их загрузчик на 0x20000000, я бы его сбросил и убедился, что у вас есть хорошая копия, и, возможно, у них есть копия на их веб-сайте. Затем вы можете изменить скрипт компоновщика на 0x20000000. Прежде чем делать это лично, я бы разбирал и проверял их загрузчик и выяснял, что, если что-то делает, стоит ли его хранить и т. Д. В их тексте написано «модифицируемый»
Я порезал себе риск-v зубыплата hifive1, но теперь она перешла на ядра с открытым исходным кодом, платы hifive довольно дорогие. Я также сделал минимальную печатную плату и отложил некоторые пять частей, собирался только закончить оперативную память и т. Д., Но моя доска была слишком минимальной, и я не стал возвращаться и пытаться снова, небольшая поддержка на их форумах для работы печатных плат и их документовоставил желать лучшего. Я предполагаю, что когда доски rev b станут доступны, я подберу одну. увидим. удачи.
Укажите, что существует множество ядер, которые вы можете симулировать с помощью verilator или другого, и видеть, как все происходит, и вы не можете ни кирпичить, ни выпустить дым, потому что это сим.
Обратите внимание на rv32ic
riscv32-none-elf-as -march=rv32ic -mabi=ilp32 novectors.s -o novectors.o
riscv32-none-elf-gcc -march=rv32ic -mabi=ilp32 -Wall -O2 -nostdlib -nostartfiles -ffreestanding -c notmain.c -o notmain.o
riscv32-none-elf-ld novectors.o notmain.o -T memmap -o notmain.elf
riscv32-none-elf-objdump -D notmain.elf > notmain.list
riscv32-none-elf-objcopy notmain.elf -O binary notmain.bin
, и вы можете увидеть, что он использует сжатые инструкции, где он может
20010000 <_start>:
20010000: 80004137 lui x2,0x80004
20010004: 00a000ef jal x1,2001000e <notmain>
20010008: 9002 ebreak
2001000a: a001 j 2001000a <_start+0xa>
2001000c <dummy>:
2001000c: 8082 ret
2001000e <notmain>:
2001000e: 1141 addi x2,x2,-16
20010010: c422 sw x8,8(x2)
20010012: c606 sw x1,12(x2)
20010014: 4401 li x8,0
20010016: 8522 mv x10,x8
20010018: 3fd5 jal 2001000c <dummy>
2001001a: 0405 addi x8,x8,1
2001001c: bfed j 20010016 <notmain+0x8>
, также довольно легко написать свой собственный эмулятор. Зависит от того, как вы хотите организовать обучение этой платформе. Сколько стоит освоение набора инструкций в сравнении с набором инструментов против конкретного чипа и его периферийных устройств.
Вам определенно нужны документы risc-v от riscv.org, которые соответствуют версии, поддерживаемой ядром, множеству внутренних регистров ядра и тому подобному, а также набору инструкций. А также начало работы и документация на чип для рассматриваемого чипа. Если вы хотите сделать свое дело. Если вы хотите играть в одной из их песочниц и использовать сторонние библиотеки, то вам нужно изучить их и играть в их песочнице, а не заниматься своими делами. Похоже, вы хотите заниматься своими делами.
Примечание. Я использую текущую версию gcc / binutils из основных источников gnu, созданную вручную.
riscv32-none-elf-gcc --version
riscv32-none-elf-gcc (GCC) 9.2.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
riscv32-none-elf-as --version
GNU assembler (GNU Binutils) 2.32
Copyright (C) 2019 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License version 3 or later.
This program has absolutely no warranty.
This assembler was configured for a target of `riscv32-none-elf'.
Приведенный выше код прекрасно работал несколько лет назад против оригинального hifive1, и этот стиль работает для основных версий gnu, и я использовал этот набор инструментов против других ядер riscv, поэтому, даже если у вас он старше, он все равно должен работать. Наиболее важным является сопоставление арки (-march) с наборами команд, поддерживаемыми ядром, или, по крайней мере, подмножество rv32i должно поддерживаться всеми ядрами, сжатые и умноженные, и такие не всегда поддерживаются.
Мой файл конфигурации openocd для первой платы
adapter_khz 10000
interface ftdi
ftdi_device_desc "Dual RS232-HS"
ftdi_vid_pid 0x0403 0x6010
ftdi_layout_init 0x0008 0x001b
ftdi_layout_signal nSRST -oe 0x0020 -data 0x0020
set _CHIPNAME riscv
jtag newtap $_CHIPNAME cpu -irlen 5 -expected-id 0x10e31913
set _TARGETNAME $_CHIPNAME.cpu
target create $_TARGETNAME riscv -chain-position $_TARGETNAME
$_TARGETNAME configure -work-area-phys 0x80000000 -work-area-size 10000 -work-area-backup 1
flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME
init
openocd -f riscv.cfg в одном терминале / окне, а затем telnet localhost 4444 в другом.
Теперь, насколько нюанс ассемблера gnu васмы просим вас увидеть ассемблер gnu, или даже лучше использовать как можно меньше специфических ассемблерных / инструментальных цепочек, как это возможно, и / или вы можете менять инструменты когда-нибудь. YMMV
Инструменты GNU не знают эту доску из дыры в стене. вы рассказываете инструментам gnu об архитектуре ядра процессора и в скрипте компоновщика карту памяти. Ваш код, прямо или косвенно (если вы используете чей-либо сценарий начальной загрузки и скрипт компоновщика), должен соответствовать загрузочным свойствам ядра процессора, будь то RISC-V из Siveive или какое-либо ядро ARM, MIPS или X86 и т. Д. Векторная таблица или нет,выполнить по какому-либо адресу и т. д. В приведенном выше случае их загрузчик переходит на 0x20010000, поэтому вам нужно поместить первую инструкцию в 0x20010000, что выполняется, если эта инструкция будет первой в источнике начальной загрузки, и если она не указана в сценарии компоновщикасначала поместив этот объект в командную строку ld, и проанализировав разборку, чтобы убедиться, что она работает, прежде чем пытаться запустить ее на оборудовании. Ядра riscv, которые я использовал, не имеют векторной таблицы, для сброса они просто запускают выполнение с какого-то адреса. Таким образом, вы бы использовали тот же подход, если у вас не было перехода к предварительному загрузчику. Для других архитектур, не относящихся к risc-v, построение программы для платы / платформы будет отличаться, если это переход к объекту адреса по сравнению с элементом таблицы вектора.
Теперь говорят, что если вы используете их песочницу, тоэто вопрос о песочнице, а не вопрос о наборе инструментов gnu.
Документация и / или веб-сайт платы указывают на то, что плата rev b использует микросхему FE310-G002 в документации FE310-G002, которую вы найдетекарта памяти. Это также указывает на то, что это архитектура risc-v, и из этого вы переходите к основанию riscv.org и получаете документацию для этой архитектуры, в которой рассказывается, как она загружается. И обратно в FE310-G002 он сообщает вам процесс загрузки с выводов MSEL. Который вам нужно будет изучить схемы. Таким образом, реальность такова, что их документация говорит вам, как указать, что это программа загрузчика, предоставляя информацию, которую вы должны предоставить gnu.
Говоря, что ... некоторые эксперименты желательны / необходимы. Можно / легко написать простой бесконечный цикл позиции, построить для 0x00000000, но загрузить в 0x20010000 на основе их документации и использовать openocd, чтобы проверить счетчик программы, чтобы увидеть, действительно ли он основан на 0x20010000. Исходя из этого, вы можете предположить, что в конечном итоге при поставке плата проходит через свой загрузчик к вам через любой выбранный MSEL.
Хммм:
При включении питания вектор сброса ядра0x1004.
И далее указываются разные адреса первых команд для каждого из вариантов ремешка MSEL. Поэтому, если вы возьмете на себя их загрузчик и замените его своим собственным, основываясь на документации, вы бы связали 0x20000000 и имели бы точку входа там.