FPGA開発日記

カテゴリ別記事インデックス https://msyksphinz.github.io/github_pages , English Version https://fpgadevdiary.hatenadiary.com/

HiFive1のプログラムコンパイルをArduinoIDEを使わずに制御したい(2. OpenOCDを使ったHiFiveへのプログラム書き込み)

前回の続き、今回は、OpenOCDを使って、コンパイルしたバイナリファイルをHiFive1に書き込み、実行する。

msyksphinz.hatenablog.com

OpenOCDを使った書き込みシーケンスを探す

Arduinoディレクトリを探して、OpenOCDを使ったバイナリファイルへのアップロードをしているスクリプトを見つけた。

  • packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/tools/openocd_upload.sh

あーこれだな。これにバイナリファイルと、構成ファイルを指定すればHiFive1への書き込みができるに違いない。

export PATH=/home/masayuki/.arduino15/packages/sifive/tools/openocd/9bab0782d313679bb0bfb634e6e87c757b8d5503/bin/:${PATH}
./packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/tools/openocd_upload.sh /home/masayuki/work/hifive1/uart_test/uart_test ./packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/env/freedom-e300-hifive1/openocd.cfg

openocd.cfgファイルは、ボードの情報、JTAGの書き込み速度などの情報を持っているスクリプトだ。

adapter_khz     10000

interface ftdi
ftdi_device_desc "Dual RS232-HS"
ftdi_vid_pid 0x0403 0x6010
...
flash bank onboard_spi_flash fespi 0x20000000 0 0 0 $_TARGETNAME
init
#reset -- This type of reset is not implemented yet
if {[ info exists pulse_srst]} {
  ftdi_set_signal nSRST 0
  ftdi_set_signal nSRST z
  #Wait for the reset stretcher
  #It will work without this, but
  #will incur lots of delays for later commands.
  sleep 1500
}
halt
#flash protect 0 64 last off

という訳で実行してみた。無事に書き込みが行われ、プログラムが実行されたようだ。

$ ./packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/tools/openocd_upload.sh /home/masayuki/work/hifive1/uart_test/uart_test ./packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/env/freedom-
e300-hifive1/openocd.cfg
+ openocd -f ./packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/env/freedom-e300-hifive1/openocd.cfg -c 'flash protect 0 64 last off; program /home/masayuki/work/hifive1/uart_test/uart_test verify; resume 0x20400000; exit'
+ tee openocd_upload.log
Open On-Chip Debugger 0.10.0-dev-g9bab078 (2017-02-02-01:39)
Licensed under GNU GPL v2
For bug reports, read
        http://openocd.org/doc/doxygen/bugs.html
adapter speed: 10000 kHz
Info : auto-selecting first available session transport "jtag". To override use 'transport select <transport>'.
Info : ftdi: if you experience problems at higher adapter clocks, try the command "ftdi_tdo_sample_edge falling"
Info : clock speed 10000 kHz
Info : JTAG tap: riscv.cpu tap/device found: 0x10e31913 (mfg: 0x489 (<unknown>), part: 0x0e31, ver: 0x1)
Info : dtmcontrol_idle=5, dbus_busy_delay=1, interrupt_high_delay=0
Info : dtmcontrol_idle=5, dbus_busy_delay=1, interrupt_high_delay=1
Info : Examined RISCV core; XLEN=32, misa=0x40001105
Info : dtmcontrol_idle=5, dbus_busy_delay=1, interrupt_high_delay=2
Info : dtmcontrol_idle=5, dbus_busy_delay=1, interrupt_high_delay=3
Info : dtmcontrol_idle=5, dbus_busy_delay=1, interrupt_high_delay=4
Info : dtmcontrol_idle=5, dbus_busy_delay=1, interrupt_high_delay=5
...
Info : dtmcontrol_idle=5, dbus_busy_delay=2, interrupt_high_delay=249
Info : Retrying memory read starting from 0x20400000 with more delays
Info : dtmcontrol_idle=5, dbus_busy_delay=2, interrupt_high_delay=274
Info : Retrying memory read starting from 0x20400000 with more delays
Info : dtmcontrol_idle=5, dbus_busy_delay=2, interrupt_high_delay=302
Info : Retrying memory read starting from 0x20400000 with more delays
Info : dtmcontrol_idle=5, dbus_busy_delay=2, interrupt_high_delay=333
Info : Retrying memory read starting from 0x20400000 with more delays
verified 4492 bytes in 0.361002s (12.152 KiB/s)
** Verified OK **
halted at 0x20400004 due to step

f:id:msyksphinz:20170315011506p:plain

あ、しまった'A'ばかり表示するプログラムだった!

ま、これで一応C/C++で記述したコードが曲りなりに動作した。今度は、core.aに頼らないネイティブなコードを動かせるようになろう。

HiFive1のプログラムコンパイルをArduinoIDEを使わずに制御したい(1. C/C++コードのコンパイル)

HiFive1を使ったプログラムは、まだ時間が無くてLチカとUARTのテストくらいしか出来ていないが、早くもArduinoIDEに不満が出てきた。

可能ならばEmacsでプログラムを書きたいし、Makeを使ってコンパイルやダウンロードができるようになるとうれしい。

そこで、Arduinoコンパイルフローをトレースすることで、これをMakefileに直接インポートし、ArduinoIDEを経由せずにC/C++でHiFive1用プログラムが書けるなろう。 まずは、C/C++のプログラムでUARTに書き込みを行えるようになるところからかな。

ArduinoIDEのコンパイルシーケンス

ArduinoIDEを使った場合の、HiFive1用プログラムのコンパイルシーケンスは過去の記事で確認した。

msyksphinz.hatenablog.com

UARTへのprintは結局何が起きているのか

これはHiFive1以外で同じことが言えるだろうが、UARTの書き込みは主に2つのシーケンスで成り立っている。

  • Serial.begin(baud) UARTの初期化とボーレートの設定
  • Serial.write(char) UARTへの書き込み

これらのプログラムは、結局以下のC++のコードで記述されている。

UARTClass::begin(unsigned long bauds)
{
  GPIO_REG(GPIO_OUTPUT_XOR)&= ~(IOF0_UART0_MASK);
  GPIO_REG(GPIO_IOF_SEL)   &= ~(IOF0_UART0_MASK);
  GPIO_REG(GPIO_IOF_EN)    |= IOF0_UART0_MASK;

  //F_Baud = f_in/(div+1)

  UART_REG(UART_REG_DIV) = F_CPU / bauds - 1;
  UART_REG(UART_REG_TXCTRL) |= UART_TXEN;
  UART_REG(UART_REG_RXCTRL) |= UART_RXEN;


//  sio_setbaud(bauds);
}

UARTClass::write(const uint8_t uc_data)
{

  sio_putchar(uc_data, 1);
  return (1);
}

UARTClass::sio_putchar(char c, int blocking)
{
  volatile uint32_t *val = UART_REGP(UART_REG_TXFIFO);
  uint32_t busy = (*val) & 0x80000000;
  if (blocking) {
    while (*val & 0x80000000);
  } else if (busy) {
      return 1;
  }
  UART_REG(UART_REG_TXFIFO) = c;
  return 0;
}

じゃあ、これをそのままCのコードに持ってくればよかろう。

#include "./platform.h"

#include "./variant.h"
#include "./uart.h"
#include "./gpio.h"

void setup()
{
  int bauds = 9600;
  GPIO_REG(GPIO_OUTPUT_XOR)&= ~(IOF0_UART0_MASK);
  GPIO_REG(GPIO_IOF_SEL)   &= ~(IOF0_UART0_MASK);
  GPIO_REG(GPIO_IOF_EN)    |= IOF0_UART0_MASK;

  UART_REG(UART_REG_DIV) = F_CPU / bauds - 1;
  UART_REG(UART_REG_TXCTRL) |= UART_TXEN;
  UART_REG(UART_REG_RXCTRL) |= UART_RXEN;
}

void loop()
{
  const int blocking = 1;

  volatile uint32_t *val = UART_REGP(UART_REG_TXFIFO);
  uint32_t busy = (*val) & 0x80000000;
  if (blocking) {
    while (*val & 0x80000000);
  } else if (busy) {
      return;
  }
  UART_REG(UART_REG_TXFIFO) = 'A';
  return;
}

setup()loop()を使っているのは、まだArduinoの生成するcore.aを使うからだ。これは、最終的には取り外せて直接main()から記述出来るようになりたい。

テストプログラムをコンパイルするためのMakefile

以下のようなMakefileを作成した。

  • riscv32-unknown-elf-gccgithubで公開されているものを使おうとしたが、何故か-march=rv32imacが認識されずに、Arduino用に(自動)ダウンロードされたgccを利用した。手動インストールしたものは古いからだろうか?もう一度最新版にアップデートしてやり直してみたい。
  • リンカスクリプトとして$(PACKAGE_BASE)/freedom-e-sdk/bsp/env/freedom-e300-hifive1/link.ldsを指定している。これはArduinoが指定しているリンカスクリプトをそのまま利用している。
  • F_CPU=16000000はこちらもArduinoIDEでのコンパイルオプションで定義してあったので追加した。だけどHiFiveって320MHz動作じゃなかったっけ?
TARGET = uart_test

# ARCH = riscv32-unknown-elf-
ARCH = ~/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-
CC = $(ARCH)g++

OBJ_FILES = entry.o init.o start.o

PACKAGE_BASE = ~/.arduino15/packages/sifive/hardware/riscv/1.0.2
LINKER = $(PACKAGE_BASE)/freedom-e-sdk/bsp/env/freedom-e300-hifive1/link.lds
INC_PATH += $(PACKAGE_BASE)/freedom-e-sdk/bsp/env/freedom-e300-hifive1/
INC_PATH += $(PACKAGE_BASE)/freedom-e-sdk/bsp/env/
INC_PATH += $(PACKAGE_BASE)/freedom-e-sdk/bsp/include/
INC_PATH += $(PACKAGE_BASE)/freedom-e-sdk/bsp/include/sifive/devices/
INC_PATH += $(PACKAGE_BASE)/variants/standard/
INC_PATH += $(PACKAGE_BASE)/cores/arduino/

DEF_PARAM += F_CPU=16000000
DEF_PARAM += FREEDOM_E300_HIFIVE1
DEF_PARAM += __riscv_float_abi_soft

INCLUDE = $(addprefix -I, $(INC_PATH))
DEFINE  = $(addprefix -D, $(DEF_PARAM))

CFLAGS += -march=rv32imac $(INCLUDE) $(DEFINE)

all: $(TARGET)

%.o: %.c
  $(CC) $(CFLAGS) -c $<
%.o: %.S
  $(CC) $(CFLAGS) -c $<

# $(TARGET): $(TARGET).o $(OBJ_FILES)
$(TARGET): $(TARGET).o
  $(CC) $(CFLAGS) -nostartfiles -nostdlib -Wl,-N -Wl,--gc-sections -Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=sbrk -Wl,--start-group "~/Arduino/core/core.a" -lm -lc -lgloss -Wl,--end-group -lgcc -T$(LINKER) $^ -o $@

clean:
  rm -rf *.o $(TARGET)

最後にcore.aを追加しているが、これは以前ArduinoIDEでプログラムをコンパイルした際に自動的に生成されたもので、こちらにいくつか定数が入っていたのでとりあえずやむを得ず追加した。 最終的にはこれも除去し、必要最低限のファイル群でプログラムを生成できるようになりたい。

core.aは以下のように作られている。でも、entry.S, init.S, start.S`があればとりあえず十分じゃないかなあ?glibcなどを使い始めると面倒だけど。

"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/entry.S.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/init.S.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/start.S.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/WInterrupts.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/hooks.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/itoa.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/malloc.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/sbrk.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/wiring.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/wiring_analog.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/wiring_digital.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/wiring_shift.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/drivers/fe300prci/fe300prci_driver.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/drivers/plic/plic_driver.c.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/Print.cpp.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/UARTClass.cpp.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/WMath.cpp.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/WString.cpp.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/abi.cpp.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/main.cpp.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/new.cpp.o"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-ar" rcs  "/home/msyksphinz/Arduino/core/core.a" "/home/msyksphinz/Arduino/core/wiring_pulse.cpp.o"

これでプログラムをコンパイルできた。uart_testはちゃんとRISC-V互換バイナリとなっている。

$ file uart_test
uart_test: ELF 32-bit LSB executable, UCB RISC-V, version 1 (SYSV), statically linked, not stripped

次は、OpenOCDを使ってHiFive1ボードへ書き込みを行う。

HiFive1におけるシリアル通信

HiFive1を使って、PCとのシリアル通信を実行する。

やり方は非常に簡単だ。プログラムはArduinoのサンプルからコピーしてきた。

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);

  Serial.print("RISC-V HiFive1 Start\r\n");
}

void loop() {
  // put your main code here, to run repeatedly:
  int c;

  if (Serial.available() > 0) {
    c = Serial.read();
 
    Serial.write(c);
  }
}

HiFive1のバグか、そもそも仕様なのか、setup()内で大量にprintをしていると途中で固まる気がする。

f:id:msyksphinz:20170314221807p:plain

asciinema.org

これ、最初はあまり気が付かなかったのだけれども、そのままC++のプログラムなんだな。

loop()main()内で何度も動作しているし、setup()main()の最初で動作している。 Serialはクラスとして定義されており、Serial.print()はクラスのメンバ関数として定義されている。

~/.arduino15/packages/sifive/hardware/riscv/1.0.2には、HiFive1用の各種関数群などが用意されている。

23:#include "HardwareSerial.h"
25:class UARTClass : public HardwareSerial
class HardwareSerial : public Stream
class Stream : public Print
class Print
{
...

    size_t print(const __FlashStringHelper *);
    size_t print(const String &);
    size_t print(const char[]);
    size_t print(char);
    size_t print(unsigned char, int = DEC);
    size_t print(int, int = DEC);
    size_t print(unsigned int, int = DEC);
    size_t print(long, int = DEC);
    size_t print(unsigned long, int = DEC);
    size_t print(double, int = 2);
    size_t print(const Printable&);
...
};

VerilogのSpecifyブロックまとめ

ちょっとVerilogのSpecify記述をいろいろチェックする機会があったので、ここでまとめておく。

VerilogのSpecifyブロック内では、主にセットアップ時間、ホールド時間などを記述するが、それ以外にもさまざまな制約条件などを指定することが出来る。

specify
  // タイミング制約事項など記述する。
  $setup (posedge clk, ...);
endspecify

specifyブロックには、以下のような制約チェックタスクを記述することが出来る。

以下の記事を参考にした。

verilog.renerta.com

  • $setup (data_event, reference_event, limit[, notifier]) ;
  • $skew (reference_event, data_event, limit[,notifier]) ;
  • $hold (reference_event, data_event, limit[,notifier]) ;
  • $recovery (reference_event, data_event, limit, [notifier]) ;
  • $setuphold (reference_event, data_event, setup_limit, hold_limit, [notifier]) ;
  • $width (reference_event, limit, threshold [,notifier]) ;
  • $period (reference_event, limit[,notifier]) ;
  • $nochange (reference_event, data_event, start_edge_offset, end_edge_offset [,notifier]) ;

setup

セットアップタイムの制約を記述する。データのFFへの到着がリファレンスイベントのある一定時間よりも前に完了しておく必要があるというもの。 以下の図において、赤の期間にデータを変化させることは禁止となる。

f:id:msyksphinz:20170313231252p:plain

以下の条件を満たした場合、違反となる。

(time of reference event) - (time of data event) < limit

skew (reference_event, data_event, limit[,notifier]) ;

以下の条件を満たした場合、違反となる。

(time of data event) - (time of reference event) > limit

クロック間のタイミング調整についての制約となる。あるデータのエッジに対して、それを受け取るクロックのエッジがずれている場合に違反となる。

hold (reference_event, data_event, limit[,notifier]) ;

以下の条件を満たした場合、違反となる。

(time of data event) - (time of reference event) < limit

リファレンスのクロックに対して、データの到着が早すぎる場合、hold違反となる。通常これはFFの付きぬけを防止するためのもので、hold違反となった場合はバッファなどを挿入して遅延を挿入する。

以下の図において、赤の期間にデータを変化させることは禁止となる。

f:id:msyksphinz:20170313231340p:plain

recovery (reference_event, data_event, limit, [notifier]) ;

以下の条件を満たす場合に違反となる。等式としてはholdと同一だが、使い分けがあるのだろうか?また、reference eventはエッジトリガでなければならない。

(time of data event) - (time of reference event) < limit

setuphold (reference_event, data_event, setup_limit, hold_limit, [notifier]) ;

setupタイムとholdタイムを同時にチェックする。

width (reference_event, limit, threshold [,notifier]) ;

リファレンスイベントの間隔をチェックする。以下を条件を満たした場合、違反となる。data eventは明示されていないが、デフォルトでは、reference eventの逆エッジとなる。 つまり、あるエッジから逆エッジまでの期間が、threasholdよりも大きく、limitよりも小さい場合に、違反となる。

threshold < (time of data event) - (time of reference event) < limit

period (reference_event, limit[,notifier]) ;

等式としてはrecovery, holdと同一である。ある信号が十分に長いかどうかをチェックしている。

(time of data event) - (time of reference event) < limit

nochange (reference_event, data_event, start_edge_offset, end_edge_offset [,notifier]) ;

data_eventが、start_edge_offsetから、end_edge_offsetの間に変化した場合に、違反がレポートされる。

HiFive1のでのArduinoプログラム コンパイル結果の解析

Arduinoのプログラムをコンパイルするとき、最初にターゲットボードを指定して、対応するGCCなどをインストールした。 GCCを利用しているはずなので、コンパイル結果やオブジェクトなどがどこかに生成されているはずだ。 調査してみると、以下のArduino IDEの設定をすることでコンパイル結果などの情報を出力することが可能らしい。

d.hatena.ne.jp

  1. Arduino IDE の [ファイル]>[環境設定] で、preference.txt の場所を確認する。

f:id:msyksphinz:20170311160523p:plain

  1. preference.txtを編集する。以下を追加した。
build.path=/home/masayuki/Arduino/
build.verbose=true

これでBlink.inoをコンパイルするとさまざまな情報が出力されるようになった。 実際に、Blink.inoをコンパイルすると、以下のようなビルドログが生成された。

/home/msyksphinz/work/software/arduino-1.8.1/arduino-builder -dump-prefs -logger=machine -hardware /home/msyksphinz/work/software/arduino-1.8.1/hardware -hardware /home/msyksphinz/.arduino15/packages -tools /home/msyksphinz/work/softwa-1.8.1/tools-builder -tools /home/msyksphinz/work/software/arduino-1.8.1/hardware/tools/avr -tools /home/msyksphinz/.arduino15/packages -built-in-libraries /home/msyksphinz/work/software/arduino-1.8.1/libraries -libraries /home/msyksphinz/Arduino/libraries -fqbn=sifive:riscv:hifive1:toolsloc=default,clksrc=hfxtal -ide-version=10801 -build-path /home/msyksphinz/Arduino -warnings=none -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.riscv32-unknown-elf-gcc.path=/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f -prefs=runtime.tools.openocd.path=/home/msyksphinz/.arduino15/packages/sifive/tools/openocd/9bab0782d313679bb0bfb634e6e87c757b8d5503 -verbose /home/msyksphinz/Blink/Blink.ino
/home/msyksphinz/work/software/arduino-1.8.1/arduino-builder -compile -logger=machine -hardware /home/msyksphinz/work/software/arduino-1.8.1/hardware -hardware /home/msyksphinz/.arduino15/packages -tools /home/msyksphinz/work/software/arduino-1.8.1/tools-builder -tools /home/msyksphinz/work/software/arduino-1.8.1/hardware/tools/avr -tools /home/msyksphinz/.arduino15/packages -built-in-libraries /home/msyksphinz/work/software/arduino-1.8.1/libraries -libraries /home/msyksphinz/Arduino/libraries -fqbn=sifive:riscv:hifive1:toolsloc=default,clksrc=hfxtal -ide-version=10801 -build-path /home/msyksphinz/Arduino -warnings=none -prefs=build.warn_data_percentage=75 -prefs=runtime.tools.riscv32-unknown-elf-gcc.path=/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f -prefs=runtime.tools.openocd.path=/home/msyksphinz/.arduino15/packages/sifive/tools/openocd/9bab0782d313679bb0bfb634e6e87c757b8d5503 -verbose /home/msyksphinz/Blink/Blink.ino

このとき、/home/msyksphinz/Arduino/sketch/Blink.ino.cppが生成されていた。 確かに、ArduinoのプログラムはC/C++と非常に似通っているが、どこが異なるのだろう。

  • diff sketch/Blink.ino.cpp ~/work/software/arduino-1.8.1/examples/01.Basics/Blink/Blink.ino
1,3d0
< #include <Arduino.h>
< #line 1 "/home/masayuki/Blink/Blink.ino"
< #line 1 "/home/masayuki/Blink/Blink.ino"
28,32d24
< #line 25 "/home/masayuki/Blink/Blink.ino"
< void setup();
< #line 31 "/home/masayuki/Blink/Blink.ino"
< void loop();
< #line 25 "/home/masayuki/Blink/Blink.ino"
45d36
<

あんまり違わない。というかこれはcppを通過させただけのようにも見える。

そして、生成されたプログラムはすべてriscv64-unknown-elf-gccを使ってコンパイルされていた。

スケッチをコンパイルしています...
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-g++" -c -O2 -march=rv32imac -fpeel-loops -ffreestanding -ffunction-sections -fdata-sections -fpermissive -Wall -fno-rtti -fno-exceptions -I/home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/system/include -I/home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/include -I/home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/env -I/home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/drivers -I/home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/env/freedom-e300-hifive1 -include sys/cdefs.h -g -DARDUINO=10801 -DF_CPU=16000000LL -DFREEDOM_E300_HIFIVE1  "-I/home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/cores/arduino" "-I/home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/variants/standard" "/home/msyksphinz/Arduino/sketch/Blink.ino.cpp" -o "/home/msyksphinz/Arduino/sketch/Blink.ino.cpp.o"
...
Linking everything together...
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-g++" -T /home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/env/freedom-e300-hifive1/link.lds -nostartfiles -Wl,-N -Wl,--gc-sections -Wl,--wrap=malloc -Wl,--wrap=free -Wl,--wrap=sbrk  "/home/msyksphinz/Arduino/sketch/Blink.ino.cpp.o" -nostdlib -Wl,--start-group "/home/msyksphinz/Arduino/core/core.a" -lm -lstdc++ -lc -lgloss -Wl,--end-group -lgcc -o "/home/msyksphinz/Arduino/Blink.ino.elf"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-objcopy" -R .rel.dyn -O binary "/home/msyksphinz/Arduino/Blink.ino.elf" "/home/msyksphinz/Arduino/Blin.ino.bin"
"/home/msyksphinz/.arduino15/packages/sifive/tools/riscv32-unknown-elf-gcc/3f7b3696217548bc31aeccf9a0c89bdfa4e16a8f/bin/riscv32-unknown-elf-objcopy" -R .rel.dyn -O srec "/home/msyksphinz/Arduino/Blink.ino.elf" "/home/msyksphinz/Arduino/Blink.ino.hex"
最大8388608バイトのフラッシュメモリのうち、スケッチが6932バイト(0%)を使っています。

Arduino/Blink.ino.elf をobjdumpすれば、大体中身が分かる。さらに、/home/msyksphinz/.arduino15/packages/sifive/hardware/riscv/1.0.2/freedom-e-sdk/bsp/env/freedom-e300-hifive1/link.ldsに格納されているリンカスクリプトを見れば、HiFive1のメモリアドレスマップも大体分かるわけだ。

riscv64-unknown-elf-objdump -D Blink.ino.elf  | less
20400000 <_start>:
20400000:       5fc01197                auipc   gp,0x5fc01
20400004:       c2818193                addi    gp,gp,-984 # 80000c28 <_gp>
20400008:       5fc04117                auipc   sp,0x5fc04
2040000c:       ff810113                addi    sp,sp,-8 # 80004000 <_sp>
20400010:       00001517                auipc   a0,0x1
20400014:       eac50513                addi    a0,a0,-340 # 20400ebc <__fini_array_end>
20400018:       5fc00597                auipc   a1,0x5fc00
2040001c:       fe858593                addi    a1,a1,-24 # 80000000 <_data>
20400020:       5fc00617                auipc   a2,0x5fc00
20400024:       41460613                addi    a2,a2,1044 # 80000434 <__bss_start>
20400028:       00c5fa63                bleu    a2,a1,2040003c <_start+0x3c>
2040002c:       00052283                lw      t0,0(a0)
...

HiFive1 の環境セットアップとサンプル実行

HiFive1の実行環境を早速構築しよう。まずはすでにHiFiveを使っている方がいらっしゃるので、それを参考に。

qiita.com

HiFive1の実行のためには、Arduino IDEをインストールする必要がある。僕はWindowsユーザなのでWindowsにインストールしようと思ったが、どうやらツールチェインがWindowsでは実行できないようだ。

確かに、RISC-VのGCCなど、Windows版は存在しないしなあ。

f:id:msyksphinz:20170311114042p:plain

そこでUbuntu Linux仮想マシンで立ち上げ、Arduino IDEをインストールした。 こちらだと、ツールチェインもダウンロードできる。

f:id:msyksphinz:20170311114134p:plain

f:id:msyksphinz:20170311114128p:plain

HiFive1ボードを接続して認識させる

HiFive1のボードを、仮想マシンとして実行されているUbuntuに接続しなければならないのだが、これはVirtualBoxの設定で、USBをUbuntu側に認識させる。 FTDI Dual RS232-HSを追加すれば良いのかな。

f:id:msyksphinz:20170311114231p:plain

さらに、dmesgでデバイスを確認する。

$ dmesg | tail
[157958.226380] usbserial: USB Serial support registered for generic
[157958.245744] usbcore: registered new interface driver ftdi_sio
[157958.245781] usbserial: USB Serial support registered for FTDI USB Serial Device
[157958.245814] ftdi_sio 1-3:1.0: FTDI USB Serial Device converter detected
[157958.245838] usb 1-3: Detected FT2232H
[157958.259902] usb 1-3: FTDI USB Serial Device converter now attached to ttyUSB0
[157958.261143] ftdi_sio 1-3:1.1: FTDI USB Serial Device converter detected
[157958.261183] usb 1-3: Detected FT2232H
[157958.268871] usb 1-3: FTDI USB Serial Device converter now attached to ttyUSB1
[screen is terminating]: reset full-speed USB device number 6 using ohci-pci

tt-y-USB1として追加された。まずは、Arduinoとして起動するメッセージをコンソールから見てみよう。

下記を実行して、HiFive1上のリセットボタン(赤色)を押す。

screen /dev/ttyUSB1  115200

f:id:msyksphinz:20170311115031p:plain

起動した。

LED Blinkの例を動かしてみる

Lチカの例を実行してみる。こちらもQittaで既に行われているものだが、とりあえず真似事としてやってみた。

qiita.com

f:id:msyksphinz:20170311115159p:plain

サンプルを開き、「書き込み装置を使って書き込む」を実行する。

f:id:msyksphinz:20170311115251g:plain

動いた!

f:id:msyksphinz:20170311120843p:plain

RISC-VのArduino(HiFive)が我が家にやってきたよ

マルツオンラインが、RISC-VのArduinoボード、HiFive1を取り扱い始めた。

www.marutsu.co.jp

これまで海外で購入可能だったが、海外サイトでわざわざ購入するのが億劫で買っていなかったのだが、マルツだと安心。 購入して即日で届く速さだった。

まだ開封しただけで、ソフトウェアの環境などは用意していないが、ボチボチ構築していこう。

さて、これで何して遊ぼうかな(買ったは良いが何をするか決めていない)。

f:id:msyksphinz:20170307010142p:plain

f:id:msyksphinz:20170307010200p:plain