AKI-SH2/7045のCクロスコンパイラ環境でのはじめてのプログラミング
CYGWIN+GCC

Copyright(C)30Nov2002
coskx
A YAMASHITA


1.はじめに
この文書は,Windows2000パソコンにAKI-SH2/7045のC言語クロスコンパイル環境での,コンパイル作業のための方法を記述しています。あらかじめ指導者あるいはパソコン管理者が構築したC言語クロスコンパイラ環境で,C言語によるSH2/7045プログラミングを学ぼうとする方がプログラミングを行ない,AKI-SH2/7045でプログラムが動作するまでを解説します。C言語のプログラミングについては別の文書で学んでください。

図1.1 AKI-SH2/7045とマザーボード(山下)

電源部,LED部,Write-Runスイッチは独自仕様

マザーボード拡張は以下の通り
LEDはPortEのbit9,bit11(PortEのHのbit1,bit3)に接続
pushSWはPortEのbit13,15(PortEのHのbit5,bit7)に接続
4BitSWはPortBのbit2,3,4,5(PortBのLのbit2,3,4,5)に接続

本文書で記述してある作業の特徴
Cプログラムソースファイルが出来上がったら,windowsのドラッグ&ドロップでコンパイルしフラッシュメモリ書き込みする手順。

前提
(1)Cygwinのシステムがc:\cygwinに導入されているものとします。「C:\cygwin\bin」に「cygwin1.dll」があること。
(2)gccの環境が整い,「sh-hms-coff-gcc」「sh-hms-coff-objcopy」が利用できるようになっているものとします。「C:\cygwin\usr\local\sh\bin」に置かれているものとします。もし設定が異なっていたら,コンパイル用コマンド「H8gcc.cmd」をカスタマイズします。
(3)コンパイル用コマンドは「各作業ファイル」に入っているものとします。
(4)転送ソフト「h8write.exe」を利用します。ご自身でダウンロードして,gccコンパイラと同じフォルダに入れてください。

転送ソフト「h8write.exe」はみついわゆきお氏のオープンツールです。次の場所から入手できます。
http://mes.sourceforge.jp/h8/writer-j.html

注意
この文書で扱っているshgcc.cmdはWindows2000,WindowsXP,WindowsVista,Windows7で使用可能です。
残念ながらWindows95/98では動作しません。
コンパイラ群の名前やインストールフォルダ名が異なる場合は,使用者の責任において「shgcc.cmd」を変更してください。

SH2-7045マニュアルを読む時の注意
マニュアル中に「Aマスク」という表現が出てくるが,SH2-7045はAマスク製品である。
(検索キーワード Aマスク,Aマスク)

2.
プログラムの作成から実行まで
シングルボードマイコンAKI-SH2/7045内で動作するプログラムはパソコン上で開発され、シングルボードマイコンAKI-SH2/7045にフラッシュメモリ書き込みされます。パソコンで開発されるソースプログラムはC言語で記述され、クロスコンパイラにより、オブジェクトプログラムに変換され、最後はダウンロード形式(xxxxxx.mot)になります。
シングルボードマイコンAKI-SH2/7045を動作させるまでの大きな流れは以下のようになります。
(1)パソコン上で作業用のフォルダの用意
(2)パソコン上でCソースプログラムの作成
(3) パソコン上でダウンロード形式ファイル(実行プログラム)の作成(クロスコンパイル、コード変換)
(4)パソコン上の転送ソフトによる,ダウンロード形式ファイル(実行プログラム)のAKI-SH2/7045への書き込み操作
これら四つの作業によりシングルボードマイコン内で動作させることが出来ます。

3.テンプレートフォルダの実行
(1)図3.1に示すテンプレートフォルダでの実行の様子を確かめてみよう。テンプレートフォルダのダウンロードは 「 ここ 」 です。


図3.1 小坂のテンプレートフォルダ

このテンプレートの内容は次の通り

ファイル 内容
7040S.H

SH7045のレジスタのアドレス配置ヘッダファイル

sh_7045.h 小坂の標準ヘッダ
shgcc.cmd コンパイルコマンド
startup.s スタートアップルーチンアッセンブリソース
romsh7045.x リンカスクリプト
xxxxxx.c Cプログラム
to_H8.ht ハイパーターミナルファイル(ダブルクリック

(2)テンプレートフォルダがダウンロードできたら,解凍し,「xxxxxx.c」の内容をエディタで確かめてみてください。
プログラムは,AKI-SH2/7045拡張マザーボード上のLEDを点滅させるものです。プログラムの内容には深入りしないことにしましょう。

リスト プログラムソースファイル"xxxxxx.c"

#include "7040S.H"           //IOポートアドレス定義
#include "sh_7045.h"         //基本関数群 sh_7045.hの先頭に説明がある

void msecwait(int msec)
/*msec間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<9450;j++);    /*9450は実測によって求めた値*/
    }
}

int main(void)
{
    initLed();
    while(1){
        turnOnLed(0); /*LED0の点灯*/
        turnOffLed(1); /*LED1の消灯*/
        msecwait(500);
        turnOnLed(1); /*LED1の点灯*/
        turnOffLed(0); /*LED0の消灯*/
        msecwait(500);
    }
}


(3)この後の作業は次のようになります。
ただし,図3.1のテンプレートフォルダは「デスクトップ」あるいは「マイドキュメント」の中にあるとします。

表3.1 フラッシュメモリ書き込み形式ファイルの作成とROMライター書き込み操作から実行までの手順

 

パソコン側

マイコンSH2/7045側
注意:shは,電源スイッチONの瞬間に,状態選択スイッチの状態を検査しますので,必ず<1><2><3>の手順が必要です

(1)  

 

<1>AKI-SH2/7045のマザーボード上の電源スイッチをOFFにします。
<2>AKI-SH2/7045のマザーボード上の状態選択スイッチをライト(Write)モードにします。ライトモードとはマイコンAKI-SH2/7045がパソコンからプログラムコードを受け取り,フラッシュメモリに書き込むモードのことです。
<3>AKI-SH2/7045のマザーボード上の電源スイッチをONにします。

(2)

「xxxxxx.c」を「shgcc.cmd」にドラッグ&ドロップする。

「h8write」を表示して止まるようであれば,シリアルケーブルの結線あるいはスイッチや電源が異常

「h8write
SH2/7045F or 7050F is ready!  2003/1/1 Yukio Mituiwa.」ここまで来て止まったように見えたらもう少しそのまま様子を見てください。転送データが表示されて転送が終ります。

この時,次のようなファイルができます。

ファイル 内容
xxxxxx.mot 転送形式の実行ファイル
xxxxxx.coff 実行ファイル
xxxxxx.map mapファイル

 
(3)  

<1>転送が終了したら、AKI-SH2/7045のマザーボード上の電源スイッチをOFFにします。
<2>AKI-SH2/7045のマザーボード上の状態選択スイッチをラン(Run)モードにします。
<3>AKI-SH2/7045のマザーボード上の電源スイッチをONにします。

(4)ここまでの作業が順調に出来ていたら,AKI-SH2/7045マザーボード上の2つのLEDが点滅して動作が確認できるはずです。

4.新規プログラムの開発手順

4.1 パソコン上で作業用のフォルダの用意

テンプレートフォルダの複製を作ってフォルダ名をled00と,xxxxxx.cのみ消去し,新しいファイルled00.cを作成します。

4.2 プログラムの作成
Windowsマシン上のエディタ上で、C言語で記述されているソースプログラムを作成します。
例えばled00.cを作るという仮定で以下の説明にはいります。リストにあるファイルを作成してください。
このリストをコピー&ペーストするとよいでしょう。

リスト プログラムソースファイル"led00.c"

#include "7040S.H"           //IOポートアドレス定義
#include "sh_7045.h"         //基本関数群 sh_7045.hの先頭に説明がある

void msecwait(int msec)
/*msec間なにもしない時間稼ぎ関数*/
{
    int i,j;
    for (i=0;i<msec;i++) {
        for (j=0;j<9450;j++);    /*9450は実測によって求めた値*/
    }
}

int main(void)
{
    initLed();
    while(1){
        turnOnLed(0); /*LED0の点灯*/
        turnOnLed(1); /*LED1の点灯*/
        msecwait(500);
        turnOffLed(0); /*LED0の消灯*/
        turnOffLed(1); /*LED1の消灯*/
        msecwait(500);
    }
}

4.3 フラッシュメモリ書き込み形式ファイルの作成とROMライター書き込み操作
Cプログラムソースファイル「led00.c」が出来ましたら,次の手順で実行してください。

表4.1 フラッシュメモリ書き込み形式ファイルの作成とROMライター書き込み操作から実行までの手順

 

パソコン側

マイコンSH2/7045側

(1) もしハイパーターミナルなどCOMポートを使用しているソフトがパソコン上で動作している時はそれらのソフトを中止します。  
(2)  

<1>AKI-SH2/7045のマザーボード上の電源スイッチをOFFにします。
<2>AKI-SH2/7045のマザーボード上の状態選択スイッチをライト(Write)モードにします。ライトモードとはマイコンAKI-SH2/7045がパソコンからプログラムコードを受け取り,フラッシュメモリに書き込むモードのことです。
<3>AKI-SH2/7045のマザーボード上の電源スイッチをONにします。

(注意:SHは,電源スイッチONの瞬間に,状態選択スイッチの状態を検査しますので,必ず<1><2><3>の手順が必要です)

(3)  

「led00.c」を「shgcc.cmd」にドラッグ&ドロップする。

「h8write」を表示して止まるようであれば,シリアルケーブルの結線あるいはスイッチや電源が異常

「h8write
SH2/7045F or 7050F is ready!  2003/1/1 Yukio Mituiwa.」ここまで来て止まったように見えたらもう少しそのまま様子を見てください。転送データが表示されて転送が終ります。

この時,次のようなファイルができます。

ファイル 内容
led00.mot 転送形式の実行ファイル
led00.coff 実行ファイル
led00.map mapファイル

 

(4)   <1>転送が終了したら、AKI-SH2/7045のマザーボード上の電源スイッチをOFFにします。
<2>AKI-SH2/7045のマザーボード上の状態選択スイッチをラン(Run)モードにします。
(5) 必要ならパソコン側で「to_H8.ht」をダブルクリックしてターミナルアプリケーション「ハイパーターミナル」を立ち上げます。  
(6)   AKI-SH2/7045のマザーボード上の電源スイッチをONにすると転送したプログラムが作動します。

 

4.4 プログラムの実行
「led00.mot」がマイコンにフラッシュメモリ書き込みされて,実行します。正常に作業が終えていれば,マザーボード上の2つのLEDが点滅します。


 

参考1 コマンドスクリプトファイルshgcc.cmdの内容

shgcc.cmdの内容を参考リスト1に示します。

参考リスト1 コマンドスクリプトファイル「shgcc.cmd」

@echo off
echo sh2/7045 GCC compile-flashwrite(GCC)
echo Copyright 26Jan 2004 20Nov2003 coskx

rem *************** カスタマイズ領域 begin *******************
rem コンパイル作業に必要なパスの追加を行います。
 set mypath=%HOMEDRIVE%\cygwin\usr\local\sh\bin
rem コンパイラファイル名の設定を行います。
 set mycompiler=sh-hms-coff-gcc
rem motファイルコンバータファイル名の設定を行います。
 set myconverter=sh-hms-coff-objcopy
rem フラッシュメモリ書き込みに使用するプログラムを指定します。
 set myFMwriter=h8write.exe -7045
rem 正常にダウンロードが終了した場合はそのまま終了する
rem YES:そのまま終了する NO:そのまま終了せず停止
 set downloadquit=YES
rem *************** カスタマイズ領域  end  *******************

%~d1
cd %~p1
if %~x1==.mot goto FMWRITE
if %~x1==.MOT goto FMWRITE
path=%path%;%mypath%;%HOMEDRIVE%\cygwin\bin
if exist %~n1.coff rm %~n1.coff
echo %mycompiler%
%mycompiler% -m2 -T romsh7045.x -nostartfiles startup.s  %~nx1 %~nx2 %~nx3 %~nx4 %~nx5 -o %~n1.coff -O2 -Wl,-Map,%~n1.map
if not exist %~n1.coff goto TERMINAL
if exist %~n1.mot rm %~n1.mot
echo %myconverter%
%myconverter% -O srec %~n1.coff %~n1.mot
if not exist %~n1.mot goto TERMINAL
:FMWRITE
echo %myFMwriter%
%myFMwriter% %~n1.mot com1
if ERRORLEVEL==0 goto TERMINAL0
goto TERMINAL
:TERMINAL0
pause
if %downloadquit%==YES goto LEXIT
:TERMINAL
echo Pushing any key leads the exit.
pause >nul
:LEXIT
exit


参考2 スタートアップルーチン「startup.S」の内容

スタートアップルーチン「startup.S」

!*****************************************************************************
!   SH7045マイコンボード スタートアップルーチン
!                                          (C) 30Nov2003 coskx, A.YAMASHITA

!  このスタートアップで行なっていること
!  (1)スタックポインタの初期化
!  (2)マルチプレックスピンの初期化
!      (アドレスとポート共用のピンをアドレスとして使えるようにするなど)
!  (3)変数領域への初期値のコピー
!  (4)初期値を持たない変数領域のクリア(C言語の仕様にあわせる)
!  (5)main()の呼び出しと直後に無限ループの設置
!  このスタートアップルーチンファイルでのサービス関数
!  (1)void setIntMask(int mask) 割り込みマスクの設定関数
!  (2)int getIntMask(void) 割り込みマスクの読み出し関数
!  (3)__main() ダミー関数
!      これを定義しておくと予期しないライブラリ関数が付加されることがない
!*****************************************************************************
    .section    .text          ! スタートアップルーチンをROM領域に書き込み
    .global     _start         ! プログラム開始位置をエクスポート
    .extern     _dataRAM_begin
    .extern     _dataRAM_end
    .extern     _dataROM_begin
    .extern     _bss_begin
    .extern     _bss_end

_start:                                 ! プログラム開始位置
!-----------------------------------------------------------------------------
! スタックポインタ設定
!
! 汎用レジスタR0〜R15のうちR15がハードウェアスタックポインタに指定されている
! アドレスは 0xFFFFF000〜0xFFFFFFFF の内臓RAMを使用するため、
! STACK_ROOTは0x0を入れておく
!-----------------------------------------------------------------------------
    MOV.L    STACK_ROOT,    r15
!-----------------------------------------------------------------------------
! 各ポート初期化
! 秋月製のマイコンキットでは標準で外部RAMが実装されている.mode2にセットする
!-----------------------------------------------------------------------------
    MOV.L       BCR1,     r1         ! BCR1   -> r1
    MOV.W       D_BCR1,   r0         ! D_BCR1 -> r0
    MOV.W       r0,       @r1
    MOV.L       BCR2,     r1         ! BCR2   -> r1
    MOV.W       D_BCR2,   r0         ! D_BCR2 -> r0
    MOV.W       r0,       @r1
    MOV.L       WCR1,     r1         ! WCR1   -> r1
    MOV.W       D_WCR1,   r0         ! D_WCR1 -> r0
    MOV.W       r0,       @r1
    MOV.L       PACRH,    r1         ! PACRH   -> r1
    MOV.W       D_PACRH,  r0         ! D_PACRH -> r0
    MOV.W       r0,       @r1
    MOV.L       PACRL1,   r1         ! PACRL1   -> r1
    MOV.W       D_PACRL1, r0         ! D_PACRL1 -> r0
    MOV.W       r0,       @r1
    MOV.L       PBCR1,    r1         ! PBCR1   -> r1
    MOV.W       D_PBCR1,  r0         ! D_PBCR1 -> r0
    MOV.W       r0,       @r1
    MOV.L       PBCR2,    r1         ! PBCR2   -> r1
    MOV.W       D_PBCR2,  r0         ! D_PBCR2 -> r0
    MOV.W       r0,       @r1
    MOV.L       PCCR,     r1         ! PCCR   -> r1
    MOV.W       D_PCCR,   r0         ! D_PCCR -> r0
    MOV.W       r0,       @r1
    MOV.L       PDCRH1,   r1         ! PDCRH1   -> r1
    MOV.W       D_PDCRH1, r0         ! D_PDCRH1 -> r0
    MOV.W       r0,       @r1
    MOV.L       PDCRH2,   r1         ! PDCRH2   -> r1
    MOV.W       D_PDCRH2, r0         ! D_PDCRH2 -> r0
    MOV.W       r0,       @r1
    MOV.L       PDCRL,    r1         ! PDCRL   -> r1
    MOV.W       D_PDCRL,  r0         ! D_PDCRL -> r0
    MOV.W       r0,       @r1
    NOP

!-----------------------------------------------------------------------------
! ROMに格納されているデータ(変数など)をRAM領域にコピーする
!   RAM_BGN  : データを格納するRAM領域の開始アドレス
!   RAM_END : データを格納するRAM領域の終了アドレス
!   ROM_BGN : 実際にデータが書き込まれているROM領域の開始アドレス
!-----------------------------------------------------------------------------
    MOV.L       RAM_BGN,  r0        ! RAM_BGN -> r0
    MOV.L       RAM_END,  r1        ! RAM_END -> r1
    MOV.L       ROM_BGN,  r2        ! ROM_BGN -> r2
    BRA         LOOP11
    NOP
LOOP1:
    MOV.B       @r2,    r3          ! ROM領域からデータを取得
    MOV.B       r3,     @r0         ! RAM領域へデータをコピー
    ADD         #1,     r0          ! RAM領域を指すアドレスをインクリメント
    ADD         #1,     r2          ! ROM領域を指すアドレスをインクリメント
LOOP11:
    CMP/eq      r0,     r1          ! RAM_BGN == RAM_END ならば T=1
    BF          LOOP1               ! T!=1 ならば LOOP1へ
    NOP
END_LOOP1:

!-----------------------------------------------------------------------------!
!   初期化無しのグローバル変数を0で初期化
!   BSS_BGN  : 初期化無しのグローバル変数が格納されている開始アドレス
!   BSS_END : 初期化無しのグローバル変数が格納されている終了アドレス
!-----------------------------------------------------------------------------
    MOV.L       BSS_BGN,  r0        ! BSS_BGN -> r0
    MOV.L       BSS_END,  r1        ! BSS_END -> r1
    BRA         LOOP21
    NOP
LOOP2:
    MOV         #0,     r3          ! r3=0
    MOV.B       r3,     @r0         ! グローバル変数の領域に0を代入
    ADD         #1,     r0          ! 領域を指すアドレスをインクリメント
LOOP21:
    CMP/eq      r0,     r1          ! BSS_BGN == BSS_END ならば T=1
    BF          LOOP2               ! T!=1 ならば LOOP2へ
    NOP
END_LOOP2:

!-----------------------------------------------------------------------------
! main関数呼び出し
!-----------------------------------------------------------------------------
START_MAIN:                         ! mainをCALL
    MOV.L       MAIN_ADRS, r0       ! main関数のアドレス -> R0
    JSR         @r0                 ! mainへのジャンプサブルーチン
    OR          r0,     r0          ! JSR命令は遅延分岐のため
                                    ! (遅延分岐とはJSR直後の命令を先に実行)

! 万が一mainが終了して戻ってきても無限ループにして停止させる
FOREVER:
    BRA         FOREVER
    OR          r0,     r0

.align  4                               ! 4Byte = 32Bit固定
!----実行時に参照される初期値有りデータの領域(RAM領域)----
RAM_BGN:            .long   _dataRAM_begin    ! 開始アドレス
RAM_END:            .long   _dataRAM_end      ! 終了アドレス
!----リンク時に参照される初期値有りデータの初期値領域(ROM領域)----
ROM_BGN:            .long   _dataROM_begin    ! 開始アドレス
!----実行時に参照される初期値なしデータの領域(RAM領域)----
BSS_BGN:            .long   _bss_begin        ! 開始アドレス
BSS_END:            .long   _bss_end          ! 終了アドレス

STACK_ROOT:         .long   0x0               !スタックポインタの初期値
MAIN_ADRS:          .long   _main             !main関数

    .align  4
BCR1:    .long 0xffff8620
BCR2:    .long 0xffff8622
WCR1:    .long 0xffff8624
PACRH:   .long 0xffff8388
PACRL1:  .long 0xffff838c
PBCR1:   .long 0xffff8398
PBCR2:   .long 0xffff839a
PCCR:    .long 0xffff839c
PDCRH1:  .long 0xffff83a8
PDCRH2:  .long 0xffff83aa
PDCRL:   .long 0xffff83ac

D_BCR1:    .short 0x202f ! CS0/CS2/CS3 are 16bit-bus,CS is 32 bit
D_BCR2:    .short 0x5510 ! wait 1 idle
D_WCR1:    .short 0x0002 ! CS0 is 2 wait, CS1-3 are 0 wait
D_PACRH:   .short 0x5020 ! WRHH WRHL DRAK0 are enable
D_PACRL1:  .short 0x5550 ! CK -RD -WRH -WRL -CS[1..0] are enable
D_PBCR1:   .short 0x000a ! A21/A20 are enable
D_PBCR2:   .short 0xa005 ! A19/A18/A17/16 are enable
D_PCCR:    .short 0xffff ! A15-0 are enable
D_PDCRH1:  .short 0x5555 ! D31-24 are enable
D_PDCRH2:  .short 0x5555 ! D23-16 are enable
D_PDCRL:   .short 0xffff ! D15-0 are enable

! void setIntMask(int mask)   r4:mask r2:work r1:srreg
    .align  4
    .global _setIntMask
_setIntMask:
    stc      sr,r1          ! srreg = __sr__
    mov.l    MASKVALUER,r2
    and      r2,r1          ! srreg &= 0xffffff0f
    shll2    r4             ! mask <<= 2
    shll2    r4             ! mask <<= 2
    mov.l    MASKVALUE,r2
    and      r2,r4          ! mask &= 0x00f0
    or       r4,r1          ! srreg |= mask
    ldc      r1,sr
    rts 
    nop

! この関数はIntMaskを返します。
! int getIntMask(void)
    .align  4
    .global _getIntMask
_getIntMask:
    stc      sr,r0
    mov.l    MASKVALUE,r2
    and      r2,r0
    shlr2    r0
    shlr2    r0
    rts 
    nop

    .align  4
MASKVALUE:    .long  0x000000f0
MASKVALUER:   .long  0xffffff0f

! 次の関数はリンカがデフォルト関数群をつけるのを防ぎます
    .align  4
    .global ___main
___main:
    rts 
    nop

.end


付録1 coffファイルの逆アッセンブル

ファイルrasm.batをダウンロードして

「rasm.bat」に「xxxxxx.coff」をドラッグ&ドロップすればよい。

付録2 motファイルの逆アッセンブル

ファイルmotrasm.batをダウンロードして

「motrasm.bat」に「xxxxxx.mot」をドラッグ&ドロップすればよい。

付録3 Cファイルのアッセンブルファイル出力

ファイルCtoAsm.batをダウンロードして

「CtoAsm.bat」に「xxxxxx.c」をドラッグ&ドロップすればよい。
その際,インクルードファイルは,読み込めるようにしておくこと。