ブログのネタ切れ対策の2番目で、今回は、
私が大学4年の11月に探したソフトウエア系派遣会社の技術研修
次に実際の派遣先の三菱電機では、
翌年の1981年夏にはS社に転職し、
それ以降、C言語とアセンブラ言語を使って、
そこで、まず、C言語の簡単な例を挙げて、
分かり易い例として、
なおC言語とアセンブラ言語で一番重要な点は、
/* C言語 サブルーチン呼び出し例 */
char file1[] = "sample";
char ext1[] = "jpg";
char filebuf[16];
makeFileName(file1, ext1, filebuf);
file1、ext1、filebufは、
ローカル変数はスタック上に確保されて、
makeFileName()
/* C言語 サブルーチン本体 */
void makeFileName(char *file, char *ext, char *buf)
{
while(*file) *buf++ = *file++; /* loop1 */
*buf++ = '.'; /* dot */
while(*ext) *buf++ = *ext++; /* loop2 */
*buf = 0; /* exit */
}
3つのポインタfile、ext、
/* loop1 */のwhile文で、ポインタfileが指す名前"
file++、buf++の++は、
呼び出し側の char file1[] = "sample"; には"sample"の後に、終端子の0が設定されているから、その0を検出してwhileループが終了する。
/* dot */では、"sample"の後に、'.'の1文字を挿入。
同じく/* loop2 */while文は、ポインタextが指す名前"jpg"
/* exit */で、bufの最後に終端子の0をセットする。
なお /* と */ で囲まれた文字列は、C言語の処理系ではコメントと判断される。
ツールプログラムの後は、S社のIBM PC互換機+MS-DOSの環境で、MS-DOSデバイスドライバのソフトウエア開発商品化をいくつか担当した。当時、
ツールプログラムではZ80 8bit CPU+CP/Mの環境で、
レジスタとはコンピュータのハードウエアであるCPUの一部で物
ax、bx、cx、dxは、それぞれ8bitレジスタのah、
アドレスはセグメントレジスタとポインタレジスタ、
そこで上記のC言語のソースコードと同じ機能を持つプログラムを
以下がそのソースコード。
ただしgroup、segment、assume、
なおアセンブラ言語の処理系では、コメントは ; で始める。
; アセンブラ言語(Intel8086) サブルーチン呼び出し例
DGROUP group dseg
;
; data segment
;
dseg segment word public 'data'
assume ds:DGROUP
public file1, ext1, filebuf
;
file1 db 'sample', 0
ext1 db 'jpg', 0
filebuf ds 16
dseg ends
;
; code segment
;
cseg segment byte public 'code'
assume cs:cseg, ds:DGROUP
;
lea ax, offset file1
push ax
lea ax, offset ext1
push ax
lea ax, offset filebuf
push ax
call makeFileName
add sp, 6
;
cseg ends
;
end
サブルーチン用の3つの引数file1、ext1、
leaはload effective addressを意味する命令コードで、
call makefFileNameは、
add sp,6はsp(stack pointer)の値に6を加算する
; アセンブラ言語(Intel8086) サブルーチン本体
cseg segment byte public 'code'
assume cs:cseg, ds:DGROUP
public makeFileName
;
makeFileName proc near
push si
push di
mov si, word ptr ss:[sp+(4+2+6)]
mov di, word ptr ss:[sp+(4+2+2)]
loop1:
mov al, byte ptr ds:[si]
and al, al
jz dot
mov byte ptr ds:[di], al
inc si
inc di
jmp loop1
dot:
mov byte ptr ds:[di], '.'
inc di
mov si, word ptr ss:[sp+(4+2+4)]
loop2:
mov al, byte ptr ds:[si]
and al, al
jz exit
mov byte ptr ds:[di], al
inc si
inc di
jmp loop2
exit:
mov byte ptr ds:[di], al
pop di
pop si
ret
end proc
;
cseg ends
ss:、ds:
ここでloop1:、dot:、loop2:、exit:
byte ptrはbyte単位でメモリにアクセスすることを意味し、
アキュミュレータと呼ばれる演算専用レジスタを持つCPUでは、
ラベルloop2:以下も同じ処理方法で、exit:
なおaxレジスタは一般に戻り値として使用されるので、
スタックはFirst In Last Outのメモリなので、
サブルーチン側で引数を取り出す手順も説明しよう。
サブルーチンmakeFileName()
ss:sp → +-----------------------------
+2 |callの戻りアドレス(2bytes=16bits) |
+----------------------------
+4 |引数3:filebufのアドレス(2bytes) |
+----------------------------
+6 |引数2:ext1のアドレス(2bytes) |
+----------------------------
+8 |引数1:file1のアドレス(2bytes) |
+----------------------------
ここで2つのpush命令でsiとdiレジスタをセーブすれば、
ss:sp → +-----------------------------
+2 |diレジスタセーブ値(2bytes=16bits) |
+----------------------------
+4 |siレジスタセーブ値(2bytes) |
+----------------------------
+6 |callの戻りアドレス(2bytes) |
+----------------------------
+8 |引数3:filebufのアドレス(2bytes) |(4+2+2)
+----------------------------
+10 |引数2:ext1のアドレス(2bytes) |(4+2+4)
+----------------------------
+12 |引数1:file1のアドレス(2bytes) |(4+2+6)
+----------------------------
その為、
mov si, word ptr [sp+12]
mov di, word ptr [sp+8]
で十分。ext1のアドレスも同様に取得する。
昔話で恐縮だが、
call makeFileName
戻り→ dw (file1のアドレスを格納)
dw (ext1のアドレスを格納)
dw (filebufのアドレスを格納)
戻り2→ (makeFileNameから戻る場合、
サブルーチンmakeFileName()では、
何故、6ではなく3を加えるか、と言えば、
ただ三菱電気の産業用コンピュータでも、
何故なら、割り込み処理ではスタックを使ったはずだから。
一般に割り込み処理では、
割り込み処理ルーチンでは以下のことを行う。
1. 割り込みをディセーブル(disable)にする。
2. 割り込み処理ルーチンが担当するハードウエアからのデータ入出力
3. ハードウエアの割り込み信号をオフ、
4. 割り込みをイネーブル(enable)にする。
5. 割り込み処理からリターン(iret)する。
iretした後は、
IPやFレジスタの内容を直接メモリにセーブする命令があれば、
私が三菱電気で働き始めた1980年の前半は、
プリンタ、紙カードリーダー、紙テープ入出力装置等は、
1980年代後半になると、
つまり紙カードや紙テープが、
S社に転職した後は、
その後、プロッピーディスクはハードディスクに置き換わり、
使用するOSもCP/M、MS-DOS、unix、
MS-
Windows以降はデバイスドライバでもC言語だけで記述した
オーディオ新商品のファームウェア開発でもチームで作業。
その後、5年程ソフトウエア開発から足を洗い、
その時はもう熟年で、
ただ入社した中小企業では、
ただ残念ながら、商品化が終了する前に派遣契約が終了した。
元々S社のリストラはトップからの指示で、現場は人手不足。
その後は、豊洲の日本ユニシスで、
ここで再びmakeFileName()サブルーチンに戻ると、
void makeFileName(char *file, char *ext, char *buf)
{
strcpy(buf, file); /* loop1 */
strcat(buf, "."); /* dot */
strcat(buf, ext); /* loop2 */
}
と書ける。ただZ80+CP/
これがC++では、もっと簡単になる。
呼び出し側は、以下。
String file1 = "sample";
String ext1 = "jpg";
String filebuf;
filebuf = makeFileName(file1, ext1);
呼び出される側は、以下。
String makeFileName(String file, String ext)
{
return file + "." + ext;
}
もう関数やサブルーチンにする必要もない、という感じ。
記憶に残っている仕事をもう一つ紹介しよう。
名古屋への長期出張という形で、
ここで使っていたのがフリーウエアのYokka。
YokkaGrepは、
Yokkaは今でも窓の杜からダウンロード可能。
その後、2010年春には引退して、リタイヤ生活に入った。
過去を振り返って、
個人的にはプログラミングの才能はなかったと考える。何故なら、
なおそれはプログラミング以外にも一般的に当てはまる昔から自明
物理学専攻の大学生だった頃には、
就職した年の1980年冬、
勿論、プログラミングの仕事やプログラマーの求人が多い時代で、
さらに言えるとしたら、