Applilet EZ PL for RL78 V1.0J, V2.00J を試してみました。
デジタル回路版電子ブロックという感じで興味深いツールと思いましたが、少々使いづらい点もあったので改善要望として挙げておきます。
> 本ツールは評価版です。本ツールに関するテクニカルサポートは受け付けておりません。
と明記されていることは理解しており、返答等を求めているものではありません。
・コードがサイズ的に冗長
Applilet EZ PL for RL78 V2.0 + CC-RL V1.04.00 を使用し、マイクロコントローラ設定を
とし、
上記の内容のプロジェクトで「生成」を行ったところ、
コンパイルを開始します。 ---------- Pass1 ---------- ---------- Pass2 ---------- src\74hc.c(284):W0520177:変数 "ucEnable" は宣言されましたが参照されていません。 W0561120:Section address is not assigned to ".text" F0563100:Section address overflow out of range : ".text" The evaluation period has expired. Renesas Optimizing Linker Abort 2017-05-02 16:51:14 C:\Users\fujita\My Documents\Applilet EZ PL for RL78\Project\test2\makeprj.bat 2017-05-02 16:51:14 1105:Build processing error. コンパイルを中断しました。
とエラーが出力され、生成に失敗しました。
ROM 容量不足のようなので、マイクロコントローラ設定の「デバイス」を、ROM 容量が 2kB の R5F10Y16ASP から 4kB の R5F10Y17ASP に変更して再度「生成」を行ったところ
コンパイルを開始します。 ---------- Pass1 ---------- ---------- Pass2 ---------- ---------- Pass3 ---------- コンパイルが終了しました。 使用ROMサイズ 2600byte
成功しました。
使用 ROM サイズが 2600byte ということで、R5F10Y16ASP の ROM には収まらなかったようです。
Applilet EZ PL for RL78 では R5F10Y16ASP をサポートしていますが、上記の例は内容的にも単純なものであり、この程度のものは動作して欲しいところです。
生成時に作成される .map ファイル等を見てみると、サイズが数バイトという関数が複数生成されており、コードサイズ増大の一因となっているようです。
例:
_MOV1_: D7 ret _NOT1_: 91 dec a F6 clrw ax 61E8 skz E6 onew ax 60 mov a, x D7 ret _ByteMemGet: 14 movw de, ax 62 mov a, c 318E shrw ax, 8+0x00000 05 addw ax, de 14 movw de, ax 89 mov a, [de] D7 ret _ByteMemSet: 14 movw de, ax 62 mov a, c 318E shrw ax, 8+0x00000 05 addw ax, de 14 movw de, ax 63 mov a, b 99 mov [de], a D7 ret _Port_Set: C1 push ax C7 push hl 60 mov a, x 340100 movw de, #0x0001 73 mov b, a D3 cmp0 b DD00 bz $.BB@LABEL@8_2 .BB@LABEL@8_1: 15 movw ax, de 01 addw ax, ax 14 movw de, ax 93 dec b DF00 bnz $.BB@LABEL@8_1 .BB@LABEL@8_2: 64 mov a, e 77 mov h, a 8803 mov a, [sp+0x03] 70 mov x, a 53FF mov b, #0xFF 63 mov a, b 14 movw de, ax 92 dec c 89 mov a, [de] 70 mov x, a DF00 bnz $.BB@LABEL@8_4 .BB@LABEL@8_3: 67 mov a, h 6160 or x, a EF00 br $.BB@LABEL@8_5 .BB@LABEL@8_4: 67 mov a, h 7CFF xor a, #0xFF 6150 and x, a .BB@LABEL@8_5: 60 mov a, x 9800 mov [sp+0x00], a .BB@LABEL@8_6: 8803 mov a, [sp+0x03] 70 mov x, a 63 mov a, b 14 movw de, ax 8800 mov a, [sp+0x00] 99 mov [de], a 1004 addw sp, #0x04 D7 ret _Port_Get: C1 push ax 8801 mov a, [sp+0x01] 70 mov x, a 51FF mov a, #0xFF 14 movw de, ax 89 mov a, [de] 318E shrw ax, 8+0x00000 14 movw de, ax 8800 mov a, [sp+0x00] 73 mov b, a D3 cmp0 b DD00 bz $.BB@LABEL@9_2 .BB@LABEL@9_1: 15 movw ax, de 311E shrw ax, 0x01 14 movw de, ax 93 dec b DF00 bnz $.BB@LABEL@9_1 .BB@LABEL@9_2: 64 mov a, e 5C01 and a, #0x01 C6 pop hl D7 ret _NOTF: 91 dec a F6 clrw ax 61E8 skz E6 onew ax 60 mov a, x D7 ret _ANDF: 91 dec a E1 oneb a 61E8 skz F1 clrb a 90 dec x E0 oneb x 61E8 skz F0 clrb x 6150 and x, a 60 mov a, x D7 ret _ORF: 91 dec a E1 oneb a 61E8 skz F1 clrb a 90 dec x E0 oneb x 61E8 skz F0 clrb x 6160 or x, a 60 mov a, x D7 ret _XORF: 6148 cmp a, x E1 oneb a 61F8 sknz F1 clrb a D7 ret
ソースコードを参照すると
UCHAR MOV1_( UCHAR Fin ) { return Fin; } UCHAR NOT1_( UCHAR Fin ) { return (Fin == HIGH) ? LOW : HIGH; } UCHAR ByteMemGet( UCHAR* memp, UCHAR count ) { UCHAR work; work = (UCHAR)(*(memp + count)); return(work); } void ByteMemSet( UCHAR* memp, UCHAR count, UCHAR value ) { UCHAR* work; work = memp + count; *work = value; } void Port_Set( UCHAR Port, UCHAR TermNum, UCHAR Val ) { volatile UCHAR *ucp_port; UCHAR ucport; UCHAR ucset = Val; ucp_port = &P0; ucp_port += Port; ucport = *ucp_port; ucset = 1; ucset <<= TermNum; if (Val == HIGH){ ucport |= ucset; }else{ ucport &= ~ucset; } *ucp_port = ucport; } UCHAR Port_Get( UCHAR Port, UCHAR TermNum ) { volatile UCHAR *ucp_port; UCHAR ucport; UCHAR ucret; ucp_port = &P0; ucp_port += Port; ucport = *ucp_port; ucret = (ucport >> TermNum) & 0x01; return(ucret); } UCHAR NOTF( UCHAR in ) { return (in == HIGH)? LOW : HIGH; } UCHAR ANDF( UCHAR in1, UCHAR in2 ) { if((in1 == HIGH) && (in2 == HIGH)) return HIGH; else return LOW; } UCHAR ORF( UCHAR in1, UCHAR in2 ) { if((in1 == HIGH) || (in2 == HIGH)) return HIGH; else return LOW; } UCHAR XORF( UCHAR in1, UCHAR in2 ) { if(in1 != in2) return HIGH; else return LOW; }
短い関数が実際に用意されていますが、この程度の単純な関数であれば呼び出しに要するコードの方がサイズでは問題となり得るのでマクロ等で実装されたら良いのではないかと思います。
#define MOV1_( Fin ) (Fin) #define NOT1_( Fin ) (HIGH - (Fin)) #define ByteMemGet(memp, count) (*((memp) + (count))) #define ByteMemSet( memp, count, value ) do {*((memp) + (count)) = value;} while (0) #define Port_Set( Port, TermNum, Val ) do { if (Val) {(&P0)[(Port)] |= (1 << (TermNum));} else {(&P0)[(Port)] &= ~(1 << (TermNum));}} while (0) #define Port_Get( Port, TermNum ) (((&P0)[(Port)] >> (TermNum)) & 0x01) #define NOTF( in ) ((in) ^ 1) #define ANDF( in1, in2 ) ((in1) & (in2)) #define ORF( in1, in2 ) ((in1) | (in2)) #define XORF( in1, in2 ) ((in1) ^ (in2))
他、数バイトのサイズの関数でなくとも、初期化を行う XXX_Init() や XXX_Initialize() といった関数は一度しか呼ばれないものなのでこういったものもマクロ(若しくはインライン関数)化すると call ~ ret 文のコードサイズの削減が期待できます。
他、.map ファイルを見てみると
SECTION=.RLIB FILE=memset 00000915 00000922 e _memset 00000915 0 none ,g 2 FILE=_COM_lmul 00000923 0000096b 49 __COM_lmul 00000923 0 none ,g 3 FILE=_COM_ucdiv 0000096c 00000983 18 __COM_ucdiv 0000096c 0 none ,g 1 FILE=_COM_ucrem 00000984 00000998 15 __COM_ucrem 00000984 0 none ,g 1 FILE=_COM_uldiv 00000999 000009e9 51 __COM_uldiv 00000999 0 none ,g 3 FILE=_COM_ulrem 000009ea 00000a36 4d __COM_ulrem 000009ea 0 none ,g 3
標準ライブラリのコードサイズも案外あるようです。 memset() や乗除算は仕方がないとして、剰余は再考の余地がありそうです。 例として、
UCHAR PWM_Calc_Duty( UCHAR regTDR00L ) { ULONG ulwork1 = 0; UCHAR ucwork2 = 0; UCHAR ucwork3 = 0; ulwork1 = regTDR00L; ulwork1 = (ulwork1 + 1) * tblgPWM[ucgPWM_Cnt].SetDuty; ucwork2 = (UCHAR)(ulwork1 % 100); ucwork3 = (UCHAR)(ulwork1 / 100); if (ucwork2 >= 50) ucwork3 ++; if (ucwork3 == 0) ucwork3 ++; return ucwork3; }
の中の
ucwork2 = (UCHAR)(ulwork1 % 100); ucwork3 = (UCHAR)(ulwork1 / 100);
の部分は、
ucwork3 = (UCHAR)(ulwork1 / 100); ucwork2 = ulwork1 - ucwork3 * 100;
と変更することで剰余演算を無くすことができます。
他、例えば
UCHAR IC_74HC138_Evaluate( UCHAR G1_in, UCHAR G2A_in, UCHAR G2B_in, UCHAR A_in, UCHAR B_in, UCHAR C_in ) { UCHAR ucRet = 0b11111111; UCHAR ucEnable = LOW; if(G1_in == HIGH){ if ((G2A_in | G2B_in)==0){ ucRet = 0; switch(A_in + (B_in << 1) + (C_in << 2)){ case 0: ucRet = 0b11111110; break; case 1: ucRet = 0b11111101; break; case 2: ucRet = 0b11111011; break; case 3: ucRet = 0b11110111; break; case 4: ucRet = 0b11101111; break; case 5: ucRet = 0b11011111; break; case 6: ucRet = 0b10111111; break; case 7: ucRet = 0b01111111; break; default: ucRet = 0b11111111; } } } return ucRet; }
は
UCHAR IC_74HC138_Evaluate( UCHAR G1_in, UCHAR G2A_in, UCHAR G2B_in, UCHAR A_in, UCHAR B_in, UCHAR C_in ) { UCHAR ucRet = 0b00000000; if(G1_in && !G2A_in && !G2B_in){ ucRet = 0b00000001; if (A_in) { ucRet <<= 1; } if (B_in) { ucRet <<= 2; } if (C_in) { ucRet <<= 4; } } return ~ucRet; }
の様に書き換えるとコードサイズの縮小ができます(80バイト → 40バイト)。
以上のようなコードサイズの縮小が可能な部分は散見されるので、全体を見直しをしていただきたいと思います。先に挙げた 2600バイトとなった例ですが、半分の 1300バイト程度には縮小できる印象です。