目次: Zephyr
Zephyr RISC-V SMP対応にチャレンジしてます。
Zephyrは既に他のアーキテクチャでSMP対応されていますから、真似するだけの何がチャレンジなの?簡単でしょ?と思われるかもしれません。その考え方は間違ってないんですが、少なくとも私にとっては「余裕」と言えるほど簡単ではなさそうです。
RISC-V向けの実装はAArch32をパクっているようで「お前、シングルコアだろ?な?」的な実装がそこら中にあり、SMPを有効にした途端、猛烈にコンパイルエラーが出ます。
一個一個見てますが、先ほど、コンテキストスイッチから直さないとダメなことに気づきました。こりゃ先は長そうだ〜……。
 この記事にコメントする
 この記事にコメントする
目次: Windows
今に始まったことではないのですが、Windows 10が突然高負荷に陥ってしまうことがあります。大抵Windows Updateが裏で動いているだけのことが多いですが、今日は様子が違ったのでメモしておきます。
いつもと違う点、その1は、Systemプロセスが高負荷に陥っていることです。Windows Updateが裏で実行されている場合、マウスを動かしたりキーボードに触ったりすると負荷が下がります。今回はマウスを触っても負荷が下がりません。
Process Explorerで見るとPsReturnProcessNonPagedPoolQuota() という関数がめちゃくちゃ頑張っていました。なんでしょうね?これ?
 この記事にコメントする
 この記事にコメントする
NVIDIAがArm全株式買収、ソフトバンクGから最大400億ドルで - ケータイWatch を読んで。
NVIDIAがArm買収です。買収額の2/3は株式交換で、ソフトバンクはNVIDIAの大株主になります。買収が成立すれば、ソフトバンクは1兆円超の利益を得ます。
ArmがNVIDIA配下となれば、NVIDIAと思い切り食い合う、Ethos(エッジAIプロセッサ)とMali(モバイル向けGPU)はゴミ箱行きですかね?ディスコンにしなくても、まともに開発しなくなりそうです。
さらにNVIDIAはNVIDIA GPUをライセンスするメリットがない(自分で作れる)ので、組み込み業界はImagination PowerVRとArm Maliという2大モバイルGPU IPを揃って失ってしまう悲しい未来になりそうです。
他陣営(RISC-Vとか)はまともなGPU IPがありませんし、Armがどんな地獄になろうとも、グラフィック必須のスマホ系SoCベンダーに逃げ場はなく、Armで作り続けるしかありません。
Armの築いたエコシステムがArmごとひっくり返されるとは思いませんでしたね。耐震構造のビルを建てていたら、いきなり一面の海になるような……バグったゲームみたいですが、現実なんですよね。
中国はImaginationごとPowerVRを買ってるので、ArmもしくはRISC-V用にPowerVRを売り出す可能性はあります(もう売ってる?)けど、PowerVRって性能的に今の時代のGPUに追いついているんでしょうか??
メモ: 技術系?の話はFacebookから転記しておくことにした。
 この記事にコメントする
 この記事にコメントする
目次: FreeRTOS
FreeRTOSにRISC-V QEMU virtpcのパッチをぶん投げてみました。やり方はGitHubでプルリクエストを送れば良いみたいです(説明へのリンク(FreeRTOS/CONTRIBUTING.md))。
FreeRTOSには既にQMEUのプロジェクトはある(SiFive HiFive1エミュレーション環境向けのEclipseプロジェクトがある)から要らないよ!?と言われることが目に浮かびますが、それならそれで良し。今後なにかの役に立つでしょう。
FreeRTOSはインデントやコード記法が非常に特徴的で、とても書きにくかったです。
void vFunc( int aaa )
{
int xBbb;
    if( aaa )
    {
        /* do something */
        xBbb = 0;
    }
}
クセが強すぎる。何でこんな記法にしたのやら……??
メモ: 技術系?の話はFacebookから転記しておくことにした。色々と加筆。
 この記事にコメントする
 この記事にコメントする
自動車業界(だけじゃないですが)で重宝されているMATLABを家で使えることになったので、インストールしてみました。
ダウンロードは Mathworksのサイトからできますが、たぶん会社や学校からもらえるアカウント、アクティベーション番号が必要です。MATLABは個人でも買えますがメチャクチャ値段が高く、私は買う気は起きません……。
MATLABはDebian 9, Debian 10には対応しています(System Requirements for MATLAB R2020a - MATLAB & Simulink)が、Debian Testingには対応していません。インストーラを起動した瞬間にクラッシュします。
$ cd matlab_archive $ unzip matlab_R2020a_glnxa64.zip $ ./install terminate called after throwing an instance of 'std::runtime_error' what(): Unable to launch the MATLABWindow application Aborted
ありがたいことに、Linux向けのMATLABインストーラは通常版とlegacy版が同梱されています。
$ cd matlab_archive $ unzip matlab_R2020a_glnxa64.zip $ bin/glnxa64/install_unix_legacy
推奨された使い方ではないと思いますがlegacy版ならばインストーラが動きます。質問にはハイハイ答えておけば、そんなに問題ないはずです。
MATLABを起動するときに変なエラーが出ます。
$ matlab MATLAB is selecting SOFTWARE OPENGL rendering. matlab_install_dir/bin/glnxa64/jcef_helper: symbol lookup error: /usr/lib/x86_64-linux-gnu/libpango-1.0.so.0: undefined symbol: g_ptr_array_copy
このエラーはMATLABの動的ライブラリの構成がおかしいことが原因です。libglib-2.0.soをMATLAB内部に抱えているのですが、libpango-1.0.soはシステム側を使うため、バージョンの非互換が発生します。libpango-1.0.soも内部に抱えれば良いのに??何だか中途半端な作りですね。
$ ldd bin/glnxa64/jcef_helper | grep glib libglib-2.0.so.0 => matlab_install_dir/bin/glnxa64/../../cefclient/sys/os/glnxa64/libglib-2.0.so.0 (0x00007f43ac828000) ★MATLAB内部に抱えているライブラリをダイナミックリンクする $ cd matlab_install_dir/cefclient/sys/os/glnxa64 $ mv libglib-2.0.so _libglib-2.0.so $ mv libglib-2.0.so.0 _libglib-2.0.so.0 $ mv libglib-2.0.so.0.5600.1 _libglib-2.0.so.0.5600.1 $ ldd bin/glnxa64/jcef_helper | grep glib libglib-2.0.so.0 => /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0 (0x00007f10b2e6d000) ★システム側のライブラリをダイナミックリンクする
MATLABの内部で抱えているlibglib-2.0.soを無視して、システム側のlibglib-2.0.soをダイナミックリンクすればエラーは出ません。これも推奨された使い方ではないと思いますが、とりあえず動いたのでめでたしめでたし。
 この記事にコメントする
 この記事にコメントする
目次: FreeRTOS
目次: 一覧の一覧
 この記事にコメントする
 この記事にコメントする
目次: FreeRTOS
前回UARTドライバとmain() 関数を実装しました。今回はmain() に至るまでのブート部分を実装します。ざっくり言うとアセンブラで書いたスタートコードと、リンカスクリプトが必要です。
RISC-V QEMU virtマシンのメモリマップは下記のようになっています。使わないハードウェアは載せていません。
今回はRAMの一部をROMの代わりとして使います。0x80000000は本来RAMですがROMの代わりとして扱います。0x80080000以降をRAMとして扱います。本当はSPI Flash ROMを使ったほうが良いですが、手抜き実装です。リンカスクリプトは下記のようにしました。
OUTPUT_ARCH( "riscv" )
ENTRY( _start )
MEMORY
{
	rom (rxa) : ORIGIN = 0x80000000, LENGTH = 512K
	ram (wxa) : ORIGIN = 0x80080000, LENGTH = 512K
}
SECTIONS
{
	.init :
	{
		_text = .;
		KEEP (*(SORT_NONE(.init)))
	} >rom AT>rom
	
	.text :
	{
		*(.text.unlikely .text.unlikely.*)
		*(.text.startup .text.startup.*)
		*(.text .text.*)
		*(.gnu.linkonce.t.*)
	} >rom AT>rom
	
	.fini :
	{
		KEEP (*(SORT_NONE(.fini)))
		_etext = .;
	} >rom AT>rom
	.rodata.align :
	{
		. = ALIGN(4);
		_rodata = .;
	} >rom AT>rom
	.rodata.start :
	{
		_rodata_lma = LOADADDR(.rodata.start);
	} >rom AT>rom
	.rodata :
	{
		*(.rdata)
		*(.rodata .rodata.*)
		*(.gnu.linkonce.r.*)
		. = ALIGN(4);
		_erodata = .;
	} >rom AT>rom
	.data.align :
	{
		. = ALIGN(4);
		_data = .;
	} >ram AT>rom
	.data.start :
	{
		_data_lma = LOADADDR(.data.start);
	} >ram AT>rom
	.data :
	{
		*(.data .data.*)
		*(.gnu.linkonce.d.*)
		. = ALIGN(8);
		PROVIDE( __global_pointer$ = . + 0x800 );
		*(.sdata .sdata.*)
		*(.sdata2 .sdata2.*)
		*(.gnu.linkonce.s.*)
		. = ALIGN(8);
		*(.srodata.cst16)
		*(.srodata.cst8)
		*(.srodata.cst4)
		*(.srodata.cst2)
		*(.srodata .srodata.*)
		. = ALIGN(4);
		_edata = .;
	} >ram AT>rom
	.bss.align :
	{
		. = ALIGN(4);
		_bss = .;
	} >ram AT>rom
	.bss.start :
	{
		_bss_lma = LOADADDR(.bss.start);
	} >ram AT>rom
	.bss :
	{
		*(.sbss*)
		*(.gnu.linkonce.sb.*)
		*(.bss .bss.*)
		*(.gnu.linkonce.b.*)
		*(COMMON)
		. = ALIGN(4);
		_ebss = .;
	} >ram AT>rom
	. = ALIGN(8);
	_end = .;
	.stack :
	{
		. = ALIGN(16);
		_stack0_bottom = .;
		. += __stack_size;
		_stack0_top = .;
	} >ram AT>ram
}
ビルドしたバイナリをnmやreadelfで見るときわかりやすくするために、あえて変なセクション(.*.align, .*.start)をいくつか作っています。このように見えます。
$ riscv64-unknown-elf-nm -n a.out | less ★.bss.alignにALIGN(4) と書いたとき 80002ea8 R __clz_tab 80002fa8 A _data_lma 80002fa8 R _erodata ★.rodataの終わり(ROM領域を0x80000000としている) 80002fb8 A _bss_lma 80080000 D _data ★.dataの始まり(RAM領域を0x80080000としている) 80080000 D pullNextTime 80080008 D uxTimerIncrementsForOneTick 8008000c D xISRStackTop 80080010 B _bss ★.bssの始まり ★4bytes alignになっている(.dataの終わりと連続している) 80080010 D _edata ★.dataの終わり 80080010 b xQueue ... ★.data.alignにALIGN(2048) と書いたとき 80002ca8 R __clz_tab 80002da8 A _data_lma 80002da8 R _erodata ★.rodataの終わり(ROM領域を0x80000000としている) 80002db8 A _bss_lma 80080000 D _data ★.dataの始まり(RAM領域を0x80080000としている) 80080000 D pullNextTime 80080008 D uxTimerIncrementsForOneTick 8008000c D xISRStackTop 80080010 D _edata ★.dataの終わり 80080800 D __global_pointer$ 80080800 B _bss ★.bssの始まり ★2KB alignになっている(.dataの終わりと連続して「いない」) 80080800 b xQueue ... $ riscv64-unknown-elf-readelf -a a.out | less ★.bss.alignにALIGN(4) と書いたとき Section Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .init PROGBITS 80000000 001000 00006c 00 AX 0 0 1 [ 2] .text PROGBITS 80000100 001100 002d2c 00 AX 0 0 256 [ 3] .rodata.align PROGBITS 80002e2c 004010 000000 00 WA 0 0 1 [ 4] .rodata PROGBITS 80002e2c 003e2c 00017c 00 A 0 0 4 [ 5] .data.align PROGBITS 80080000 004010 000000 00 WA 0 0 1 [ 6] .data PROGBITS 80080000 004000 000010 00 WA 0 0 4 [ 7] .bss.align NOBITS 80080010 000000 000000 00 WA 0 0 1 [ 8] .bss NOBITS 80080010 004010 0040c0 00 WA 0 0 16 ★4bytes alignになっている [ 9] .stack NOBITS 800840d0 0040d0 00012c 00 WA 0 0 1 ★.data.alignにALIGN(2048) と書いたとき ection Headers: [Nr] Name Type Addr Off Size ES Flg Lk Inf Al [ 0] NULL 00000000 000000 000000 00 0 0 0 [ 1] .init PROGBITS 80000000 001000 000068 00 AX 0 0 1 [ 2] .text PROGBITS 80000100 001100 002b2c 00 AX 0 0 256 [ 3] .rodata.align PROGBITS 80002c2c 004010 000000 00 WA 0 0 1 [ 4] .rodata PROGBITS 80002c2c 003c2c 00017c 00 A 0 0 4 [ 5] .data.align PROGBITS 80080000 004010 000000 00 WA 0 0 1 [ 6] .data PROGBITS 80080000 004000 000010 00 WA 0 0 4 [ 7] .bss.align NOBITS 80080010 004010 0007f0 00 WA 0 0 1 [ 8] .bss NOBITS 80080800 004800 0040c0 00 WA 0 0 16 ★2KB alignになっている [ 9] .stack NOBITS 800848c0 0048c0 00012c 00 WA 0 0 1
ALIGN(4) をALIGN(2048) など、大きめの値に変えたときの様子を載せました。変なセクション .*.alignがアドレスのアラインメントをしている様子が nmでもreadelfでもわかりやすいですよね?だめ?上記は .bssの例ですが、他のセクションでも同様です。
ブートコードはアセンブラで書く必要があります。
// freertos/FreeRTOS/Demo/RISC-V-Qemu-virt_GCC/start.S
#include "riscv-reg.h"
#if __riscv_xlen == 32
#define REGSIZE		4
#define LOAD		lw
#define STOR		sw
#elif __riscv_xlen == 64
#define REGSIZE		8
#define LOAD		ld
#define STOR		sd
#endif /* __riscv_xlen */
	.section .init
	.globl _start
	.type _start,@function
_start:
	.cfi_startproc
	.cfi_undefined ra
.option push
.option norelax
	la gp, __global_pointer$
.option pop
	la sp, _stack0_top
	# Load data section
	la a0, _data_lma
	la a1, _data
	la a2, _edata
	bgeu a1, a2, 2f
1:
	LOAD t0, (a0)
	STOR t0, (a1)
	addi a0, a0, REGSIZE
	addi a1, a1, REGSIZE
	bltu a1, a2, 1b
2:
	# Clear bss section
	la a0, _bss
	la a1, _ebss
	bgeu a0, a1, 2f
1:
	STOR zero, (a0)
	addi a0, a0, REGSIZE
	bltu a0, a1, 1b
2:
	/* argc, argv, envp is 0 */
	li a0, 0
	li a1, 0
	li a2, 0
	j main
	.cfi_endproc
実装は非常に単純です。.dataをROM領域からRAM領域にコピーし、.bssを0クリアしてmain() に飛ぶだけです。
以上の実装でビルドして(makeするだけ)、動かします。
$ qemu-system-riscv32 -nographic -machine virt -net none -chardev stdio,id=con,mux=on -serial chardev:con -mon chardev=con,mode=readline -bios none -kernel a.out Hello FreeRTOS! Blink Blink Blink ...
動きましたね。良かった良かった。 改行が余計に入っちゃってるのが気になる場合はmain.cの "Blink\r\n" を "Blink\n" にすると治ります。
 この記事にコメントする
 この記事にコメントする
目次: FreeRTOS
前回は既にあるデモアプリのビルドシステムを組み替えてRISC-V QEMU sifive_eマシン(SiFive HiFive1相当)上でFreeRTOSを動かしました。今回はRISC-V QEMU virtマシン上でFreeRTOSを動かします。
マシンの違いですが、まずUARTが違います。HiFive1はSiFive UART、virtは16550です。UARTを動かすための簡易的なドライバを書きます。
// freertos/FreeRTOS/Demo/RISC-V-Qemu-virt_GCC/ns16550.c
#include <stdint.h>
#include "ns16550.h"
/* register definitions */
#define REG_RBR		0x00 /* Receiver buffer reg. */
#define REG_THR		0x00 /* Transmitter holding reg. */
#define REG_IER		0x01 /* Interrupt enable reg. */
#define REG_IIR		0x02 /* Interrupt ID reg. */
#define REG_FCR		0x02 /* FIFO control reg. */
#define REG_LCR		0x03 /* Line control reg. */
#define REG_MCR		0x04 /* Modem control reg. */
#define REG_LSR		0x05 /* Line status reg. */
#define REG_MSR		0x06 /* Modem status reg. */
#define REG_SCR		0x07 /* Scratch reg. */
#define REG_BRDL	0x00 /* Divisor latch (LSB) */
#define REG_BRDH	0x01 /* Divisor latch (MSB) */
/* Line status */
#define LSR_DR			0x01 /* Data ready */
#define LSR_OE			0x02 /* Overrun error */
#define LSR_PE			0x04 /* Parity error */
#define LSR_FE			0x08 /* Framing error */
#define LSR_BI			0x10 /* Break interrupt */
#define LSR_THRE		0x20 /* Transmitter holding register empty */
#define LSR_TEMT		0x40 /* Transmitter empty */
#define LSR_EIRF		0x80 /* Error in RCVR FIFO */
uint8_t readb( uintptr_t addr )
{
	return *((uint8_t *) addr );
}
void writeb( uint8_t b, uintptr_t addr )
{
	*((uint8_t *) addr ) = b;
}
void ns16550_out( struct device *dev, unsigned char c )
{
	uintptr_t addr = dev->addr;
	while ( (readb( addr + REG_LSR ) & LSR_THRE) == 0 ) {
		/* busy wait */
	}
	writeb( c, addr + REG_THR );
}
このドライバは初期化も設定も何もせず、いきなり出力だけ行う手抜き実装です。QEMUでは動きますが、おそらく実機では動かないでしょう。
元のコードはmain.cにSiFive UART用のシリアルの出力コードが入っているので、これを削ります。またmain.cとmain_blinky.c, main_full.cに別れていますが、あまり複雑なデモは要りません。main_full.cの方は削って、main.cに統合します。
// freertos/FreeRTOS/Demo/RISC-V-Qemu-virt_GCC/main.c
static void prvQueueSendTask( void *pvParameters )
{
TickType_t xNextWakeTime;
const unsigned long ulValueToSend = 100UL;
BaseType_t xReturned;
	/* Remove compiler warning about unused parameter. */
	( void ) pvParameters;
	/* Initialise xNextWakeTime - this only needs to be done once. */
	xNextWakeTime = xTaskGetTickCount();
	for( ;; )
	{
		/* Place this task in the blocked state until it is time to run again. */
		vTaskDelayUntil( &xNextWakeTime, mainQUEUE_SEND_FREQUENCY_MS );
		/* Send to the queue - causing the queue receive task to unblock and
		toggle the LED.  0 is used as the block time so the sending operation
		will not block - it shouldn't need to block as the queue should always
		be empty at this point in the code. */
		xReturned = xQueueSend( xQueue, &ulValueToSend, 0U );
		configASSERT( xReturned == pdPASS );
	}
}
/*-----------------------------------------------------------*/
static void prvQueueReceiveTask( void *pvParameters )
{
unsigned long ulReceivedValue;
const unsigned long ulExpectedValue = 100UL;
const char * const pcPassMessage = "Blink\r\n";
const char * const pcFailMessage = "Unexpected value received\r\n";
	/* Remove compiler warning about unused parameter. */
	( void ) pvParameters;
	for( ;; )
	{
		/* Wait until something arrives in the queue - this task will block
		indefinitely provided INCLUDE_vTaskSuspend is set to 1 in
		FreeRTOSConfig.h. */
		xQueueReceive( xQueue, &ulReceivedValue, portMAX_DELAY );
		/*  To get here something must have been received from the queue, but
		is it the expected value?  If it is, toggle the LED. */
		if( ulReceivedValue == ulExpectedValue )
		{
			puts( pcPassMessage );
			ulReceivedValue = 0U;
		}
		else
		{
			puts( pcFailMessage );
		}
	}
}
/*-----------------------------------------------------------*/
int main( void )
{
	puts( "Hello FreeRTOS!" );
	/* Create the queue. */
	xQueue = xQueueCreate( mainQUEUE_LENGTH, sizeof( uint32_t ) );
	if( xQueue != NULL )
	{
		/* Start the two tasks as described in the comments at the top of this
		file. */
		xTaskCreate( prvQueueReceiveTask, "Rx", configMINIMAL_STACK_SIZE * 2U, NULL,
					mainQUEUE_RECEIVE_TASK_PRIORITY, NULL );
		xTaskCreate( prvQueueSendTask, "TX", configMINIMAL_STACK_SIZE * 2U, NULL,
					mainQUEUE_SEND_TASK_PRIORITY, NULL );
	}
	vTaskStartScheduler();
	return 0;
}
// freertos/FreeRTOS/Demo/RISC-V-Qemu-virt_GCC/riscv-virt.c
int puts( const char *s )
{
	struct device dev;
	size_t i;
	dev.addr = NS16550_ADDR;
	for (i = 0; i < strlen(s); i++)
	{
		ns16550_out( &dev, s[i] );
	}
	ns16550_out( &dev, '\n' );
	return 0;
}
別にPOSIX信者というわけでもないんですが、ついでにputs() もどきを実装しておきました。
続きはまた今度。
 この記事にコメントする
 この記事にコメントする
| < | 2020 | > | ||||
| << | < | 09 | > | >> | ||
| 日 | 月 | 火 | 水 | 木 | 金 | 土 | 
| - | - | 1 | 2 | 3 | 4 | 5 | 
| 6 | 7 | 8 | 9 | 10 | 11 | 12 | 
| 13 | 14 | 15 | 16 | 17 | 18 | 19 | 
| 20 | 21 | 22 | 23 | 24 | 25 | 26 | 
| 27 | 28 | 29 | 30 | - | - | - | 
 wiki
 wiki Linux JM
 Linux JM Java API
 Java API 2002年
 2002年 2003年
 2003年 2004年
 2004年 2005年
 2005年 2006年
 2006年 2007年
 2007年 2008年
 2008年 2009年
 2009年 2010年
 2010年 2011年
 2011年 2012年
 2012年 2013年
 2013年 2014年
 2014年 2015年
 2015年 2016年
 2016年 2017年
 2017年 2018年
 2018年 2019年
 2019年 2020年
 2020年 2021年
 2021年 2022年
 2022年 2023年
 2023年 2024年
 2024年 2025年
 2025年 過去日記について
 過去日記について アクセス統計
 アクセス統計 サーバ一覧
 サーバ一覧 サイトの情報
 サイトの情報合計: 
本日: