tcl言語とC言語の連携
tcl言語でC言語の関数を使う
tcl言語はプラットフォームを問わず幅広く使われている言語です。今回は、
tcl言語は高水準のインタープリタなので、
ここではC言語で簡単な演算を行う関数を作成し、
tcl言語から呼び出すC言語関数
全ての引数の数と累積加算の戻り値を返すC言語側の関数は、
tcl言語から呼び出されるC言語で書かれた自作共有ライブラリ内での関数の戻り値は、
初期化関数名は以下となります。
int [任意の名称]_Init(Tcl_Interp *interp)
任意の名称は必ずしも共有ライブラリ名と一致させる必要はなく、
tcl言語から呼び出されるC言語の関数の仕様は、
01:  #include <tcl.h>
02:  
03:  int CalcCmd(ClientData clientdata, Tcl_Interp *interp, int argc, char **argv);
04:  
05:  int Calc_Init(Tcl_Interp *interp) {
06:  Tcl_CreateCommand(interp, "calc", CalcCmd, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
07:      Tcl_PkgProvide(interp, "calc", "1.1");
08:      return TCL_OK;
09:  }
10:  
11:  int CalcCmd(ClientData clientdata, Tcl_Interp *interp, int argc, char **argv) {
12:      int    data, i, n, error;
13:  
14:      if(argc <= 2) {
15:          interp->result = "Usage: calc num num ...";
16:          return TCL_ERROR;
17:      }
18:      data = 0;
19:      for(i = 1;i < argc;i++) {
20:          error = Tcl_GetInt(interp, argv[i], &n);
21:          if(error != TCL_OK) return error;
22:          data += n;
23:      }
24:      sprintf(interp->result, "%d", data);
25:      return TCL_OK;
26:  }
tcl言語から呼び出されるC言語の関数を記述する場合は、
また、
自作共有ライブラリ内での初期化関数やtcl言語から呼び出されるC言語の関数とtcl言語インタープリタ処理系とのインターフェースは、
初期化関数においては、
tcl言語から呼び出されるC言語の関数の生成は、
tcl言語から呼び出されるC言語の関数の登録は、
tcl言語から呼び出されるC言語の関数であるCalcCmd関数
tcl言語から呼び出されるC言語の関数内で数値などの引数の実体を取得するには、
C言語での戻り値は TCL_
Lua言語からのハードウェアアクセス
C言語での記述
前回、
001: #include <sys/types.h>
002: #include <sys/stat.h>
003: #include <fcntl.h>
004: #include <unistd.h>
005: #include <stdlib.h>
006: #include <stdio.h>
007: #include <string.h>
008: #include <sys/mman.h>
009: #include <asm/page.h>
010: 
011: #include <lua.h>
012: #include <lualib.h>
013: #include <lauxlib.h>
014: 
015: static void MemoryByteWrite(lua_State *List, unsigned int addr, unsigned int data);
016: static unsigned int MemoryByteRead(lua_State *List, unsigned int addr);
017: static void MemoryWordWrite(lua_State *List, unsigned int addr, unsigned int data);
018: static unsigned int MemoryWordRead(lua_State *List, unsigned int addr);
019: static void MemoryLongWrite(lua_State *List, unsigned int addr, unsigned int data);
020: static unsigned int MemoryLongRead(lua_State *List, unsigned int addr);
021: 
022: static void MemoryByteWrite(lua_State *List, unsigned int addr, unsigned int data) {
023:     volatile unsigned char    *mmaped;
024:     int        fd, i;
025:     unsigned int    pageaddr, offsetmask, pagemask;
026: 
027:     fd = open("/dev/mem",O_RDWR);
028:     if(fd < 0) {
029:         lua_pushstring(List, "Cannot open /dev/mem");
030:         lua_error(List);
031:     }
032:     offsetmask = PAGE_SIZE;
033:     offsetmask--;
034:     pagemask = ~offsetmask;
035:     pageaddr = addr & pagemask;
036:        mmaped = (volatile unsigned char*)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
037:     close(fd);
038:     if(mmaped == MAP_FAILED) {
039:         lua_pushstring(List, "Cannot mmap");
040:         lua_error(List);
041:     }
042:     mmaped[addr & offsetmask] = data;
043:     munmap((char*)mmaped, PAGE_SIZE);
044: }
045: 
046: static unsigned int MemoryByteRead(lua_State *List, unsigned int addr) {
047:     volatile unsigned char    *mmaped;
048:     int        fd, i;
049:     unsigned int    pageaddr, offsetmask, pagemask, data;
050: 
051:     fd = open("/dev/mem",O_RDWR);
052:     if(fd < 0) {
053:         lua_pushstring(List, "Cannot open /dev/mem");
054:         lua_error(List);
055:     }
056:     offsetmask = PAGE_SIZE;
057:     offsetmask--;
058:     pagemask = ~offsetmask;
059:     pageaddr = addr & pagemask;
060:     mmaped = (volatile unsigned char*)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
061:     close(fd);
062:     if(mmaped == MAP_FAILED) {
063:         lua_pushstring(List, "Cannot mmap");
064:         lua_error(List);
065:     }
066:     data = mmaped[addr & offsetmask] & 0xff;
067:     munmap((char*)mmaped, PAGE_SIZE);
068:     return data;
069: }
070: 
071: static void MemoryWordWrite(lua_State *List, unsigned int addr, unsigned int data) {
072:     volatile unsigned short    *mmaped;
073:     int        fd, i;
074:     unsigned int    pageaddr, offsetmask, pagemask;
075: 
076:     fd = open("/dev/mem",O_RDWR);
077:     if(fd < 0) {
078:         lua_pushstring(List, "Cannot open /dev/mem");
079:         lua_error(List);
080:     }
081:     offsetmask = PAGE_SIZE;
082:     offsetmask--;
083:     pagemask = ~offsetmask;
084:     pageaddr = addr & pagemask;
085:     mmaped = (volatile unsigned short *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
086:     close(fd);
087:     if(mmaped == MAP_FAILED) {
088:         lua_pushstring(List, "Cannot mmap");
089:         lua_error(List);
090:     }
091:     mmaped[(addr & offsetmask) >> 1] = data;
092:     munmap((char*)mmaped, PAGE_SIZE);
093: }
094: 
095: static unsigned int MemoryWordRead(lua_State *List, unsigned int addr) {
096:     volatile unsigned short    *mmaped;
097:     int        fd, i;
098:     unsigned int    pageaddr, offsetmask, pagemask, data;
099: 
100:     fd = open("/dev/mem",O_RDWR);
101:     if(fd < 0) {
102:         lua_pushstring(List, "Cannot open /dev/mem");
103:         lua_error(List);
104:     }
105:     offsetmask = PAGE_SIZE;
106:     offsetmask--;
107:     pagemask = ~offsetmask;
108:     pageaddr = addr & pagemask;
109:     mmaped = (volatile unsigned short *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
110:     close(fd);
111:     if(mmaped == MAP_FAILED) {
112:         lua_pushstring(List, "Cannot mmap");
113:         lua_error(List);
114:     }
115:     data = mmaped[(addr & offsetmask) >> 1] & 0xffff;
116:     munmap((char*)mmaped, PAGE_SIZE);
117:     return data;
118: }
119: 
120: static void MemoryLongWrite(lua_State *List, unsigned int addr, unsigned int data) {
121:     volatile unsigned int    *mmaped;
122:     int        fd, i;
123:     unsigned int    pageaddr, offsetmask, pagemask;
124: 
125:     fd = open("/dev/mem",O_RDWR);
126:     if(fd < 0) {
127:         lua_pushstring(List, "Cannot open /dev/mem");
128:         lua_error(List);
129:     }
130:     offsetmask = PAGE_SIZE;
131:     offsetmask--;
132:     pagemask = ~offsetmask;
133:     pageaddr = addr & pagemask;
134:     mmaped = (volatile unsigned int *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
135:     close(fd);
136:     if(mmaped == MAP_FAILED) {
137:         lua_pushstring(List, "Cannot mmap");
138:         lua_error(List);
139:     }
140:     mmaped[(addr & offsetmask) >> 2] = data;
141:     munmap((char*)mmaped, PAGE_SIZE);
142: }
143: 
144: static unsigned int MemoryLongRead(lua_State *List, unsigned int addr) {
145:     volatile unsigned int    *mmaped;
146:     int        fd, i;
147:     unsigned int    pageaddr, offsetmask, pagemask, data;
148: 
149:     fd = open("/dev/mem",O_RDWR);
150:     if(fd < 0) {
151:         lua_pushstring(List, "Cannot open /dev/mem");
152:         lua_error(List);
153:     }
154:     offsetmask = PAGE_SIZE;
155:     offsetmask--;
156:     pagemask = ~offsetmask;
157:     pageaddr = addr & pagemask;
158:     mmaped = (volatile unsigned int *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
159:     close(fd);
160:     if(mmaped == MAP_FAILED) {
161:         lua_pushstring(List, "Cannot mmap");
162:         lua_error(List);
163:     }
164:     data = mmaped[(addr & offsetmask) >> 2];
165:     munmap((char*)mmaped, PAGE_SIZE);
166:     return data;
167: }
168: 
169: int memory(lua_State *List) {
170:     lua_Number    addr, data;
171:     char        *type;
172:     int        argc;
173:     void        (*writefunc)(lua_State *, unsigned int, unsigned int);
174:     unsigned int    (*readfunc)(lua_State *, unsigned int);
175: 
176:     argc = lua_gettop(List);
177:     if(argc < 2 || argc > 3) {
178:         lua_pushstring(List, "Usage: memory byte|word|long address ?data?");
179:         lua_error(List);
180:     }
181:     type = lua_tostring(List, 1);
182:     if(strcmp(type, "byte") == 0) {
183:         writefunc = MemoryByteWrite;
184:         readfunc = MemoryByteRead;
185:     } else if(strcmp(type, "word") == 0) {
186:         writefunc = MemoryWordWrite;
187:         readfunc = MemoryWordRead;
188:     } else if(strcmp(type, "long") == 0) {
189:         writefunc = MemoryLongWrite;
190:         readfunc = MemoryLongRead;
191:     } else {
192:         lua_pushstring(List, "Usage: memory byte|word|long address ?data?");
193:         lua_error(List);
194:     }
195:     addr = lua_tonumber(List, 2);
196:     if(argc == 3) {
197:         data = lua_tonumber(List, 3);
198:         (*writefunc)(List, (unsigned int)addr, (unsigned int)data);
199:     }
200:     data = (lua_Number)((*readfunc)(List, (unsigned int)addr));
201:     lua_pushnumber(List, data);
202:     return 1;
203: }
リスト2の22~167行目まではハードウェアアクセスを行う関数で、
SHプロセッサではメモリアクセスが1バイトアクセス、
外部から呼び出させる関数はmemory関数で、
第1引数はメモリアクセスのサイズを文字列で受け取り
第2引数は物理メモリアドレスでlua_
もし、
コンパイルと実行
共有ライブラリのコンパイルはPC上で行い、
# sh3-linux-gcc -shared -Wl,-soname,memory.so -o memory.so memory.c
できあがったmemory.
# lua
Lua 5.1.4  Copyright (C) 1994-2008 Lua.org, PUC-Rio
> func = package.loadlib("./memory.so", "memory")
> func("byte",0xa4000136,0x36)
^C
#
上記の例では、
tcl言語からのハードウェアアクセス
C言語での記述
前半でtcl言語からC言語の関数を呼び出す方法について説明しましたので、
ハードウェアアクセスを行うtcl言語から呼び出されるC言語の関数は、
001: #include <sys/types.h>
002: #include <sys/stat.h>
003: #include <fcntl.h>
004: #include <unistd.h>
005: #include <stdlib.h>
006: #include <stdio.h>
007: #include <string.h>
008: #include <sys/mman.h>
009: #include <asm/page.h>
010: #include <tcl.h>
011: 
012: static int MemoryByteWrite(Tcl_Interp *interp, unsigned int addr, unsigned int data);
013: static int MemoryByteRead(Tcl_Interp *interp, unsigned int addr, unsigned int *data);
014: static int MemoryWordWrite(Tcl_Interp *interp, unsigned int addr, unsigned int data);
015: static int MemoryWordRead(Tcl_Interp *interp, unsigned int addr, unsigned int *data);
016: static int MemoryLongWrite(Tcl_Interp *interp, unsigned int addr, unsigned int data);
017: static int MemoryLongRead(Tcl_Interp *interp, unsigned int addr, unsigned int *data);
018: static int MemoryCmd(ClientData clientdata, Tcl_Interp *interp, int argc, char **argv);
019: 
020: static int MemoryByteWrite(Tcl_Interp *interp, unsigned int addr, unsigned int data) {
021:     volatile unsigned char    *mmaped;
022:     int        fd, i;
023:     unsigned int    pageaddr, offsetmask, pagemask;
024: 
025:     fd = open("/dev/mem",O_RDWR);
026:     if(fd < 0) {
027:         interp->result = "Cannot open /dev/mem";
028:         return TCL_ERROR;
029:     }
030:     offsetmask = PAGE_SIZE;
031:     offsetmask--;
032:     pagemask = ~offsetmask;
033:     pageaddr = addr & pagemask;
034:     mmaped = (volatile unsigned char*)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
035:     close(fd);
036:     if(mmaped == MAP_FAILED) {
037:         interp->result = "Cannot mmap";
038:         return TCL_ERROR;
039:     }
040:     mmaped[addr & offsetmask] = data;
041:     munmap((char*)mmaped, PAGE_SIZE);
042:     return TCL_OK;
043: }
044: 
045: static int MemoryByteRead(Tcl_Interp *interp, unsigned int addr, unsigned int *data) {
046:     volatile unsigned char    *mmaped;
047:     int        fd, i;
048:     unsigned int    pageaddr, offsetmask, pagemask;
049: 
050:     fd = open("/dev/mem",O_RDWR);
051:     if(fd < 0) {
052:         interp->result = "Cannot open /dev/mem";
053:         return TCL_ERROR;
054:     }
055:     offsetmask = PAGE_SIZE;
056:     offsetmask--;
057:     pagemask = ~offsetmask;
058:     pageaddr = addr & pagemask;
059:     mmaped = (volatile unsigned char*)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
060:     close(fd);
061:     if(mmaped == MAP_FAILED) {
062:         interp->result = "Cannot mmap";
063:         return TCL_ERROR;
064:     }
065:     *data = mmaped[addr & offsetmask] & 0xff;
066:     munmap((char*)mmaped, PAGE_SIZE);
067:     return TCL_OK;
068: }
069: 
070: static int MemoryWordWrite(Tcl_Interp *interp, unsigned int addr, unsigned int data) {
071:     volatile unsigned short    *mmaped;
072:     int        fd, i;
073:     unsigned int    pageaddr, offsetmask, pagemask;
074: 
075:     fd = open("/dev/mem",O_RDWR);
076:     if(fd < 0) {
077:         interp->result = "Cannot open /dev/mem";
078:         return TCL_ERROR;
079:     }
080:     offsetmask = PAGE_SIZE;
081:     offsetmask--;
 82     pagemask = ~offsetmask;
083:     pageaddr = addr & pagemask;
084:     mmaped = (volatile unsigned short *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
085:     close(fd);
086:     if(mmaped == MAP_FAILED) {
087:         interp->result = "Cannot mmap";
088:         return TCL_ERROR;
089:     }
090:     mmaped[(addr & offsetmask) >> 1] = data;
091:     munmap((char*)mmaped, PAGE_SIZE);
092:     return TCL_OK;
093: }
094: 
095: static int MemoryWordRead(Tcl_Interp *interp, unsigned int addr, unsigned int *data) {
096:     volatile unsigned short    *mmaped;
097:     int        fd, i;
098:     unsigned int    pageaddr, offsetmask, pagemask;
099: 
100:     fd = open("/dev/mem",O_RDWR);
101:     if(fd < 0) {
102:         interp->result = "Cannot open /dev/mem";
103:         return TCL_ERROR;
104:     }
105:     offsetmask = PAGE_SIZE;
106:     offsetmask--;
107:     pagemask = ~offsetmask;
108:     pageaddr = addr & pagemask;
109:     mmaped = (volatile unsigned short *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
110:     close(fd);
111:     if(mmaped == MAP_FAILED) {
112:         interp->result = "Cannot mmap";
113:         return TCL_ERROR;
114:     }
115:     *data = mmaped[(addr & offsetmask) >> 1] & 0xffff;
116:     munmap((char*)mmaped, PAGE_SIZE);
117:     return TCL_OK;
118: }
119: 
120: static int MemoryLongWrite(Tcl_Interp *interp, unsigned int addr, unsigned int data) {
121:     volatile unsigned int    *mmaped;
122:     int        fd, i;
123:     unsigned int    pageaddr, offsetmask, pagemask;
124: 
125:     fd = open("/dev/mem",O_RDWR);
126:     if(fd < 0) {
127:         interp->result = "Cannot open /dev/mem";
128:         return TCL_ERROR;
129:     }
130:     offsetmask = PAGE_SIZE;
131:     offsetmask--;
132:     pagemask = ~offsetmask;
133:     pageaddr = addr & pagemask;
134:     mmaped = (volatile unsigned int *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
135:     close(fd);
136:     if(mmaped == MAP_FAILED) {
137:         interp->result = "Cannot mmap";
138:         return TCL_ERROR;
139:     }
140:     mmaped[(addr & offsetmask) >> 2] = data;
141:     munmap((char*)mmaped, PAGE_SIZE);
142:     return TCL_OK;
143: }
144: 
145: static int MemoryLongRead(Tcl_Interp *interp, unsigned int addr, unsigned int *data) {
146:     volatile unsigned int    *mmaped;
147:     int        fd, i;
148:     unsigned int    pageaddr, offsetmask, pagemask;
149: 
150:     fd = open("/dev/mem",O_RDWR);
151:     if(fd < 0) {
152:         interp->result = "Cannot open /dev/mem";
153:         return TCL_ERROR;
154:     }
155:     offsetmask = PAGE_SIZE;
156:     offsetmask--;
157:     pagemask = ~offsetmask;
158:     pageaddr = addr & pagemask;
159:     mmaped = (volatile unsigned int *)mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, pageaddr);
160:     close(fd);
161:     if(mmaped == MAP_FAILED) {
162:         interp->result = "Cannot mmap";
163:         return TCL_ERROR;
164:     }
165:     *data = mmaped[(addr & offsetmask) >> 2];
166:     munmap((char*)mmaped, PAGE_SIZE);
167:     return TCL_OK;
168: }
169: 
170: static int MemoryCmd(ClientData clientdata, Tcl_Interp *interp, int argc, char **argv) {
171:     unsigned int    addr, data;
172:     int    error;
173:     int    (*writefunc)(Tcl_Interp*, unsigned int, unsigned int);
174:     int    (*readfunc)(Tcl_Interp*, unsigned int, unsigned int *);
175: 
176:     if(argc < 3 || argc > 4) {
177:         interp->result = "Usage: memory byte|word|long address ?data?";
178:         return TCL_ERROR;
179:     }
180:     if(strcmp(argv[1], "byte") == 0) {
181:         writefunc = MemoryByteWrite;
182:         readfunc = MemoryByteRead;
183:     } else if(strcmp(argv[1], "word") == 0) {
184:         writefunc = MemoryWordWrite;
185:         readfunc = MemoryWordRead;
186:     } else if(strcmp(argv[1], "long") == 0) {
187:         writefunc = MemoryLongWrite;
188:         readfunc = MemoryLongRead;
189:     } else {
190:         interp->result = "Usage: memory byte|word|long address ?data?";
191:         return TCL_ERROR;
192:     }
193:     error = Tcl_GetInt(interp, argv[2], &addr);
194:     if(error != TCL_OK) return error;
195:     if(argc == 4) {
196:         error = Tcl_GetInt(interp, argv[3], &data);
197:         if(error != TCL_OK) return error;
198:         error = (*writefunc)(interp, addr, data);
199:         if(error != TCL_OK) return error;
200:     }
201:     error = (*readfunc)(interp, addr, &data);
202:     if(error != TCL_OK) return error;
203:     sprintf(interp->result, "%d", data);
204:     return TCL_OK;
205: }
206: 
207: int Memory_Init(Tcl_Interp *interp) {
208:     Tcl_CreateCommand(interp, "memory", MemoryCmd, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
209:     Tcl_PkgProvide(interp, "memory", "1.1");
210:     return TCL_OK;
211: }
リスト3の20~168行目まではハードウェアアクセスを行う関数で、
SHプロセッサではメモリアクセスが1バイトアクセス、
Tcl_
外部から呼び出させる関数は初期化関数 Memory_
tcl言語処理系からMemoryCmd関数へ渡される引数は2つまたは3つでそれ以外はエラー終了にしています
第2引数は、
もし、
コンパイルと実行
共有ライブラリのコンパイルはPC上で行い、
# sh3-linux-gcc -shared -Wl,-soname,memory.so -o memory.so memory.c
できあがったmemory.
# tclsh % load ./memory.so Memory % format %x [memory byte 0xa4000136 0x36] 36 % exit #
上記の例ではSH7706LSRの付属LEDを点灯させる処理を行っています。
次回は
次回はSH7706LSRのLinux上でハードウェア割り込みを扱う方法について解説します。