MIPS(4)

一頃に比べて、日中の時間が短くなってきてるようだ。一年で一番日中の時間が長い夏至を とおにとおり越しているから、当たり前なんだけど。。

今日の、日の出・日の入は何時? 新聞に出てるよ。Webでも調べられるのかな。そういうのは 国立天文台にあるでしょう。こういうのは、こよみの計算 って言うんだ。ならば、計算式はどうなってるの?

こよみの計算で調べていたら、 計算サイト なんてのに行き着いた。このサイト、答え一発で有名な、カシオさん提供なのね。

ちゃんと計算しようとすると、それなりの本を読む必要があるみたいだ。で、理論は抜きにして、 計算式をJavascriptで提供してる方が居た。

solar-j.htmlの中にスクリプトが埋め込まれている。サイン・コサイン・タンジェントと、暦が 出てくるのね。球面幾何学なんでしょうかね?

原理は、こちらの図が 好いのかな。そして、 コメントが親切に書いてあるサイトも参照かな。

そうだ、アマチュア無線家の一部の人が大好きな衛星通信。いつ日本上空に衛星が現れるか 一生懸命に計算してたけど、計算の考え方は、日の出・日の入と一緒かな。だとしたら、そちら 方面も探ってみるかな?

JavaScriptで人工衛星の位置を表示する

アマチュア衛星通信初心者のためのWiki

LinuxでもMIPS

FreeBSDでMIPS版のNetBSDが動く(しかも、kdbも)んで、大満足なんだけど、直交性を考えたら Linuxでも動いて欲しいなあ。探してみたよ。

そしたら、以前お世話になったサイトの方が、 MIPSのクロスコンパイラで実行ファイルの作成 と言うお題で記事を書かれていた。早速追試してみる。こういう検証実験は、ソフトウェア業界の 正常なる発展に大きく寄与するものであります。

GNUのサイトから取ってきたやつで、まずはアセンブラ系を作ります。おいらが使うサイトは、 RIng Serverだったりします。

[sakae@archbang binutils-2.21.1]$ mkdir build_mips && cd build_mips
[sakae@archbang build_mips]$ ../configure --target=mipsel-linux-elf --disable-nls
[sakae@archbang build_mips]$  sudo make install

次は、 newlib-download へ行って、Glibの代用品(?)を取ってきます。それを展開して、gcc系と融合させるための準備を してから、gccを作ります。

[sakae@archbang ~]$ cd gcc-4.7.1/
[sakae@archbang gcc-4.7.1]$ ln -s /home/sakae/newlib-1.20.0/newlib/ .
[sakae@archbang gcc-4.7.1]$ ln -s /home/sakae/newlib-1.20.0/libgloss/ .
[sakae@archbang gcc-4.7.1]$ mkdir build_mips && cd build_mips
[sakae@archbang build_mips]$ ../configure --target=mipsel-linux-elf --enable-languages=c \
  --with-newlib --disable-nls --disable-multilib --disable-libssp \
  --with-headers=/home/sakae/gcc-4.7.1/newlib/libc/include/
[sakae@archbang build_mips]$ make
[sakae@archbang build_mips]$ sudo make install

gcc-4.6.0だと、途中でコンパイルエラーに成ったので、ええい、面倒とばかり新しいやつを 試したって訳。以下、newlibも新しい版を選びましたよ。

最後に、ライブラリーを作ります。

[sakae@archbang newlib-1.20.0]$ ./configure --target=mipsel-linux-elf --disable-nls
[sakae@archbang newlib-1.20.0]$ make
[sakae@archbang newlib-1.20.0]$ sudo make install

長い長い時間がかかって、やっと出来上がりました。実を言うと、この道はいつか来た道、なんです。 そう、HITACHIで出している、8Bitマイコン、H8を秋月から買って来て、使った時、こういう環境を 作りました。H8へ書き込むのに必要な、write(だったかな)も、どこからか落としてきて一緒に 使いましたねぇ。

H8への書き込み保障回数は、確か100回だったはず。何回書き込んだか、チェックしながら使った ものです。今となっては、とっても懐かしい記憶。

MIPSの試運転

そんじゃ、早速コンパイルして走らせてみます。何は無くともHelloですかね。これは、K&R本の読者の 義務でもあります。

#include <stdio.h>
int main(void)
{
        printf("hello world\n");
        return 0;
}
[sakae@archbang z]$ mipsel-linux-elf-gcc -g hello.c
/usr/local/lib/gcc/mipsel-linux-elf/4.7.1/../../../../mipsel-linux-elf/bin/ld: warning: cannot find entry symbol _start; defaulting to 0000000000400038
/tmp/ccYn8nUQ.o: In function `main':
/home/sakae/z/hello.c:4: undefined reference to `puts'
collect2: error: ld returned 1 exit status

先輩も、これに泣かされたみたいです。

[sakae@archbang z]$ mipsel-linux-elf-gcc -T idt.ld -g hello.c
[sakae@archbang z]$ mipsel-linux-elf-run ./a.out
hello world

以上、試運転終わり。。。 じゃ、寂しいので、まずは、mipsel-linux-elf-runって何者よ。--helpを 付けると、いろいろ出て来るので、ちょいとお試し。

[sakae@archbang z]$ mipsel-linux-elf-run --info-memory a.out
Memory maps:
 memory region 0x7fff8000,0x8000
 memory alias 0xa0000000@0x1,0x20000000%0x800000,0x80000000@0x1
hello world
[sakae@archbang z]$ mipsel-linux-elf-run --memory-fill 0xdeadbeaf a.out
Missing fill value between 0 and 255
[sakae@archbang z]$ mipsel-linux-elf-run --memory-fill 55 a.out
hello world

mipsel-linux-elf-runって、どうやら前々回ぐらいに造ったmips用gdbの一族みたい。殺虫剤が手に入ったかと思ったけど、気休め程度だったよ。次は、あれかな。

[sakae@archbang z]$ file a.out
a.out: ELF 32-bit LSB executable, MIPS, MIPS-I version 1 (SYSV), statically linked, with unknown capability 0xf41 = 0x756e6700, with unknown capability 0x70100 = 0x1040000, not stripped
[sakae@archbang z]$ mipsel-linux-elf-readelf -a a.out
ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           MIPS R3000
  Version:                           0x1
  Entry point address:               0xa0020004
  Start of program headers:          52 (bytes into file)
  Start of section headers:          157812 (bytes into file)
  Flags:                             0x1001, noreorder, o32, mips1
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         1
  Size of section headers:           40 (bytes)
  Number of section headers:         29
  Section header string table index: 26

そんじゃgdbが使えるかな?

[sakae@archbang z]$ mipsel-linux-elf-gdb a.out
GNU gdb (GDB) 7.2
Copyright (C) 2010 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "--host=i686-pc-linux-gnu --target=mipsel-linux-elf".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
Reading symbols from /home/sakae/z/a.out...done.
(gdb) b main
Breakpoint 1 at 0xa0020348: file hello.c, line 4.
(gdb) run
Starting program: /home/sakae/z/a.out
Don't know how to run.  Try "help target".

だめだって怒られたよ。H8の時は確かシュミレータで動かしたな。

(gdb) target sim
Connected to the simulator.
(gdb) load
Loading section .text, size 0x3a30 vma 0xa0020000
Loading section .init, size 0x38 vma 0xa0023a30
Loading section .fini, size 0x28 vma 0xa0023a68
Loading section .eh_frame, size 0x4 vma 0xa0023a90
Loading section .jcr, size 0x4 vma 0xa0023a94
Loading section .ctors, size 0x8 vma 0xa0023a98
Loading section .dtors, size 0x8 vma 0xa0023aa0
Loading section .rodata, size 0x14 vma 0xa0023aa8
Loading section .data, size 0x830 vma 0xa0023ac0
Loading section .sdata, size 0x18 vma 0xa00242f0
Start address 0xa0020004
Transfer rate: 137248 bits in <1 sec.
(gdb) b main
Breakpoint 1 at 0xa0020348: file hello.c, line 4.
(gdb) run
Starting program: /home/sakae/z/a.out

Breakpoint 1, main () at hello.c:4
4                   printf("hello world\n");
(gdb) n
hello world
5                       return 0;
(gdb) disassemble main
Dump of assembler code for function main:
   0xa0020338 <+0>:     addiu   sp,sp,-24
   0xa002033c <+4>:     sw      ra,20(sp)
   0xa0020340 <+8>:     sw      s8,16(sp)
   0xa0020344 <+12>:    move    s8,sp
   0xa0020348 <+16>:    lui     v0,0xa002
   0xa002034c <+20>:    addiu   a0,v0,15016
   0xa0020350 <+24>:    jal     0xa00204e8 <puts>
   0xa0020354 <+28>:    nop
=> 0xa0020358 <+32>:    move    v0,zero
   0xa002035c <+36>:    move    sp,s8
   0xa0020360 <+40>:    lw      ra,20(sp)
   0xa0020364 <+44>:    lw      s8,16(sp)
   0xa0020368 <+48>:    addiu   sp,sp,24
   0xa002036c <+52>:    jr      ra
   0xa0020370 <+56>:    nop
End of assembler dump.

まあ、ここまでは普通な事。loadした時、Starting addressって出てたので、そこから 逆アセンブルしてみる。(適当に、ラベルの冒頭付近を掲載)

(gdb) disassemble 0xa0020004,+1000
   0xa0020004 <_start+0>:       lui     v0,0x2010
   0xa0020008 <_start+4>:       mtc0    v0,c0_sr
   0xa002000c <_start+8>:       mtc0    zero,c0_cause
   0xa0020010 <_start+12>:      nop
   0xa0020014 <_start+16>:      lui     t0,0x0
   0xa0020018 <_start+20>:      addiu   t0,t0,0
   0xa002001c <_start+24>:      beqz    t0,0xa002002c <_start+40>
   0xa0020020 <_start+28>:      nop
   0xa0020024 <_start+32>:      jalr    t0
     :
   0xa002009c <zerobss+0>:      lui     v0,0xa002
   0xa00200a0 <zerobss+4>:      addiu   v0,v0,17160
   0xa00200a4 <zerobss+8>:      lui     v1,0xa002
   0xa00200a8 <zerobss+12>:     addiu   v1,v1,17536
   0xa00200ac <zerobss+16>:     sw      zero,0(v0)
   0xa00200b0 <zerobss+20>:     sltu    at,v0,v1
   0xa00200b4 <zerobss+24>:     bnez    at,0xa00200ac <zerobss+16>
     :
   0xa0020104 <init+0>: lui     t9,0x0
   0xa0020108 <init+4>: addiu   t9,t9,0
   0xa002010c <init+8>: beqz    t9,0xa002011c <init+24>
   0xa0020110 <init+12>:        nop
   0xa0020114 <init+16>:        jalr    t9
      :
   0xa002016c <_exit+0>:        lui     t0,0x0
   0xa0020170 <_exit+4>:        addiu   t0,t0,0
   0xa0020174 <_exit+8>:        beqz    t0,0xa0020184 <_exit+24>
   0xa0020178 <_exit+12>:       nop
   0xa002017c <_exit+16>:       jalr    t0
   0xa0020180 <_exit+20>:       nop
   0xa0020184 <_exit+24>:       break   0x3ff
      :
   0xa0020334 <frame_dummy+88>: addiu   sp,sp,24
   0xa0020338 <main+0>: addiu   sp,sp,-24
   0xa002033c <main+4>: sw      ra,20(sp)
   0xa0020340 <main+8>: sw      s8,16(sp)

ふーん、OSのまねをしてるんだ。mainって、JALで訪れる楽園です。普通の人は、この中で 遊ぶだけね。

そんじゃ、どんな風にEndingを迎えるか、追っ手みます。

(gdb) stepi
6       }
(gdb)
0xa0020360      6       }
(gdb)
0xa0020364      6       }
(gdb)
0xa0020368      6       }
(gdb)
0xa002036c      6       }
(gdb)
init () at ../../.././libgloss/mips/crt0.S:232
232     ../../.././libgloss/mips/crt0.S: No such file or directory.
        in ../../.././libgloss/mips/crt0.S
(gdb)
exit (code=0) at ../../../.././newlib/libc/stdlib/exit.c:60
60      ../../../.././newlib/libc/stdlib/exit.c: No such file or directory.
        in ../../../.././newlib/libc/stdlib/exit.c
(gdb) c
Continuing.

Program exited normally.

どうやら、地の果てはnewlibの中っぽいぞ。ついでに、宇宙の始まりも見とくか。

  :
Start address 0xa0020004
Transfer rate: 137248 bits in <1 sec.
(gdb) b _start
Breakpoint 1 at 0xa0020008: file ../../.././libgloss/mips/crt0.S, line 85.
(gdb) run
Starting program: /home/sakae/z/a.out

Breakpoint 1, _start () at ../../.././libgloss/mips/crt0.S:85
85      ../../.././libgloss/mips/crt0.S: No such file or directory.
        in ../../.././libgloss/mips/crt0.S

idt.ld

hello.cをコンパイルする時、-Tオプションに、idt.ldなんてのを与えた。 これは一体何? manを紐解いてみると

       -T script
           Use script as the linker script.  This option is supported by most
           systems using the GNU linker.  On some targets, such as bare-board
           targets without an operating system, the -T option may be required
           when linking to avoid references to undefined symbols.

リンカースクリプトですって。何処にあるの? おいらの場合、/usr/localの中に mips系環境が入っているんで、その中を探してみた。

[sakae@archbang ~]$ lv /usr/local/mipsel-linux-elf/lib/idt.ld
ENTRY(_start)
STARTUP(crt0.o)
OUTPUT_FORMAT("elf32-bigmips", "elf32-bigmips", "elf32-littlemips")
GROUP(-lc -lidt -lgcc)
   :
SECTIONS
{
  . = 0xA0020000;
  .text : {
    _ftext = . ;
    PROVIDE (eprol = .);
    *(.text)
    *(.text.*)
    *(.gnu.linkonce.t.*)
    *(.mips16.fn.*)
    *(.mips16.call.*)
  }
    :

これの解説は、例のリンカーローダー本を読めばいいのだな。

include

何は無くともHellow worldした時、当たり前のようにstdio.hを取り込んでいた。他にどんなのが 有るの?

[sakae@archbang local]$ cd mipsel-linux-elf/include/
[sakae@archbang include]$ ls
alloca.h   envz.h      inttypes.h  process.h  signal.h     termios.h
_ansi.h    errno.h     langinfo.h  pthread.h  stdint.h     time.h
argz.h     fastmath.h  libgen.h    pwd.h      stdio_ext.h  unctrl.h
ar.h       fcntl.h     limits.h    reent.h    stdio.h      unistd.h
assert.h   fnmatch.h   locale.h    regdef.h   stdlib.h     utime.h
bits       getopt.h    machine     regex.h    string.h     utmp.h
complex.h  glob.h      malloc.h    rpc        strings.h    wchar.h
ctype.h    grp.h       math.h      sched.h    sys          wctype.h
dirent.h   iconv.h     newlib.h    search.h   _syslist.h   wordexp.h
envlock.h  ieeefp.h    paths.h     setjmp.h   tar.h
[sakae@archbang include]$ ls sys/
cdefs.h           dir.h       iconvnls.h  resource.h  string.h     _types.h
config.h          errno.h     lock.h      sched.h     syslimits.h  types.h
custom_file.h     fcntl.h     param.h     signal.h    timeb.h      unistd.h
_default_fcntl.h  features.h  queue.h     stat.h      time.h       utime.h
dirent.h          file.h      reent.h     stdio.h     times.h      wait.h

微妙に揃ってるな。(笑)

組み込みScheme

ひょっとしたら、以前、移植するぞでやった、教育用Schemeが動くかも知れないな。無謀にも やってみるか。こういうのを、他人の褌で相撲を取るって言うんだな。

[sakae@archbang Simple]$ make
mipsel-linux-elf-gcc -g -c main.c
mipsel-linux-elf-gcc -g -c cell.c
mipsel-linux-elf-gcc -g -c list.c
mipsel-linux-elf-gcc -g -c function.c
mipsel-linux-elf-gcc -g -c compute.c
mipsel-linux-elf-gcc -g main.o cell.o list.o function.o compute.o -o simp -lm -T idt.ld
/usr/local/lib/gcc/mipsel-linux-elf/4.7.1/../../../../mipsel-linux-elf/lib/libidt.a(idtmon.o):/home/sakae/newlib-1.20.0/mipsel-linux-elf/libgloss/mips/../../.././libgloss/mips/idtmon.S:37: multiple definition of `read'
main.o:/home/sakae/Simple/main.c:1417: first defined here
/usr/local/lib/gcc/mipsel-linux-elf/4.7.1/../../../../mipsel-linux-elf/lib/libc.a(lib_a-timesr.o): In function `_times_r':
(.text+0x0): undefined reference to `times'
collect2: error: ld returned 1 exit status
make: *** [simp] Error 1

うーん、惜しいな。あと一歩の所だぞ。折角だからちょいと手を入れてみる。

まずは、read()がぶつかってる。readは、newlibの商法登録だから、後から来た、simp.h,main.c,function.cの中にある read()は使用禁止。だったら、別の名前にしてやればいい。vimとかだと

:%s/read(/myread(/gc

で、いけるよ。

次のtimesのエラーは、涙を呑んで、時間関係の手続は諦めよう。だってハードウェアの 機能をもろに使ってるんだもの。clock()が あちこちに散らばっていて修正が面倒なんで、main.c内にダミーを書いてごまかす。

//#include <time.h>
#define CLOCKS_PER_SEC 1
#define clock_t int
int clock(void) { return (123); }  // dummy

さあ、これでどうだ。

[sakae@archbang Simple]$ make
mipsel-linux-elf-gcc -g -c main.c
mipsel-linux-elf-gcc -g -c cell.c
mipsel-linux-elf-gcc -g -c list.c
mipsel-linux-elf-gcc -g -c function.c
mipsel-linux-elf-gcc -g -c compute.c
mipsel-linux-elf-gcc -g main.o cell.o list.o function.o compute.o -o simp -lm -T idt.ld
[sakae@archbang Simple]$ mipsel-linux-elf-run simp
educational Scheme compiler Simple Ver0.18.9 (written by sasagawa888)
ReservedInstruction at PC = 0xa0028f88
program stopped with signal 4.

signal 4 って、Illegal Instruction なのね。きっと、使えるメモリー範囲をオーバーしちゃって おかしくなってるんだろうな。CELLの割り当てサイズを縮小してみるか。昔を思い出して、100Kの セルを割り当て。

[sakae@archbang Simple]$ mipsel-linux-elf-run simp
educational Scheme compiler Simple Ver0.18.9 (written by sasagawa888)
Simp> (car '(a b c))
a
Simp> (gbc #t)
Simp> (gbc)
enter GBC free= 79345
exit  GBC free= 94124
Simp> (exit)
- good bye. -

おおお、動いたね。同じ要領でやれば、秋月のボードでも動くだろう。これぞ組み込みSchemeだな。 問題になるのは、本体は、single binaryになってるからいいんだけど、外付けのsimpmacs.scmをどうするか だけだな。