リロケータブルな書き方


    

【リロケータブルとは?】

リロケータブルというのは何のことでしょうか? これは大きなプログラム
を作る時に必要とされるもので、下記のような特徴を持ったプログラムの
作り方を言い、MPASMはこの機能を内蔵しています。

(1) プログラムを分割して作成し、アセンブルはそれぞれ独立に行う
  ことができる。そしてアセンブルした後に、それらの必要な部分を
  関連付けして「リンク」することができる。

(2) 分割して作成したプログラムを、各々メモリ内の場所を指定して
  配置することができる。

(3) 別モジュールにある変数を共有したり、別モジュールにジャンプしたり
  サブルーチンを使ったりすることが出来ます。
  このため、繰り返し使うサブルーチン群をまとめて「ライブラリ」として
  おき、何時でもリンクして使うことができる。

(4) アセンブラだけでなく、C言語や他の言語でできたプログラムも
  リンクして使うことができる。
  このリンクには「MPLINK]を使用する。



【リロケータブル用指示命令】

まずは、アセンブラ言語でリロケータブルなプログラムを作成するには
どうすれば良いのでしょうか?
リロケータブルにするためには下表の指示命令が重要な役割をします。
これらの指示命令により、アセンブラがリロケータブルであることを判断
してそれぞれに適する処理をします。

命令

機  能

書  式

CODE

実行プログラムの指定 [<name>] code [<address>]

UDATA

初期化無しのデータエリア確保。
RES命令でエリアを確保する。
[<name>] udata [<address>]

UDATA_OVR

初期化無しの変数エリアで複数モジュールから使用できる。
RES命令でエリアを確保する。
[<name>] udata_ovr [<address>]

UDATA_SHR

初期化無しの変数エリアで全バンクに共通とされる。RES命令でエリアを確保する。 [<name>] udata_shr [<address>]

IDATA

初期化付きのデータエリア確保をする。
RES,DB,DW命令でデータを定義する。
[<name>] idata [<address>]

CBLOCK

名前付きリストで変数エリアを確保する。
ENDCまでの複数行の記述ができる。
cblock [<expr>]

ENDC

  〃 endc

GLOBAL

他のモジュールでも使える変数であることを定義する。 global <label>[ ,<label>]

EXTERN

他のモジュールでGLOBAL定義されていることを宣言する。 extern <label>[ ,<label>]

BANKSEL

labelで指定されたデータが存在するバンクに切り替える banksel <label>

PAGESEL

labelで指定されたプログラムが存在するpageに切り替える pagesel <label>

【指示命令の詳細】

【CODE】 Begins executable code section
 1.形式
    [<name>]  CODE  [<address>]
 2.説明
   CODEセクションの開始宣言で、これ以下にプログラムを記述する。
   各CODEセクションは、「name」という名前を必ず付ける必要がある。
   「address」で絶対アドレスを指定することで、特定の番地からスタート
   するプログラムとすることが出来、割り込み処理など特定番地指定が
   必要なときに使う。
 3.使用例
  RESET   CODE  01FFH
       GOTO  START

  MAIN   CODE
       CLRW
       ・・・・
【UDATA】     Begins uninitialized data section
【UDATA_OVR】 Begins 0verlayed uninitialized data section
【UDATA_SHR】 Begins Shared uninitialized data Section
【IDATA】     Begins initialized data section
 1.形式
    [<name>]  UDATA  [<address>]  (他も同じ形式)
 2.説明
   データ定義セクションの開始を宣言し、これに続く命令でデータエリア
   を確保していく。
   実際のデータエリアの確保には、RES,DB,DW指示命令を使う。

   UDATA    :最も一般的な変数エリアの開始宣言で初期値は無し。
   UDATA_OVR :複数モジュールで共用される変数エリアの開始宣言
   UDATA_SHR :複数バンクに渡る共通変数エリアの開始宣言で、
   IDTA      :初期値付きの変数エリアの指定宣言。
        
 3.使用例
       IDATA ;実際の値が確保される
  VECTOR  DB   0
  WORDS   DW   '1234','5678'
  STRING  DB   "High",0
    
       UDATA         ;エリアの確保のみ
  INGAIN  RES   1
  OUTGAIN  RES   1
  
       UDATA_OVR       ;エリアの確保のみ
  TEMP1   RES   1
  TEMP2   RES   1
【CBLOCK】 Define a Block of Constants
【ENDC】   End an Automatic Constant Block
 1.形式
    cblock [<expr>]
     -----
     ----
     endc


 2.説明
   変数エリアを名前でまとめて確保する時に使用する。
   <expr>を指定することで、絶対アドレスを指定して確保する
   こともできる。

 3.使用例
   CBLOCK  020H     ;絶対アドレス20H番地から確保
     INGAIN,OUTGAIN   ;連続して名前付きでエリア確保
     VECTOR       ;
     TEMP1,TEMP2,TEMP3
   ENDC
【GLOBAL】 Export a defined label
 1.形式
   global   <label>[ ,<label>]
 2.説明
   別のモジュール間でラベルを指定してアクセスできるように
   するための外部ラベル定義。
   GLOBALと宣言されたラベルは他のモジュールからも指定できる。
   逆に使う方は、EXTERNで他のモジュールにあるラベルであることを
   宣言しておくことが必要。
 3.使用例
  FILTER
       GLOBAL FILTER
       CLRW
       ・・・・・
       RETURN

       UDATA
  INGAIN  RES  1
  OUTGAIN  RES  1
       GLOBAL INGAIN,OUTGAIN

【EXTERN】 Declares an extenal label
 1.形式
    extern  <label>[ ,<label>]
 2.説明
   別のモジュール間でラベルを指定してアクセスできるように
   するための外部ラベル宣言。
   EXTERNで他のモジュールにあるラベルであることを宣言し、
   別モジュールでGLOBAL宣言されたラベルを使う。
 3.使用例
       EXTERN INGAIN,OUTGAIN,FILTER
       
       CODE
       ・・・・
       MOVWF  INGAIN
       CALL  FILTER

【BANKSEL】 Generate RAM bank Selecting code
【PAGESEL】 Generate ROM page selecting code
 1.形式
    banksel  <label>
    pagesel  <label>
 2.説明
   リロケータブルでバンクが特定できない変数や、実際に配置される
   ページが特定できないプログラムモジュールに対して、アセンブル
   時に適当なバンク指定やページ指定をするための命令を挿入する。
 3.使用例
  VAL1  EQU 010H  ;BANK0に実在する
  VAL2  EQU 030H  ;BANK2に実在する
       
      CODE
      ・・・・
      BANKSEL VAR1
      MOVWF  VAR1
      PAGESEL SUBPRO ;SUBPROはどこのページか不明
      CALL   SUBPRO
      ・・・・


【リロケータブルなソースの構造】

では実際に上記の指示命令を使って、リロケータブルなソースファイル
を作成する方法です。

(1)単一なバンクとページで良いときのソースファイル
  一つのバンクやページの中でプログラムが完了するときのリロケー
  タブルなプログラムは下記のような構造のソースファイルとします。

  <モジュール1> 定義モジュール

      UDATA          ;変数エリア定義 
 INGAIN  RES   1        ;エリア確保
 OUTGAIN  RES   1
      GLOBAL INGAIN,OUTGAIN  ;グローバル変数定義

      CODE           ;プログラム部指定
 FILTER
      GLOBAL FILTER      ;グローバル定義
      ・・・・・・
      ・・・・・・
      END

  <モジュール2> 実行モジュール

      EXTERN INGAIN,OUTGAIN,FILTER ;外部変数定義

      UDATA           ;変数エリア定義
 READ   RES   1         ;変数エリア確保

      CODE            ;プログラム部指定
      ・・・・
      ・・・・
      MOVLW  GAIN1
      MOVWF  INGAIN      ;外部変数も通常と
      MOVLW  GAIN2       ;同じ扱い
      MOVWF  OUTGAIN
      MOVF   READ,W
      CALL   FILTER      ;外部プログラムも同じ
      ・・・・
      ・・・・
      END

(2)複数バンクやページを使うとき
  データやプログラムが複数のバンク、ページを使うときには、どのバンク
  かページかを指定する必要がありますが、リンクするまでは、どのバンク
  、ページに存在するかは不明なままとなってしまいます。
  このような時には、下記のように、BANKSELやPAGSEL指示命令を使って
  ソースファイルを作成します。

 <モジュール3> 複数バンク、ページのモジュール
 
      LIST   P=16C73A ;通常と同じ定義方法で可
 #INCLUDE "PIC16C73A.INC"

 VAR1   EQU   010H    ;Bank0とする
 VAR2   EQU   030H    ;Bank1とする
 
      ・・・・

      CODE        ;プログラムエリア開始
      MOVLW  IVAL    ;初期値定数ロード
      BANKSEL VAR1    ;Bankを指定
      MOVWF  VAR1    ;変数にセット
      BANKSEL VAR2    ;Bankを指定
      MOVWF  VAR2
  
      PAGESEL SUBPRO   ;Pageを指定
      CALL   SUBPRO
      ・・・・
      ・・・・
 (別のバンクから開始しているとする)
 SUBPRO  CLRW
      ・・・・       ;
      ・・・・       
;一つのサブルーチンが
      RETURN      
;ページをまたがってはならない
    

【リロケータブルなソースの実例1】

下記はMPASMに実例として紹介されているリロケータブルなプログラム
の実際で、1バイトの掛け算のサブルーチンをライブラリとして使える
ようにした例です。
このライブラリは、常にソースとしてモジュールを使う側のモジュールと
一緒にアセンブルする必要は無く、オブジェクトファイルとしておいて、
使う側のモジュールのオブジェクトを作った後に、リンカで一緒にリンク
して使うことができます。
このようなリロケータブルなライブラリとしておくことで、ライブラリを
色々なプログラムで共用して使うことができます。
例えば、液晶表示や他の周辺機器のサブルーチンをリロケータブル
なサブルーチンとしておけば、どのプログラムにも共通にメモリ配置も
気にすること無く使うことが出来ます。

<リロケータブルプログラム例>
 《メインモジュール》
     LIST  P=16C54
     #INCLUDE "PIC16C5x.INC"

     EXTERN  MULCND,MULPLR,H_BYTE,L_BYTE
     EXTERN  MPY

     CODE
 START  CLRW
     OPTION
 MAIN  MOVF   PORTB,W
     MOVWF   MULPLR
     MOVF   PORTB,W
     MOVWF   MULCND
 CALL_M CALL   MPY
     GOTO   MAIN
 
 RESET  CODE    01FFH
     GOTO   START
     END

 《ライブラリモジュール》
     LIST  P=16C54
     #INCLUDE "PIC16C5x.INC"
     
     UDATA
 MULCND RES   1
 MULPLR RES   1
 H_BYTE RES   1
 L_BYTE RES   1
 COUNT  RES   1
     GLOBAL  MULCND,MULPLR,H_BYTE,L_BYTE
 
     CODE
 MPY
     GLOBAL  MPY

     CLRF   H_BYTE
     CLRF   L_BYTE
     MOVLW  8
     MOVWF  COUNT
     ・・・・・
     ・・・・
     RETLW  0
     END


【リロケータブルなソースの実例2】

下記は、PIC活用例にある「周波数カウンタ」を例にして、リロケー
タブルな形式で作成したものです。

全体は下記の3つのモジュールで構成されています。

(1) ベクター定義モジュール(cntvct.asm)
  リセットと割り込みのエントリーを指定する絶対番地にGOTO文
  だけで出来ているモジュールです。
(2) メインモジュール(cntmain.asm)
  カウンタとしての機能を実現しているモジュールです。
(3) ライブラリモジュール(cntlib.asm)
  液晶表示器の制御サブルーチンと、タイマサブルーチンの
  ライブラリモジュールです。
(4) これに標準リンクファイルが付きます。(16F84.lkr)

以上の4つのファイルをProject "newcnt.prj"として登録しています。
これでリンクした結果は、"newcnt.hex"として出力されます。
下記で上記3個のソースファイルをダウンロード出来ます。


  ★ リロケータブル構成のカウンタソースファイル





  次のページへ    目次ページへ