日々

link permalink

リアル脱出ゲーム

友人とリアル脱出ゲーム(主催社 SCRAP のサイト)に行きました。参加したのは「DEATH NOTE×リアル脱出ゲーム 新世界の神からの脱出」です。友人にチケットを取ってもらい、一人 3,100円でした。

「脱出ゲーム」の名から、部屋をうろうろしてヒントを探し回るゲームかな?と思っていましたが、部屋を探し回ることはほぼなく、机でクイズを解き続けるタイプのゲームでした。

制限時間は 1時間で残念ながらクリアはならず。最後に答えを教えてくれますが、解けるのかこんなの?って難易度でした。レイトン教授シリーズが得意な人は、向いているかも知れません。

登録商標

調べていて、へえーと思ったのが「リアル脱出ゲーム」が SCRAP の登録商標になっていることでした。この単語はおいそれと使えないようです。

このゲームを説明できる単語は無いような気がします。もし NHK が取り上げるとしたら、このゲームを何と言って紹介するのだろうか??

[編集者: すずき]
[更新: 2014年 8月 3日 17:25]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

自作 ARMv5 エミュレータ(途中)

せっかく組み込み屋さんやってるんだから、何か一つ組み込みっぽいことでもしようと思い立ち、ARM のエミュレータを書き始めて、はや 2ヶ月が経ちました。

Linux のブートの途中まで動いたみたい
Connected to the target VM, address: '127.0.0.1:52615', transport: 'socket'
Exception: Reset by 'Init.'.
I&D-cache: all invalidated.
I&D-TLB  : all invalidated.
TTBR0    : 0x80004000.
  base   : 0x20001.
SCTLR    : 0x3137.
  V      : true.
  R      : false.
  S      : true.
  A      : true.
  M      : true.
D-TLB    : all invalidated.
I-TLB    : all invalidated.
VICITCR: 0x00000000
VICVECTCNTL[0]: 0x00000020
VICVECTCNTL[1]: 0x00000021
VICVECTCNTL[2]: 0x00000022
VICVECTCNTL[3]: 0x00000023
VICVECTCNTL[4]: 0x00000024
VICVECTCNTL[5]: 0x00000025
VICVECTCNTL[6]: 0x00000026
VICVECTCNTL[7]: 0x00000027
VICVECTCNTL[8]: 0x00000028
VICVECTCNTL[9]: 0x00000029
VICVECTCNTL[10]: 0x0000002a
VICVECTCNTL[11]: 0x0000002b
VICVECTCNTL[12]: 0x0000002c
VICVECTCNTL[13]: 0x0000002d
VICVECTCNTL[14]: 0x0000002e
VICVECTCNTL[15]: 0x0000002f
VICDEFVECTADDR: 0x00000020
SIC_ENCLR: 0xffffffff
SIC_PICENSET: 0xffd00000
Timer1Control: 0x00000000
Timer2Control: 0x00000000
Timer1Control: 0x00000000
Timer2Control: 0x00000000
Timer2Control: 0x00000000
Timer2Load: 0xffffffff
Timer2Value: 0xffffffff
Timer2Control: 0x000000c2
Timer1Control: 0x00000000
Timer1Control: 0x00000022
Timer1Control: 0x00000022
Timer1Control: 0x00000022
Timer1Load: 0x00002710
Timer1Control: 0x000000e2
UARTIMSC: 0x00000000
UARTICR: 0x0000ffff
UARTFBRD: 0x00000004
UARTIBRD: 0x00000027
UARTLCR_H: 0x00000070
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 3.12.20 (katsuhiro@falcon) (gcc version 4.8.1 (Sourcery CodeBench Lite 2013.11-33) ) #1 Sun Jun 1 00:39:50 JST 2014
[    0.000000] CPU: ARM926EJ-S [41069260] revision 0 (ARMv5TEJ), cr=00003137
[    0.000000] CPU: VIVT data cache, VIVT instruction cache
[    0.000000] Machine: ARM-Versatile PB
[    0.000000] Ignoring unrecognised tag 0x00000000
[    0.000000] Memory policy: ECC disabled, Data cache writeback
[    0.000000] On node 0 totalpages: 16384
[    0.000000] free_area_init_node: node 0, pgdat c03a801c, node_mem_map c03c5000
[    0.000000]   Normal zone: 128 pages used for memmap
[    0.000000]   Normal zone: 0 pages reserved
[    0.000000]   Normal zone: 16384 pages, LIFO batch:3
[    0.000000] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 178956ms
[    0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
[    0.000000] pcpu-alloc: [0] 0 
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
[    0.000000] Kernel command line: console=ttyAMA0 mem=64M lpj=0 root=/dev/nfs debug printk.time=1
[    0.000000] PID hash table entries: 256 (order: -2, 1024 bytes)
[    0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Memory: 61064K/65536K available (2732K kernel code, 153K rwdata, 708K rodata, 114K init, 111K bss, 4472K reserved)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.000000]     vmalloc : 0xc4800000 - 0xff000000   ( 936 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
[    0.000000]     modules : 0xbf000000 - 0xc0000000   (  16 MB)
[    0.000000]       .text : 0xc0008000 - 0xc03647b8   (3442 kB)
[    0.000000]       .init : 0xc0365000 - 0xc03819dc   ( 115 kB)
[    0.000000]       .data : 0xc0382000 - 0xc03a8740   ( 154 kB)
[    0.000000]        .bss : 0xc03a8740 - 0xc03c4624   ( 112 kB)
[    0.000000] NR_IRQS:224
[    0.000000] VIC @f1140000: id 0x00041190, vendor 0x41
[    0.000000] FPGA IRQ chip 0 "SIC" @ f1003000, 13 irqs
[    0.000000] Console: colour dummy device 80x30
[    1.562791] Calibrating delay loop... 6.52 BogoMIPS (lpj=32640)
[    2.099243] pid_max: default: 32768 minimum: 301
[    2.130496] Mount-cache hash table entries: 512
[    2.273627] CPU: Testing write buffer coherency: ok
[    2.315394] Setting up static identity map for 0xc0299720 - 0xc0299778
[    2.672739] VFP support v0.3: no double precision support
[    2.734862] NET: Registered protocol family 16
[    2.873316] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    3.345429] Serial: AMBA PL011 UART driver
[    3.362809] dev:f1: ttyAMA0 at MMIO 0x101f1000 (irq = 44, base_baud = 0) is a PL011 rev1
[    3.628990] console [ttyAMA0] enabled
UARTIMSC: 0x00000000
UARTICR: 0x0000ffff
[    3.681619] dev:f2: ttyAMA1 at MMIO 0x101f2000 (irq = 45, base_baud = 0) is a PL011 rev1
UARTIMSC: 0x00000000
UARTICR: 0x0000ffff
[    3.735775] dev:f3: ttyAMA2 at MMIO 0x101f3000 (irq = 46, base_baud = 0) is a PL011 rev1
UARTIMSC: 0x00000000
UARTICR: 0x0000ffff
[    3.796222] fpga:09: ttyAMA3 at MMIO 0x10009000 (irq = 70, base_baud = 0) is a PL011 rev1
[    4.796654] bio: create slab <bio-0> at 0
[    5.084143] Switched to clocksource timer3
[    6.655203] NET: Registered protocol family 2
[    6.825171] TCP established hash table entries: 512 (order: 0, 4096 bytes)
[    6.840762] TCP bind hash table entries: 512 (order: -1, 2048 bytes)
[    6.853819] TCP: Hash tables configured (established 512 bind 512)
[    6.871232] TCP: reno registered
[    6.877328] UDP hash table entries: 256 (order: 0, 4096 bytes)
[    6.891042] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[    6.958240] NET: Registered protocol family 1
[    7.029488] RPC: Registered named UNIX socket transport module.
[    7.035967] RPC: Registered udp transport module.
[    7.041442] RPC: Registered tcp transport module.
[    7.047158] RPC: Registered tcp NFSv4.1 backchannel transport module.
java.lang.IllegalArgumentException: Sorry, not implemented.
pc:c016ed88
Disconnected from the target VM, address: '127.0.0.1:52615', transport: 'socket'
Exception in thread "main" java.lang.IllegalArgumentException: Sorry, not implemented.
	at net.katsuster.semu.ARMv5.executeLdrbt(ARMv5.java:2625)
	at net.katsuster.semu.ARMv5.executeSubLdrStr(ARMv5.java:4227)
	at net.katsuster.semu.ARMv5.executeInst(ARMv5.java:3833)
	at net.katsuster.semu.ARMv5.execute(ARMv5.java:3814)
	at net.katsuster.semu.ARMv5.step(ARMv5.java:4961)
	at net.katsuster.semu.CPU.run(CPU.java:158)
	at net.katsuster.semu.Main.main(Main.java:222)

Process finished with exit code 1

空き時間でチマチマ実装して、ようやく Linux ブートの途中でクラッシュする、微妙な何かが動くところまで辿り着きました。

この先に進むには ldrt 命令が要るようなので、いよいよサボっていた MMU を実装するときが来たようです。しかしまあ CPU も MMU も周辺コアもスタブだらけでほぼ実装していないのに、よくここまで動きますね。Linux ってすごいのか適当なのか…。

方針

きっと古い CPU の方が単純だろうという単純な考えで、CPU は ARM9(アーキテクチャで言うと ARMv5)、ボードは ARM Versatile-AB/PB という開発ボードをエミュレーションのターゲットにしました。ボードの実物見たこと無いですが、実物が要る機会なんてそうそう無いでしょう…。

なんと CPU、周辺機器、ボードの仕様書、マニュアルは、ARM のサイトからタダでダウンロードできてしまいます。アカウントの登録は要りますけど、タダなのが素晴らしいです。

どこから作るか

よっしゃ、俺も作ったるわ!という変な人はまず居ないと思いますが、もし作るなら CPU の作り込みは程々にして、周辺機器、特にタイマー、UART 辺りと繋がる方法を先に考えることをオススメします。

Linux のブートメッセージを拝むには CPU だけではダメで、UART を作らないとメッセージが出力できませんし、タイマー割り込みが入らないと BogoMIPS の測定が終わらず、ブートメッセージが出る前にカーネルがハング(※)してしまうからです。

なぜブートメッセージにこだわるかというと、趣味のやる気を維持するには「進んでる、楽しい!」という感覚を繰り返すことが大事でして、エミュレータなら Linux のブートメッセージがどこまで出たか?という指標が、作業の手応えとして結構良いからです。

動くのか動かないのかさっぱりわからないまま、延々と実装する方が楽しいという方は、どこから作り始めても問題ないです。が、大抵の方にとってそれは「苦行」以外の何者でもないですよね。

(※)コマンドラインに lpj=1000 とか 0以外の数字を与えて BogoMIPS の測定をスキップする、という手もあります。

[編集者: すずき]
[更新: 2014年 8月 3日 18:54]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

CodeSourcery に代わって Linaro を使う

組み込み系 CPU 向けクロスコンパイラの定番といえば CodeSourcery ですが、ダウンロードのページに行くためにはユーザー登録が必要で、面倒くさいよー、という方も居ると思います。

ARM 向けに限りますが、別の選択肢として Linaro が公開しているクロスコンパイラという手があります。CodeSourcery 同様にお手軽に使える Prebuild 版も用意してくれていますので、使い方には困らないと思います。

Linaro のクロスコンパイラで ARM 用カーネルビルド
# 取得する
wget https://www.kernel.org/pub/linux/kernel/v3.x/linux-3.14.15.tar.xz
wget http://releases.linaro.org/14.07/components/toolchain/binaries/gcc-linaro-arm-linux-gnueabihf-4.9-2014.07_linux.tar.xz

# 展開する
tar xJvf linux-3.14.15.tar.xz
tar xJvf gcc-linaro-arm-linux-gnueabihf-4.9-2014.07_linux.tar.xz

# ビルドする
export ARCH=arm
export CROSS_COMPILE=/home/katsuhiro/share/arm_cross/gcc-linaro-arm-linux-gnueabihf-4.9-2014.07_linux/bin/arm-linux-gnueabihf-

cd linux-3.14.15
make KBUILD_DEFCONFIG=versatile_defconfig defconfig
make -j4

ビルド成功したようなので、自作 ARMv5 エミュレータに放り込んでみました。

Linux 3.14 on 自作エミュレータ
Connected to the target VM, address: '127.0.0.1:49748', transport: 'socket'
Exception: Reset by 'Init.'.
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 3.14.15 (katsuhiro@falcon) (gcc version 4.9.1 20140710 (prerelease) (crosstool-NG linaro-1.13.1-4.9-2014.07 - Linaro GCC 4.9-2014.07) ) #1 Fri Aug 8 15:38:54 JST 2014
[    0.000000] CPU: ARM926EJ-S [41069260] revision 0 (ARMv5TEJ), cr=00003137
[    0.000000] CPU: VIVT data cache, VIVT instruction cache
[    0.000000] Machine: ARM-Versatile PB
[    0.000000] Ignoring unrecognised tag 0x00000000
[    0.000000] Memory policy: Data cache writeback
[    0.000000] On node 0 totalpages: 16384
[    0.000000] free_area_init_node: node 0, pgdat c03c4ce8, node_mem_map c3f7a000
[    0.000000]   Normal zone: 128 pages used for memmap
[    0.000000]   Normal zone: 0 pages reserved
[    0.000000]   Normal zone: 16384 pages, LIFO batch:3
[    0.003317] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 178956969942ns
[    0.029105] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
[    0.031450] pcpu-alloc: [0] 0 
[    0.042642] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
[    0.045733] Kernel command line: console=ttyAMA0 mem=64M lpj=0 root=/dev/nfs debug printk.time=1
[    0.093627] PID hash table entries: 256 (order: -2, 1024 bytes)
[    0.109772] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.173519] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.734098] Memory: 60952K/65536K available (2817K kernel code, 157K rwdata, 732K rodata, 115K init, 116K bss, 4584K reserved)
[    0.754145] Virtual kernel memory layout:
[    0.754145]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.754145]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.754145]     vmalloc : 0xc4800000 - 0xff000000   ( 936 MB)
[    0.754145]     lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
[    0.754145]     modules : 0xbf000000 - 0xc0000000   (  16 MB)
[    0.754145]       .text : 0xc0008000 - 0xc037f900   (3551 kB)
[    0.754145]       .init : 0xc0380000 - 0xc039ccd4   ( 116 kB)
[    0.754145]       .data : 0xc039e000 - 0xc03c5420   ( 158 kB)
[    0.754145]        .bss : 0xc03c5420 - 0xc03e2774   ( 117 kB)
[    0.835624] NR_IRQS:224
[    1.433660] VIC @f1140000: id 0x00041190, vendor 0x41
[    1.480147] FPGA IRQ chip 0 "SIC" @ f1003000, 13 irqs, parent IRQ: 63
[    1.600891] Console: colour dummy device 80x30
[    1.608749] Calibrating delay loop... 6.52 BogoMIPS (lpj=32640)
[    2.220671] pid_max: default: 32768 minimum: 301
[    2.257974] Mount-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    2.263175] Mountpoint-cache hash table entries: 1024 (order: 0, 4096 bytes)
[    2.424212] CPU: Testing write buffer coherency: ok
[    2.471352] Setting up static identity map for 0x802ae5b8 - 0x802ae610
[    3.001781] VFP support v0.3: no double precision support
[    3.085927] NET: Registered protocol family 16
[    3.237579] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    3.885257] Serial: AMBA PL011 UART driver
[    3.909160] dev:f1: ttyAMA0 at MMIO 0x101f1000 (irq = 44, base_baud = 0) is a PL011 rev1
[    4.214325] console [ttyAMA0] enabled
UARTIMSC: 0x00000000
UARTICR: 0x0000ffff
[    4.292449] dev:f2: ttyAMA1 at MMIO 0x101f2000 (irq = 45, base_baud = 0) is a PL011 rev1
UARTIMSC: 0x00000000
UARTICR: 0x0000ffff
[    4.371940] dev:f3: ttyAMA2 at MMIO 0x101f3000 (irq = 46, base_baud = 0) is a PL011 rev1
UARTIMSC: 0x00000000
UARTICR: 0x0000ffff
[    4.454404] fpga:09: ttyAMA3 at MMIO 0x10009000 (irq = 70, base_baud = 0) is a PL011 rev1
[    5.788310] bio: create slab <bio-0> at 0
SYS_LED: 0x000000ff
SYS_LED: read 0x00000000
SYS_LED: read 0x00000000
SYS_LED: read 0x00000000
SYS_LED: read 0x00000000
SYS_LED: read 0x00000000
SYS_LED: read 0x00000000
SYS_LED: read 0x00000000
SYS_LED: read 0x00000000
[    6.329351] Switched to clocksource timer3
[    8.419343] NET: Registered protocol family 2
[    8.592061] TCP established hash table entries: 1024 (order: 0, 4096 bytes)
[    8.613714] TCP bind hash table entries: 1024 (order: 0, 4096 bytes)
[    8.632315] TCP: Hash tables configured (established 1024 bind 1024)
[    8.652642] TCP: reno registered
[    8.659583] UDP hash table entries: 256 (order: 0, 4096 bytes)
[    8.675257] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[    8.750198] NET: Registered protocol family 1
[    8.820467] RPC: Registered named UNIX socket transport module.
[    8.827386] RPC: Registered udp transport module.
[    8.833482] RPC: Registered tcp transport module.
[    8.839809] RPC: Registered tcp NFSv4.1 backchannel transport module.
[    8.932090] NetWinder Floating Point Emulator V0.97 (double precision)
[    9.113116] futex hash table entries: 256 (order: -1, 3072 bytes)
Exception: Data abort by 'MMU trans sec, paL1:0x80004000, entryL1:0x00000000, va:0x00000000, dom:0, inst:dat, priv:user, read:rd.'.
[    9.275864] Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
[    9.309731] jffs2: version 2.2. (NAND) Ac 2001-2006 Red Hat, Inc.
[    9.368658] ROMFS MTD (C) 2007 Red Hat, Inc.
[    9.378358] msgmni has been set to 119
[    9.461972] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
[    9.469946] io scheduler noop registered
[    9.475694] io scheduler deadline registered
[    9.485652] io scheduler cfq registered (default)
Exception in thread "main" java.lang.IllegalArgumentException: Illegal address 0x00000410.
	at net.katsuster.semu.Controller64Reg32.isValidReg(Controller64Reg32.java:57)
	at net.katsuster.semu.GPIO.tryAccess(GPIO.java:79)
	at net.katsuster.semu.GPIO.tryWrite(GPIO.java:69)
	at net.katsuster.semu.Bus64.tryWrite(Bus64.java:168)
	at net.katsuster.semu.MasterCore64.tryWrite(MasterCore64.java:96)
	at net.katsuster.semu.ARMv5.executeStrb(ARMv5.java:3303)
	at net.katsuster.semu.ARMv5.executeSubLdrStr(ARMv5.java:4492)
	at net.katsuster.semu.ARMv5.executeInst(ARMv5.java:4074)
	at net.katsuster.semu.ARMv5.execute(ARMv5.java:4055)
	at net.katsuster.semu.ARMv5.step(ARMv5.java:5201)
	at net.katsuster.semu.CPU.run(CPU.java:158)
	at net.katsuster.semu.Main.main(Main.java:252)
java.lang.IllegalArgumentException: Illegal address 0x00000410.
pc:c0179db4
Disconnected from the target VM, address: '127.0.0.1:49748', transport: 'socket'

Process finished with exit code 1

GPIO デバイスにアクセスに行くらしく途中で怒られました。GPIO なんて何に使っているんでしょう?他にもボードの LED を光らせるみたいですが、何したいんだろう…これ。

[編集者: すずき]
[更新: 2014年 8月 8日 16:02]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

IntelliJ IDEA でコピーができない

IntelliJ IDEA の Console ウインドウのコピー処理でハマりました。

Null 文字を print すると(例えば System.out.printf("%c", (char)0); など)、Ctrl+A, Ctrl+C とキーを押して Console の出力結果を全コピーしようとしても、Null 文字以降がコピーされません。何これ…困るわ。

バグ?仕様??

メモ: 技術系?の話は Facebook から転記しておくことにした。

[編集者: すずき]
[更新: 2014年 8月 14日 10:23]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

動かぬ自作エミュレータ

自作 ARM エミュレータ、Linux 起動して initramfs 上の /init を execve するところで必ず失敗するので調べてたら、
do_execve_common() → load_elf_binary() → padzero() → clear_user() → access_ok() → __range_ok()
ときて失敗し、結果的に EFAULT が返っていました。

range_ok は常に失敗するわけでもないのが不思議で、さらに調べたら sbc, rsc 命令のキャリーフラグ(C フラグ)のエミュレーションが間違っていて、本来は成功なのに失敗を返す場合があることがわかりました。

ARM の仕様
a - b - c でボローが発生したらキャリーフラグを 0
ミスった実装
a - b と (a + b) - c 双方でボローが発生したらキャリーフラグを 0
修正した実装
a - b か (a - b) - c のどちらかでボローが発生したらキャリーフラグを 0

いきさつ

  • ボロー判定の関数は 2 項しか取れないから 3 項は渡せないけど、2 回に分けて処理すれば 3 項でも判定できる!
    → a - b または b - c ではなく、a - b 「かつ」 b - c と実装する過ちが発生
  • 引き算は足し算とほぼ処理が同じ!
    → a - b ではなく、a + b と実装する過ちが発生

うーん、パッと見ではわからん…。けど、これで 2 日間も悩んでいた俺って一体…。

メモ: 技術系?の話は Facebook から転記しておくことにした。

[編集者: すずき]
[更新: 2014年 8月 14日 10:29]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

ARM ldm 命令の怪

ARM の ldm 命令には変わった機能が付いています。レジスタリストの後ろに付ける ^ なのですが、実は ^ には意味が 2通りあります。そのためアセンブラで記述するときすこぶるわかりづらくなっています。

具体例を挙げると、下記の 2つの ldm 命令は、同じようなレジスタリストを指定していて、同じような ^ が付いていますが、命令の意味は全く違います。

2つのハット

ldmdb sp, {r0, r1, r2, pc}^
ldmdb sp, {r0, r1, r2, lr}^

1つ目の ldm 命令は、sp - 16 の指すアドレスから r0, r1, r2, pc にデータをロードして、cpsr レジスタに現在の動作モードの spsr レジスタをコピーせよ、という意味になります。

2つ目 ldm 命令は、sp - 16 の指すアドレスから「ユーザモードの」r0, r1, r2, lr にデータをロードせよ、という意味になります。

何?意味がわからない?恐らく誰でもそうでしょう。私も最初に見たとき意味がわからなくて、目が点になりました。

仕様です

なぜこんなことになるかというと、ARM の ldm 命令の ^ の意味が、レジスタリストに依存して変わるからです。具体的に言えば、

レジスタリストに pc レジスタが入っていたら、
「pc をロードする ldm 命令で、カレントモードの spsr を cpsr にコピーすることを示す」

レジスタリストに pc レジスタが入っていなかったら、
「pc をロードしない ldm 命令で、ユーザモードレジスタをロードすることを示す」

のように ARM の仕様で定義されているからです。

一応の擁護

なんだその仕様は!と思われるでしょうが、この機能は、一般的なプログラムでは全く使われません。使われるのは、割り込みハンドラからの復帰、もしくは特権モードが絡む部分くらいで、いずれも OS の内部です。

そのため ARM の初学者が使う可能性はほぼありません。いわゆる「わかってる」人しか使わない通の機能です。

少数のわかっている人しか使わないので、多少可読性が低くてもあまり問題が出ないのでしょう。たぶん。

感想

と、擁護した直後に言うのは憚られますが、正直なところそこまで ^ を酷使せず、せめてどちらかを ^ じゃない別の記号にすれば良かったのに…と思わんでもないです。いきなり変えたら大混乱が起きるので、今さらどうしようもありませんけど…。

仕様を切るとき、特に将来も下位互換性が求められそうな仕様、オープンな仕様では、記号の一文字取っても、細心の注意が必要だよなーと、強く感じた一件でした。

[編集者: すずき]
[更新: 2014年 8月 13日 02:29]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

Busybox まで動いた

自作 ARM エミュレータで Linux 3.12.26 をブートし、Busybox の ash のプロンプト表示まで到達しました。

現時点での動作イメージです。実際は最初の方にエミュレータのデバッグメッセージが大量に出ますが、意味ないので叩き切ってます。

Busybox on Linux 3.12.26 on 自作 ARMv5 エミュレータ
Connected to the target VM, address: '127.0.0.1:49281', transport: 'socket'

Exception: Reset by 'Init.'.
[    0.000000] Booting Linux on physical CPU 0x0
[    0.000000] Linux version 3.12.26+ (katsuhiro@falcon) (gcc version 4.9.1 20140710 (prerelease) (crosstool-NG linaro-1.13.1-4.9-2014.07 - Linaro GCC 4.9-2014.07) ) #1 Thu Aug 14 02:42:16 JST 2014
[    0.000000] CPU: ARM926EJ-S [41069260] revision 0 (ARMv5TEJ), cr=00003137
[    0.000000] CPU: VIVT data cache, VIVT instruction cache
[    0.000000] Machine: ARM-Versatile PB
[    0.000000] Ignoring unrecognised tag 0x00000000
[    0.000000] Memory policy: ECC disabled, Data cache writeback
[    0.000000] On node 0 totalpages: 16384
[    0.000000] free_area_init_node: node 0, pgdat c03ac754, node_mem_map c03c9000
[    0.000000]   Normal zone: 128 pages used for memmap
[    0.000000]   Normal zone: 0 pages reserved
[    0.000000]   Normal zone: 16384 pages, LIFO batch:3
[    0.000000] sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 178956ms
[    0.000000] pcpu-alloc: s0 r0 d32768 u32768 alloc=1*32768
[    0.000000] pcpu-alloc: [0] 0 
[    0.000000] Built 1 zonelists in Zone order, mobility grouping on.  Total pages: 16256
[    0.000000] Kernel command line: console=ttyAMA0 mem=64M lpj=0 root=/dev/ram init=/bin/sh debug printk.time=1
[    0.000000] PID hash table entries: 256 (order: -2, 1024 bytes)
[    0.000000] Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
[    0.000000] Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
[    0.000000] Memory: 59960K/65536K available (2742K kernel code, 155K rwdata, 712K rodata, 114K init, 111K bss, 5576K reserved)
[    0.000000] Virtual kernel memory layout:
[    0.000000]     vector  : 0xffff0000 - 0xffff1000   (   4 kB)
[    0.000000]     fixmap  : 0xfff00000 - 0xfffe0000   ( 896 kB)
[    0.000000]     vmalloc : 0xc4800000 - 0xff000000   ( 936 MB)
[    0.000000]     lowmem  : 0xc0000000 - 0xc4000000   (  64 MB)
[    0.000000]     modules : 0xbf000000 - 0xc0000000   (  16 MB)
[    0.000000]       .text : 0xc0008000 - 0xc0367c14   (3456 kB)
[    0.000000]       .init : 0xc0368000 - 0xc03849fc   ( 115 kB)
[    0.000000]       .data : 0xc0386000 - 0xc03ace80   ( 156 kB)
[    0.000000]        .bss : 0xc03ace80 - 0xc03c8d64   ( 112 kB)
[    0.000000] NR_IRQS:224
[    0.000000] VIC @f1140000: id 0x00041190, vendor 0x41
[    0.000000] FPGA IRQ chip 0 "SIC" @ f1003000, 13 irqs
[    0.000000] Console: colour dummy device 80x30
[    1.823423] Calibrating delay loop... 0.51 BogoMIPS (lpj=2559)
[    2.008160] pid_max: default: 32768 minimum: 301
[    2.051389] Mount-cache hash table entries: 512
[    2.282632] CPU: Testing write buffer coherency: ok
[    2.336914] Setting up static identity map for 0xc029c520 - 0xc029c578
[    3.015733] VFP support v0.3: no double precision support
[    3.115064] NET: Registered protocol family 16
[    3.402544] DMA: preallocated 256 KiB pool for atomic coherent allocations
[    4.241363] Serial: AMBA PL011 UART driver
[    4.264723] dev:f1: ttyAMA0 at MMIO 0x101f1000 (irq = 44, base_baud = 0) is a PL011 rev1
[    4.657293] console [ttyAMA0] enabled
[    4.748693] dev:f2: ttyAMA1 at MMIO 0x101f2000 (irq = 45, base_baud = 0) is a PL011 rev1
[    4.827661] dev:f3: ttyAMA2 at MMIO 0x101f3000 (irq = 46, base_baud = 0) is a PL011 rev1
[    4.958784] fpga:09: ttyAMA3 at MMIO 0x10009000 (irq = 70, base_baud = 0) is a PL011 rev1
[    6.984675] bio: create slab <bio-0> at 0
[    7.563484] Switched to clocksource timer3
[   10.489897] NET: Registered protocol family 2
[   10.731930] TCP established hash table entries: 512 (order: 0, 4096 bytes)
[   10.761376] TCP bind hash table entries: 512 (order: -1, 2048 bytes)
[   10.781356] TCP: Hash tables configured (established 512 bind 512)
[   10.810155] TCP: reno registered
[   10.817472] UDP hash table entries: 256 (order: 0, 4096 bytes)
[   10.833676] UDP-Lite hash table entries: 256 (order: 0, 4096 bytes)
[   10.936594] NET: Registered protocol family 1
[   11.031626] RPC: Registered named UNIX socket transport module.
[   11.039086] RPC: Registered udp transport module.
[   11.045485] RPC: Registered tcp transport module.
[   11.050589] RPC: Registered tcp NFSv4.1 backchannel transport module.
[   11.116524] Trying to unpack rootfs image as initramfs...
[  107.483588] Freeing initrd memory: 1084K (c0800000 - c090f000)
[  107.546930] NetWinder Floating Point Emulator V0.97 (double precision)
[  107.961293] Installing knfsd (copyright (C) 1996 okir@monad.swb.de).
[  108.022282] jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
[  108.128699] ROMFS MTD (C) 2007 Red Hat, Inc.
[  108.143263] msgmni has been set to 119
[  108.269578] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 254)
[  108.280765] io scheduler noop registered
[  108.289606] io scheduler deadline registered
[  108.308715] io scheduler cfq registered (default)
[  108.386028] clcd-pl11x dev:20: PL110 rev0 at 0x10120000
SYS_CLCD: read 0x00001f00
LCDControl: 0x00000000
[  109.004790] clcd-pl11x dev:20: Versatile hardware, VGA display
SYS_CLCD: read 0x00001f00
SYS_CLCD: 0x00001f00
LCDIMSC: read 0x00000000
LCDTiming0: 0x27175f9c
LCDTiming1: 0x200b05df
LCDTiming2: 0x067f3800
LCDTiming3: 0x00000000
LCDUPBASE: 0x83000000
LCDLPBASE: 0x8304b000
SYS_OSC4: read 0x00000000
SYS_LOCK: 0x0000a05f
SYS_OSC4: 0x0001c863
SYS_LOCK: 0x00000000
LCDIMSC: 0x00001029
LCDIMSC: 0x00001829
SYS_CLCD: read 0x00001f00
SYS_CLCD: 0x00001f03
SYS_CLCD: 0x00001f17
[  113.628628] Console: switching to colour frame buffer device 80x60
[  122.764467] brd: module loaded
[  122.953158] physmap platform flash device: 04000000 at 34000000
[  123.244156] physmap-flash physmap-flash.0: map_probe failed
[  123.531512] smc91x: not found (-19).
[  123.686616] mousedev: PS/2 mouse device common for all mice
[  124.249155] TCP: cubic registered
[  124.257574] NET: Registered protocol family 17
UARTIFLS: 0x00000012
UARTFBRD: 0x00000000
UARTIBRD: 0x00000001
UARTLCR_H: 0x00000000
UARTFBRD: 0x00000004
UARTIBRD: 0x00000027
UARTLCR_H: 0x00000070
[  124.810528] Freeing unused kernel memory: 112K (c0368000 - c0384000)
----- ls -la
total 4
drwxr-xr-x   11 1000     1003             0 Aug 14  2014 .
drwxr-xr-x   11 1000     1003             0 Aug 14  2014 ..
drwxr-xr-x    2 1000     1003             0 Aug 13  2014 bin
drwxr-xr-x    2 1000     1003             0 Aug 13  2014 dev
drwxr-xr-x    2 1000     1003             0 Aug  8  2014 etc
-rwxr-xr-x    1 1000     1003           129 Aug 14  2014 init
drwxr-xr-x    2 1000     1003             0 Aug  8  2014 lib
drwxr-xr-x    2 1000     1003             0 Aug  8  2014 proc
drwx------    2 0        0                0 Aug 13  2014 root
drwxr-xr-x    2 1000     1003             0 Aug  8  2014 run
drwxr-xr-x    2 1000     1003             0 Aug  8  2014 sbin
drwxr-xr-x    2 1000     1003             0 Aug  8  2014 sys
/bin/sh: can't access tty; job control turned off
UARTFBRD: 0x00000004
UARTIBRD: 0x00000027
UARTLCR_H: 0x00000070
/ # 

Disconnected from the target VM, address: '127.0.0.1:49281', transport: 'socket'

Process finished with exit code -1


(メモ: コマンドラインから実行)
$ java -cp out/production/semu net.katsuster.semu.Main ~/share/arm_cross/linux-3.12.26/arch/arm/boot/Image ~/share/arm_cross/work/initramfs.gz

エミュレータの出しているデバッグメッセージがなかったら、普通の起動ログとあまり変わりませんね。って、そりゃ当たり前か。

開発環境、開発期間

珍しいものは使っていません。ぶっちゃけ PC 本体さえあれば、他は全部タダで行けます。

  • 開発環境: IntelliJ IDEA
  • エミュレータの実装言語: Java 7 SE
  • クロスコンパイラ: Linaro の成果物と、CodeSourcery G++
  • クロスコンパイル環境: Debian GNU/Linux
  • ARM や Versatile ボードの仕様書: ARM 社のサイト、PDF も GET できます

エミュレータのコードはこのサイトに置いています(リンク)。マニュアルなどはないので、使い方が意味不明だと思いますし、見ても面白くないと思いますが…。

最初のコミットが 6/4 なので、開発期間は約 2か月半です。日曜大工というか日曜プログラミングなので、割と長期間の取り組みになっています。とはいえ、フルタイムでやったとしても、実装方式などを悩む時間は変わらないので、開発期間はそんなに変わらないように思います。

ハマった点

前に書いたもの以外のハマりポイントをご紹介。

Linux カーネルのコンフィギュレーションが間違っていた
ARM はシステムコール呼び出し規約が 2つあります。ARM OABI(swi の 24ビット即値にシステムコール番号を埋め込む)と、ARM EABI(r7 にシステムコール番号、swi 0x00000000 で実行)です。
最近のコンパイラはみな EABI を使いますが、カーネルコンフィグで EABI を(コンフィグ名 CONFIG_AEABI)無効にして、EABI のお作法でシステムコールを呼ぶと、全て「0 番なんていうシステムコール知らん」=bad systemcall 扱いになります。
エミュレーション対象にした Versatile AB/PB の defconfig は作られた時代が古いせいか、CONFIG_AEABI がデフォルト無効になっていてハマりました。
Thumb 命令のエミュレーションをサボった
自作エミュレータが Thumb モードビット(CPSR の T ビット)を全く見ていなかったので、Thumb 命令を ARM 命令だと思って実行して、クラッシュしていました。
コンパイラの選定ミス
Busybox は glibc と static link しますから、Busybox が動作するか?=glibc に Thumb 命令が入っているかどうか?ですが、完全に頭から抜けていました。
調べてみると Linaro の glibc は Thumb 命令を含んでいて、CodeSourcery の glibc は Thumb 命令を含んでいないようだったので、コンパイラを CodeSourcery に切り替えてひとまず Thumb 命令未実装の問題を回避しました。
UART の出力側(TX)実装が悪かった
UART の実装をサボって 0 を返しまくったせいで、TX FIFO 残量まで 0 という意味になっていたらしく、ARM UART ドライバが TX FIFO の空き待ちでハングしていました。
カーネル起動時の printk は FIFO 残量なんか見てなかったくせに…、Linux の ARM UART ドライバって良くできてますね。

改善点

改良の余地はいくらでもあります。

  • クソ遅い、起動までに 3分(QEMU は 1秒くらい)
  • 文字入力が未実装、インタラクティブな使い方が出来ない
  • コンパイラを選ぶ
  • ARMv5TEJ と言いつつ、TEJ つまり Thumb 命令、エンハンスド DSP 命令、Jazelle 拡張は未実装で実質、素の ARMv5
  • キャッシュ、TLB 周りはガン無視
  • FPU 命令も未実装
  • ネットワーク、ストレージなど、周辺 I/O は未実装

しばらくは楽しいオモチャになりそうです。

謎な点

Linux 3.12 は起動するのに、Linux 3.14 だとなぜか途中でハングします、なんでだろ?未だに良くわかりません。

[編集者: すずき]
[更新: 2014年 8月 15日 00:57]
link 編集する

コメント一覧

  • よしだあ 
    おもしろいなあ。
    私は最近オフでアウトプットできてないなあと反省。(;  ̄▽ ̄)
    つぎは、コンパイラですか!?笑 
    (2014年08月14日 20:23:13)
  • すずき 
    >よしだあさん
    会社入ってから、日曜プログラミングはアウトプットまで辿り着けないことが多くて、モヤモヤしてましたので、久々に何となく形になったのは嬉しいです。

    残念ながらコンパイラを作る予定はないですなー。

    C のコンパイラ、大学の課題で作ったのが懐かしい…。 
    (2014年08月15日 00:42:01)
open/close この記事にコメントする



link permalink

C はいくらでもメチャクチャに書ける言語

switch 文を使ってはいけないを読んで。

PHP はさておいて。私も switch より State パターンを選びますが、C 言語の関数ポインタで State パターンを実現するのは、今も迷います。言語仕様上、悪い方に倒れるのを阻止できないためです。

ハッカーが明確で読みやすいコードを書いてくれるうちは良いですが、頭のおかしい人が do という関数ポインタに全関数を入れるクソコードを書き始めたらもう全部パアです。

いやまさかそんなこと、と思うかもしれませんが、どこの会社とは言いませんがそんなクソコードが実在してるんですよ、世の中って怖いですよね…。

ワルいコード

この記事(コードのネストを深くするな)を読んでいたら、会社のクソコード山脈を思い出しました。

7段 if なんて序の口。世の中の悪手とされる書き方は、大概やってるワルい奴です。バグも多い…。

ファイルシステムのベンチマーク

Qiita - EXT4 vs XFS vs Btrfs vs ZFS を fio でベンチマークを取ってみました。を読んで。

参考になった。ZFS は FUSE 経由じゃない Native 実装があるのか…知らなんだ。

XFS は 1MB over のデカいファイルは速いけど、1KB くらいの細かいファイルの create/delete をぶちかます(カーネルの tarball を展開しながら、古いカーネルソースを rm -r するとか)と、すっごい遅くて嫌になって使うの辞めた記憶があるのだけど…改善されたのだろうか?

メモ: 技術系の話は Facebook から転記しておくことにした。

[編集者: すずき]
[更新: 2015年 11月 29日 06:18]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

コードの読みやすさとは

基本的には、コードを読むときに、覚えておかなければならないことを減らし、覚える時間を短く済ませた方がわかりやすい、と感じます。

コードを横長にするくらいなら、縦長にする。
一度に覚えることが減るから。
コードの横も縦も短くできれば、なお良い。
メソッドを読むときに覚え続ける時間が減るから。
引数は少ない方が良い。
メソッドの目的は 1つが良い。
コードを読むときに覚える項目が減るから。
インデントは浅い方が良い。
ブロックを読むときに覚える条件の数が減るから。
意味のわからない変数名は無い方が良い。
マジックナンバーは無い方が良い。
名前と名前の意味を対応させる必要がなくなるから。
グローバル変数は無い方が良い。
ソースコード全域で覚えなければならない項目が減るから。
副作用は無い方が良い。
覚える必要すらなくなるから。

覚えきれない量の条件や変数が出てくるコード、長時間覚えておかなければ理解できないコードは、どこかが病気だと思って、直すようにしています。

[編集者: すずき]
[更新: 2014年 8月 16日 16:23]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

私の常識はあなたの非常識

【レビュー】超小型PC「Raspberry Pi」で夏休み自由課題・第1回 - Raspberry Piとは? 入手とセットアップ (1) Raspberry Piでコンピューターを学ぼう を読んで。

"Raspberry Pi は少々とっつきにくい。買ってくると基板が入っているだけで、電源をつないでも動かないのだ。"(引用)

え!そうなの?

SD カードに tarball 一個解凍するだけで使えるようになるので、一番とっつきやすい部類だと思ってました。

いつの間にか一般的な理解と乖離していたみたいです。うーん、認識を改めなければいかんなー…。

メモ: 技術系?の話は Facebook から転記(※)しておくことにした。

(※)本来 8月13日のエントリです。8月14日辺りでエミュレータが動いたのが嬉しくて、浮かれて Facebook に書きまくったら、このサイトに転記しきれなくなったため、未来のエントリに移動させています。

[編集者: すずき]
[更新: 2014年 8月 16日 16:38]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

クソコード山脈

switch 文を使ってはいけない を読んで。

PHP はさておいて。私も switch より State パターンを選びますが、C 言語の関数ポインタで State パターンを実現するのは、今も迷います。言語仕様上、悪い方に倒れるのを阻止できないためです。

ハッカーが明確で読みやすいコードを書いてくれるうちは良いですが、頭のおかしい人が do という関数ポインタに全関数を入れるクソコードを書き始めたらもう全部パアです。

いやまさかそんなこと、と思うかもしれませんが、そんなクソコードが実在してるんですよ、世の中って怖いですよね…。

メモ: 技術系?の話は Facebook から転記(※)しておくことにした。

(※)本来 8月14日のエントリです。8月14日辺りでエミュレータが動いたのが嬉しくて、浮かれて Facebook に書きまくったら、このサイトに転記しきれなくなったため、未来のエントリに移動させています。

[編集者: すずき]
[更新: 2014年 8月 16日 16:38]
link 編集する

コメント一覧

  • すずき 
    C 言語だと do はキーワードなので、変数名としては使えないので、exec ですかね…。文意に変わりはありませんけど。 
    (2014年08月18日 11:44:52)
  • IKeJI 
    main = 195;
    みたいなもんですか? 
    (2014年08月26日 17:08:14)
  • すずき 
    >IKeJI さん
    コードゴルフなら超短い、その手があったか!など発見や感動がありますが、クソコードは無駄に長いし、発見もないです。
    まあ、良くこんなのメンテナンスできますわねー、って違う意味での感動はありますけど…。 
    (2014年08月26日 21:20:26)
open/close この記事にコメントする



link permalink

ファイルシステム対決

CentOS7 EXT4 vs XFS vs Btrfs vs ZFS on vda - Qiita を読んで。

参考になります(※1)。ZFS は FUSE 経由じゃない Native 実装があるのか…知らなんだ。

(※1)補足。この手のベンチマークはたくさんあるように見えて、ファイルシステム側の進化が早いため、すぐに陳腐化します。なので、新しいベンチマークは常にありがたいものです。

XFS は 1MB over のデカいファイルは速いけど、1KB くらいの細かいファイルの create/delete をぶちかます(カーネルの tarball を展開しながら、古いカーネルソースを rm -r するとか)と、すっごい遅くて嫌になって使うの辞めた記憶があるのだけど…改善されたのだろうか?

メモ: 技術系?の話は Facebook から転記(※2)しておくことにした。

(※2)本来 8月14日のエントリです。8月14日辺りでエミュレータが動いたのが嬉しくて、浮かれて Facebook に書きまくったら、このサイトに転記しきれなくなったため、未来のエントリに移動させています。

[編集者: すずき]
[更新: 2014年 8月 16日 16:40]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

マウス壊れた

一昨年買った(2012年 4月 5日の日記参照)、Logicool Perfomance MX M950 が壊れました。マウスの左ボタンがバカになって、全部ダブルクリックになってしまう、良くある壊れ方です。

形あるもの、いつか壊れるとは思っていますが、1万以上したマウスが 2年で壊れるのはちょっと悲しい。

New マウス 2号

存外に早く壊れた以外、使い勝手は最高に気に入っていたので、もう一個 M950 を買いました。アマゾンで 8,226円でした。前回は 12,000円したので、3割近く安くなっていますね。

しかし 2年前のフラッグシップモデルだった M950 が、未だにフラッグシップモデルとして君臨しているのはちょっと意外でした。余程の人気なのか、それとも新製品開発をあまりしていないのでしょうか。

Logicool マウス愛好者としては、後者でないことを祈るばかりです。

保証期間

新たにやってきた M950 の保証書を見てびっくり。保証期間「ご購入日から 3年間」の文字が輝いています。

さ、3年…だと…?ということは、壊れたマウスは保証期間内?無料で直せちゃう感じ?マジで…?

普通のメーカー保証は 1年で速攻切れる役立たずなイメージですが、3年ってすごいですね。さすがだな Logicool さん。でも、もう保証書がどっか行ってしまったから、何年でも意味なかったりするのだけど…。今度は大事に取っておきます。

[編集者: すずき]
[更新: 2014年 8月 21日 23:24]
link 編集する

コメント一覧

  • hdk 
    ロジクールの 1,500 円もしないマウスがなぜか 5 年保証で、1 年ちょっとでボタンのチャタリングが出たことがあったんですが、購入店で修理に出したら 1 か月かかって新品交換されてきました。交換後 5 年以上たっていますがチャタリングはもう出ていないので、個体差があるんですかねぇ。 
    (2014年08月22日 01:11:40)
  • すずき 
    >hdk さん
    今まで使ってきたマウスも長持ちが多かったので、偶然外れを引いたのだと思います。
    しかし 5年は長すぎではなかろうかw 
    (2014年08月23日 01:42:57)
open/close この記事にコメントする



link permalink

ARMv5 と ARMv7 アーキテクチャの名前について

ARM アーキテクチャを表すとき ARMv5T があって、ARMv6T がないのはなぜでしょう?

ARMv5T の T の部分は「バリアント」と呼ばれ、T バリアントであれば THUMB 命令セットに対応した ARM アーキテクチャである、ことを示します。他にもエンハンスト DSP 命令の E とか、Jazzele 命令の J があります。

ARMv5 までは THUMB 命令セットへの対応はオプションでした。このため、ARMv5 世代の ARM アーキテクチャは THUMB 非対応の ARMv5 と THUMB 対応の ARMv5T の 2種類が存在し得ました。実際に THUMB 未対応の ARMv5 プロセッサを作った会社があるか、まではわかりませんが。そういうプロセッサを「作っても良い」ことにはなっていました。

例えば、携帯でよく使われていた ARM926EJ-S プロセッサのアーキテクチャは ARMv5TEJ、つまり THUMB とエンハンスト DSP と Jazzele に対応したアーキテクチャ、という意味です。

しかし ARMv6 からは THUMB 対応が必須となり、THUMB の有り/無しを区別する必要がなくなり、名前も ARMv6 のみとなりました。ARMv6 は THUMB 命令セットに対応していても ARMv6T とは呼びません。対応している機能を全部並べ始めると、冗長になるためでしょう、たぶん。

なお、エンハンスト DSP 命令も v6 で ARM 命令セットに取り込まれたため、T と同時に E バリアントも消滅しています。

ARMv7 以降

さらに、最近の ARMv7 アーキテクチャでは、バリアントの考えが変わったようで、ARMv7 の後ろに対応機能を意味するアルファベットは付かなくなりました。

種類も ARMv7-A と ARMv7-R と ARMv7-M の 3つです。それぞれ「アプリケーション」「リアルタイム」「マイクロコントローラ」プロファイルの意味だそうです。対応する機能は下記の通り。

  • A: MMU、ARM、Thumb、Thumb-2、Thumb-2EE、NEON、32 ビット SIMD
  • R: ARM、Thumb、Thumb-2(オプション)、VFP、32 ビット SIMD、ハードウェア除算
  • M: Thumb-2、ハードウェア除算

アーキテクチャが対応する命令セットの規模順に並べたとき、ARM となるところもまたニクいですね。イギリス人はこういうシャレが好きなのでしょうか?

これ以上の詳細情報は ARM のサイト(ARM のサイトへのリンクを張っておきます)をご覧ください。

ARM 命令セットと THUMB 命令セットの関係

余談ですが、ARM 命令セットや THUMB 命令セットにもバージョンがあります。下記の通りです。

  • ARMv6 : THUMBv3
  • ARMv5 : THUMBv2
  • ARMv4 : THUMBv1

バージョンは 1:1 に対応しており、異なる世代を組み合わせること、たとえば ARMv6 と THUMBv2 を組み合わせることはできません。

メモ: 技術系?の話は Facebook から転記しておくことにした。なお ARMv7 の節は 8/25 に加筆。

[編集者: すずき]
[更新: 2014年 8月 26日 01:12]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

壊れないとしか言ってない

私のスマホは防水だけど、その意味は雨でも壊れない、であって、雨でも使える、って意味ではないんだなあ。

なぜなら、タッチパネルに水滴が着くとまともに動かないからです…。

メモ: 技術系の話は Facebook から転記しておくことにした。

[編集者: すずき]
[更新: 2015年 11月 29日 06:08]
link 編集する

コメント一覧

  • コメントはありません。
open/close この記事にコメントする



link permalink

hprof プロファイラ

Java の hprof というプロファイラは、準備を必要とせず(JDK 標準だから)に、CPU、ヒープ、モニタの衝突など、一通り測れる便利なプロファイラです。

特に各メソッドのカウントを「全て取る」モード(-Xrunhprof:cpu=times)は、明らかに呼び過ぎのメソッドが一発で分かるため、大変に便利です。

しかし便利な反面、実行速度が下がりすぎて使い物にならなくなる場合があります。

今日遭遇したケースは、7MBのファイルを DataInputStream から readByte() するプログラムです。通常のデバッグ実行であれば、ほんの一瞬で終わりますが、cpu=times でプロファイリングすると 10分経っても終わりません…。

どうも、細かいメソッドが頻繁に呼ばれすぎるせいで、メソッド呼び出しのカウントを行う部分がパンクしているようです。

思い出してみれば InputStream 系は InputStream -> BufferedInputStream -> DataInputStream などのように連鎖させるのでメソッド呼び出しが深く、データをロードするという処理はループ回数が多くなりがちなので、深さ×ループ回数の掛け算に比例してどんどん遅くなってしまいます。

これはよろしくありません。

頑張って軽くするには

待てるくらいの時間に収まるように、何とか軽くしてみましょう。

まず目を付けたのは readByte() です。readByte() で 1バイトつずつ読むから呼び出しカウントが多くなるわけです。ならば readLong() で 8バイトずつ読めばカウントは 1/8 です。

コードもちょい変えで済むし、お手軽高速化としては、プロファイリング時の実行速度もほぼ 8倍になる、という中々の効果です。

しかし readLong() を持ってしても 100MB オーバーとなると厳しいでしょう。もし本当にそこまで必要なら、根底から覆す(InputStream を使わないとか)別の手立てを考える必要がありそうです。

[編集者: すずき]
[更新: 2014年 8月 26日 03:15]
link 編集する

コメント一覧

  • IKeJI 
    BufferedInputStreamのうしろは何回もは呼ばれないのでは? 
    (2014年08月26日 17:13:00)
  • すずき 
    >IKeJI さん
    そうか、確かに BufferedInputStream 以降はあまり呼ばれないから、BufferedInputStream のバックエンドは呼び出し回数にほとんど関係無いですね。すみません、間違ってました。

    ただ BufferedInputStream 自体が結構遅くて、readByte() だとつらいという点は変わりません。
    試しに DataInputStream(new BufferedInputStream(new FileInputStream())) に対して、readLong() で 30万回読みだしてみますと、

    count : method
    307547 : java.io.BufferedInputStream.read
    307547 : java.io.DataInputStream.readLong
    307547 : java.io.DataInputStream.readFully
    307567 : java.io.BufferedInputStream.read1
    307568 : java.io.BufferedInputStream.getBufIfOpen
    307894 : java.io.BufferedInputStream.getBufIfOpen
    301 : java.io.FileInputStream.read
    3584 : java.io.BufferedInputStream.read
    301 : java.io.BufferedInputStream.fill

    こんな感じになっていて、getBufIfOpen がプロファイリングを激しく邪魔します。 
    (2014年08月26日 21:43:18)
  • IKeJI 
    なるほど。
    その辺のprivateなメソッドはインライン展開できそうなもんですが、何かできない理由があるんですかね?
    BufferedInputStream.readをfinalにしたら早くなるんだろうか? 
    (2014年08月27日 00:42:45)
  • すずき 
    >IKeJI さん
    BufferedInputStream をコピーした OreBufferedInputStream を作って、read を final にして試してみました。

    (final にする前)
    count method
    616787 net.katsuster.semu.arm.OreBufferedInputStream.read
    616787 java.io.DataInputStream.readFully
    616787 java.io.DataInputStream.readLong
    616787 net.katsuster.semu.arm.OreBufferedInputStream.read1
    616787 net.katsuster.semu.arm.OreBufferedInputStream.getBufIfOpen
    617390 net.katsuster.semu.arm.OreBufferedInputStream.getBufIfOpen
    603 java.io.FileInputStream.read
    2 java.io.FileInputStream.<init>
    3584 java.io.BufferedInputStream.read
    896 java.io.DataInputStream.readInt
    3584 java.io.BufferedInputStream.getBufIfOpen

    (final にした後)
    616787 net.katsuster.semu.arm.OreBufferedInputStream.read
    616787 java.io.DataInputStream.readFully
    616787 java.io.DataInputStream.readLong
    616787 net.katsuster.semu.arm.OreBufferedInputStream.read1
    617390 net.katsuster.semu.arm.OreBufferedInputStream.getBufIfOpen
    616787 net.katsuster.semu.arm.OreBufferedInputStream.getBufIfOpen
    603 java.io.FileInputStream.read
    3584 java.io.BufferedInputStream.getBufIfOpen
    2 java.io.FileInputStream.<init>
    896 java.io.DataInputStream.readInt

    速度も変わらないですね。 
    (2014年08月27日 02:09:36)
  • IKeJI 
    DataInputStreamがOreBufferedInputStreamをInputStreamとして扱っているからでしょうか? 
    (2014年08月27日 13:32:33)
  • すずき 
    >IKeJI さん
    もしかして JIT でインライン展開されようとされまいと、関数呼び出しカウントは行われるんじゃないですかね?
    BufferedInputStream.read が遅いわけではないので、単にカウントが遅いのでは。 
    (2014年08月28日 10:11:24)
  • IKeJI 
    そうですが、プロファイルしない時の実行速度はあがるのでは? > 関数呼び出しカウントは行われる 
    (2014年08月28日 14:26:29)
  • すずき 
    >IKeJI さん
    プロファイルするときと、しないときとで、JIT の動作が変われば、インライン展開されそうなメソッドなのに、プロファイラにカウントされる理由が付きますかね…?
    うーむ、でも自分で書いておいてなんですが、そこまでやらないよな…さすがに…。 
    (2014年08月29日 17:02:23)
open/close この記事にコメントする



こんてんつ

open/close wiki
open/close Java API

過去の日記

open/close 2002年
open/close 2003年
open/close 2004年
open/close 2005年
open/close 2006年
open/close 2007年
open/close 2008年
open/close 2009年
open/close 2010年
open/close 2011年
open/close 2012年
open/close 2013年
open/close 2014年
open/close 2015年
open/close 2016年
open/close 2017年
open/close 過去日記について

その他の情報

open/close アクセス統計
open/close サーバ一覧
open/close サイトの情報