lisp meet up #25, 8-bit pic マイコン用ネイティブコンパイラの作成

24
8-bit PIC マイコン用ネイティブコンパイラの作成 2015.2.25 Masayuki Takagi Lisp Meet Up presented by Shibuya.lisp #25

Upload: masayukitakagi

Post on 16-Jul-2015

898 views

Category:

Technology


1 download

TRANSCRIPT

Page 1: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

8-bit PIC マイコン用ネイティブコンパイラの作成

2015.2.25 Masayuki Takagi

Lisp Meet Up presented by Shibuya.lisp #25

Page 2: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-2-

自己紹介

高木 雅之

cl-cuda : a library to use NVIDIA CUDA in Common LispCommon Lisp から CUDA を使うライブラリ。半年ほどまえに、ここで紹介しました。

仕事は?先月に会社を設立。売上はまだないです >_<

Common Lisp

Page 3: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-3-

8-bit PICマイコン向けネイティブコンパイラ:動機

これまで、まともにアセンブラを書いたことがなかったのです。

1月下旬:はじめての PIC マイコン

2月上旬:はじめてのアセンブラ

PIC マイコンをはじめて触りました。

PIC で何作ろう?PIC用のコンパイラ作ろう。

2月中旬:PIC 用のコンパイラ

Page 4: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-4-

今日の話の流れ

そのあと、今回作った、PIC マイコン用のコンパイラについて説明します。

PIC マイコンについて

PIC マイコン用コンパイラについて

最初に、PIC マイコン自体について説明します。

Page 5: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-5-

PIC マイコンとは?

いまだと Arduino とかありますが、PIC はそれより昔からよく使われています。

マイクロコントローラ

マイクロチップ・テクノロジー社

演算器、メモリ、発振回路、割り込み、タイマ、リセット、スリープなど各種回路が1チップに。

今回使ったのは、一番小さな 8 ビット PIC。PIC12F683 や PIC16F630。

8ビット、16ビット、32ビット

Page 6: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-6-

ピン

PIC12F683(8ピン) PIC16F630(14ピン)

VDD

上2本(VDD, VSS)を電源に接続

残り6本を IO に使用可能(HI/LOW)

ただし、4番ピンは入力のみ

GP5

GP4

GP3

VSS

GP0

GP1

GP2

VDD VSS

RA5RA4RA3RC5RC4RC3

RA0RA1RA2RC0RC1RC2

上2本(VDD, VSS)を電源に接続

残り12本を IO に使用可能(HI/LOW)

ただし、4番ピンは入力のみ

Page 7: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-7-

PIC12F683

プログラムメモリは、2K ワード

SRAM は、128 バイト

DDPROM は、256 バイト

Page 8: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-8-

PIC12F683 デバイス概観

ALU

乗算器、FPU、16ビット演算器はない

プログラムメモリとデータメモリ

ハードウェアスタック

Page 9: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-9-

メモリアーキテクチャ

プログラムメモリとデータメモリが分離(ハーバード・アークテクチャ)

プログラムメモリには、専用の機器でプログラムを書き込む

プログラムからプログラムメモリを操作することはできない

データメモリプログラムメモリ

Page 10: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-10-

プログラムメモリ

プログラムメモリは 2048 ワード(000h-07FFh)

プログラムは 0 番地から始まる

4 番地は割り込み発生時にここにジャンプ

ハードウェアスタックを持つ

CALL 命令などで、戻り値アドレスが積まれる

Page 11: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-11-

データメモリ

データメモリは、SFR と GPR からなる

SFR は、Special Function Registers

GPR は、General Purpose Registers

SFR は、CPU やその他機能の制御に使う

残念なことに、番地により「バンク」を切り替えなければならない

SFR

汎用レジスタ

SFR

汎用レジスタ

バンク0 バンク1

00h

20h

80h

A0h

BFh

7Fh

Page 12: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-12-

スペシャル・ファンクション・レジスタ

SFR は、CPU やその他機能の制御に使う

STATUS は、バンク切替(RP0)、ゼロビット(Z)、キャリービット(DC,C)など

GPIOは、ピンの状態(High/Low)

TRISIOは、ピンの入出力モード

PCL と PCLATH は、プログラムカウンタ

INTCON と IOC は、割り込みの有効/無効

Page 13: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-13-

W レジスタ

ALU は、W レジスタとデータメモリから入力を受け付ける

通常の CPU の「レジスタ」に相当

ただし、1つしかない

W レジスタ レジスタ

データメモリ メモリ

EEPROM ストレージ

PIC マイコン 通常のCPU

記憶装置の対応

Page 14: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-14-

内蔵発振回路

発振回路を内蔵

デフォルトの周波数は、4MHz ±1%

1命令サイクル = 4クロック = 1μsec

Page 15: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-15-

命令セット

ADDWF ANDWF CLRF CLRW COMF DECF

DECFSZ INCF INCFSZ IORWF MOVF MOVWF

NOP RLF RRF SUBWF SWAPF XORWF

BCF BSF BTFSC BTFSS ADDLW ANDLW

CALL CLRWDT GOTO IORLW MOVLW RETFIE

RETLW RETURN SLEEP SUBLW XORLW

命令は35種類のみ。非常に簡単

要する命令サイクルは、1サイクル(=1μsec@4MHz)

ただし、CALLや条件分岐などは、2サイクル

Page 16: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-16-

ちょっと面倒

何をするにも、単一の W レジスタを要するので、ちょっと面倒

データのムーブ(R0番地からR1番地へデータをコピー)

MOVF R0,W

MOVWF R1

END

整数の加算(R0番地に 42 を加算)

MOVLW 42

ADDWF R0,F

END

Page 17: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-17-

コンパイラの概要

ホスト言語は、ML 系言語の本当に小さなサブセット

ターゲット言語は、8-bit PIC マイコンのアセンブリ

コンパイラ言語は、Common Lisp

コンパイラの設計は、MinCaml を参考にした(MinCaml ですみません…)

Page 18: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-18-

MinCaml とは?

http://esumii.github.io/min-caml/

Page 19: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-19-

構文

今回のコンパイラ MinCaml

定数

プリミティブ演算(+,-,*,/ など)

条件分岐 if e1 then e2 else e3

変数定義 let

変数の読み出し x

再帰関数定義 let rec

関数呼び出し e e1, …, en

組の作成 (e1, …, en)

配列の作成 Array.create e1 e2

組の読み出し let

配列の読み出し e1.(e2)

配列への書き込み e1.(e2) ← e3

定数

プリミティブ演算

条件分岐

変数定義

変数の読み出し

再帰関数定義(クロージャ不採用)

関数呼び出し

組は不採用

配列は不採用

SFRへの書き込み setreg

Page 20: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-20-

コンパイルステージ

今回のコンパイラ MinCaml

字句解析

構文解析

型推論

K正規化

α変換

β簡約

ネストした let の簡約

インライン展開

不要定義削除

定数畳み込み

クロージャ変換

仮想マシンコード生成

即値最適化

レジスタ割当て

アセンブリ生成

(CommonLisp のリーダを使用)

(型は 8 ビット整数のみ)

K正規化

α変換

β簡約

ネストした let の簡約

(最適化はあとで)

クロージャ変換

仮想マシンコード生成

レジスタ割当て

アセンブリ生成

(最適化はあとで)

Page 21: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-21-

呼び出し規約

当初、ソフトウェアスタックに積んで渡していた

間接アドレッシングが煩雑なため、方針変更

入力用疑似レジスタ(I0-I7)、ローカル用疑似レジスタ(L0-L7)

引数は、入力用レジスタに格納して、呼び出される関数に渡す

関数は、ローカル用レジスタを自由に使える

戻り値は、W レジスタに格納して返す

関数呼び出し時に、「生きているレジスタ」をスタックに退避する

Page 22: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-22-

クロージャを不採用とした理由

クロージャには、間接アドレスへのジャンプが必要

CALL 命令は、オペランドに即値のみ受け付ける

間接アドレスへのジャンプは、プログラムカウンタへの書き込みで可能

しかし、いろいろ面倒

PCL と PCLATH

戻りアドレスの計算

戻りアドレスの管理(ハードウェアスタックを使えない)

PCL の桁上がりの考慮

Page 23: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-23-

API

defpic

defpicmacro

pic-compile

pic-disassemble

Page 24: Lisp Meet Up #25, 8-bit PIC マイコン用ネイティブコンパイラの作成

© 2015 Masayuki Takagi-24-

サンプル - LED

(defpic init ()

(progn

(setreg :gpio #x0)

(setreg :cmcon0 #b00000111)

(setbank1)

(setreg :trisio #b00001000)

(setreg :ansel #x0)

(setreg :ioc #x0)

(setbank0)

(setreg :intcon #b00000000)))

(defpic main ()

(progn

(setreg :gpio #b00100000)

(mdelay 50)

(setreg :gpio #b00000000)

(mdelay 950)

(main)))

(defpic mdelay1 ()

(loop 52

0))

(defpicmacro mdelay (n)

(unless (<= 0 n 65535)

(error "The value ~S is invalid." n))

(multiple-value-bind (q r) (truncate n 256)

(if (= q 0)

`(loop ,r (mdelay1))

`(loop ,q (loop ,r (mdelay1))))))