ASSIST09で、Hello World!2023年10月29日 08:15

モトローラのMC6809を使った自作マイコン"MyOwn6809"は、Assist09というモトローラが発表した モニタープログラムを搭載しています。Assist09には、12のサービスルーチンがあります。

  1. INCHP 文字入力
  2. OUTCH 文字出力
  3. PDATA1 文字列送出
  4. PDATA 改行と文字列送出
  5. OUT2HS 1バイトの16進化
  6. OUT4HS 1ワードの16進化
  7. PCRLF 改行
  8. SPACE スペース送出
  9. MONITOR Assist09の起動
  10. VCTRSW ベクタ・スワップ
  11. BRKPT ユーザ・ブレイク・ポイント
  12. PAUSE プログラム・ブレークとチェック

これらのサービスを使うことで、プログラムの開発をスムーズに進めることができます。

いつもの Hello World!を作ってみました。

* HELLO.ASM -- SAY "HELLO WORLD!"
* ASSIST09 SERVICE ENTRY CODE
PDATA   EQU     3       PUT CR/LF AND STRING TO CONSOLE

* CONSTANT VALUES
EOT     EQU     $04     END OF TEXT
CR      EQU     $0D     CARIGE RETURN
LF      EQU     $0A     LINE FEED
RAMTOP  EQU     $C000
*
        ORG     RAMTOP
MAIN:
        LEAX    HELLO,PCR
        SWI
        FCB     PDATA
        RTS
*
HELLO:  FCC     'HELLO WORLD!'
        FCB     CR,LF,EOT
*
        END

このプログラムは、RAMエリアの先頭、C000からロードするように作ってあります。このようにして、実行します。

このプログラムには、プログラムをどのような位置にロードしても実行できるように、おまじないをかけています。 論より証拠、C000からロードして、更にC020からにロードして実行してみました。

C020から実行しても正常に動いています。 いわゆる「リロケータブル」なプログラムになっています。変数のアドレスを指定するのに、プログラムカウンタの値を基準にして 指定しているので、このようなことができます。プログラムカウンタ相対です。

このプログラム中、出力文字列のアドレスを指定する部分、

        LEAX    HELLO,PCR
で、"PCR"がプログラムカウンタ相対を指定しています。

TRN-8にEEPROMを搭載する2023年08月11日 15:36

私のCP/M機 TRN-8のROM-BIOSは、UVEPROMの27C256互換品を使っています。実験などで ROM を 書き換えることもあります。コードを書いては、アセンブリし、UVEPROMに書き込んでテストするという、手順を 繰り返します。書き込む前に、紫外線でUVEPROMをイレーズする必要があります。これには、10分から15分かかります。 テストの繰り返しの中で、結構な待ち時間になります。というわけで、EEPROMを使用してみることを計画していました。

最近、27C256の互換品のEEPROM 28C256を入手できましたので、早速、27C256の内容をダンプして、28C256に 書き込み、置き換えてみました。結果、動きません。ROMライターを変えてもだめでした。当然、書き込みエラーは起きません。 こなったら、初心に戻り、データシートを比較してみました。アクセス速度は200nsecで問題なしです。ピン接続を確認すると、 おぉっと、1番ピンと27番ピンに違いがありました。違いは以下のごとくです。

PIN#27C25628C257
1VppA14
27A14/WE

このままでは、EEPROM 28C256を使ってテストをして、本番にはUV-EPROM 27C256を使ってという、 当初の目論見が実現できません。苦肉の策として、このような下駄を作りました。

本来のPROMソケットにこの下駄を差し、テスト中は下駄にEEPROMを刺します。テストが完了したら、下駄を取り外し UVEPROMを直接、PROMソケットに刺すわけです。こんな感じです。

これで、効率よくテストする環境が揃いました。

DC-DCコンバーターの制作2023年04月13日 13:51

5Vの電源から、他の電圧の電源を作成するには、DC-DCコンバーター用のICを使うのが手っ取り早いです。 以前、自作CP/MマシンTRN-8にAMD9511を組み込むときに+21Vが必要となり、中華製のDC-DCコンバーターを使用しました。

コイルを作成できれば自作できそうなので、挑戦しました。使用したコンバーター用のICは、モトローラのMC34063Aです。

今回作成したDC-DCコンバーターは、RS-232-Cのドライバ/レシーバの電源を想定した、+12V出力と-12V出力のものです。

回路図中の部品定数は、モトローラのデータシートを参照し決定しました。 コイルはジャンクで入手したトロイダルコアを使用し、自作しました。 作成には、デリカのインピーダンスブリッジ D1Sが活躍してくれました。

約70mmX約50mmの大きさにまとまりました。大げさな抵抗器が付いていますが、これは手持ちの部品を使用したためです。

目標通り、+5Vから+12V/-12Vを得ることができました。

Windowsやめたい -- その後2023年03月30日 16:43

Windowsがとても重くなってしまい、身動きが取れなくなってきたので代替えを模索していました。 おせっかいで邪魔なプロセスが沢山動いていているのが原因なのはわかっているのですが、殺す手立てがわからないので 改善することができずにいました。

Windowsの代替としてLinuxを検討し、テスト運用をしてきました。Windowsで使っているツールうち必須のものについて、 動作確認ができましたので、本格的にLinuxに移行しました。

Linuxは、Debianです。これをベースに、wineをいれて必須のWindowsのツールを動かしています。

移行したツールは、以下のとおりです。

  1. Google Chrome
  2. Mozilla ThunderBird
  3. 画像編集ソフトの JTrim (Windows版)
  4. 水魚堂さんの回路図エディタ (Windows版)

この移行を期に、Warp ServerでNFSサーバーを立ち上げ、Debianマシンからマウントできるようにしました。 安定してファイルの共有ができてます。

これから便利ツールを追加する計画です。

久しぶりに、Modula-2でプログラミング --その4-- CmdArgsの修正2023年01月30日 15:50

先に公開した"CmdArgs"モジュールに危ないところがありました。エクスポートしている変数"Argc"は、 インポートしたモジュールで変更できます。変えられてしまうと、"CmdArgs"モジュールが誤作動します。これを さけるために、引数の数を手続き"Argc()"で返すようにしました。 これで、不用意に"CmdArgs"モジュールにダメージを 与えることがなくなりました。

修正版の定義モジュール"CmdArgs.def"は、以下の通り。

DEFINITION MODULE CmdArgs;

EXPORT QUALIFIED Argv,Argc;

PROCEDURE Argc(): CARDINAL;
PROCEDURE Argv(n: CARDINAL;VAR ArgString: ARRAY OF CHAR);

END CmdArgs.

修正版の実装モジュール"CmdArgs.mod"は、以下の通り。

IMPLEMENTATION MODULE CmdArgs;
FROM ASCII IMPORT nul,ht,lf,cr;
FROM SYSTEM IMPORT ADR,WORD;
FROM OpSys IMPORT BdosFunctions,Bdos,CPMStringBuffer;

CONST
        SPACE = ' ';
        TAB = ht;
        COMMA = ',';
        SQUORT = "'";
        DQUORT = '"';
        EOS = nul;
        MAXARGS = 20;
        EMPTY = -1;

VAR
        ArgList: ARRAY [0..MAXARGS-1] OF INTEGER;
        CommandLine: CPMStringBuffer;
        QChar: CHAR;
        c,s: CARDINAL;
        CommaFlag: BOOLEAN;
        nArgc: CARDINAL;
        Msg: ARRAY [0..80] OF CHAR;

PROCEDURE Argc(): CARDINAL;
BEGIN
        RETURN nArgc;
END Argc;

PROCEDURE Argv(n: CARDINAL;VAR ArgString: ARRAY OF CHAR);
VAR
        s,d: CARDINAL;
BEGIN
        IF nArgc < n THEN
                ArgString[0] := EOS;
        ELSIF ArgList[n] = EMPTY THEN
                ArgString[0] := EOS;
        ELSE
                s := ArgList[n];
                d := 0;
                WHILE CommandLine.text[s] # EOS DO
                        ArgString[d] := CommandLine.text[s];
                        INC(s);INC(d);
                END;
                ArgString[d] := EOS;
        END;
END Argv;

PROCEDURE skipBlanks();
BEGIN
        WHILE isBlankChar(CommandLine.text[c]) DO
                INC(c);
        END;
END skipBlanks;

PROCEDURE skipSeparator();
BEGIN
        WHILE isSeparator(CommandLine.text[c]) DO
                INC(c);
        END;
END skipSeparator;

PROCEDURE isBlankChar(ch: CHAR): BOOLEAN;
BEGIN
        IF (ch = SPACE) OR (ch = TAB) THEN
                RETURN TRUE;
        END;
        RETURN FALSE;
END isBlankChar;

PROCEDURE nextQuort();
BEGIN
        WHILE (CommandLine.text[c] # EOS)
                AND (CommandLine.text[c] # QChar) DO
                INC(c);
        END;
END nextQuort;

PROCEDURE nextSeparator();
BEGIN
        WHILE (CommandLine.text[c] # EOS)
                AND (NOT isSeparator(CommandLine.text[c])) DO
                INC(c);
        END;
END nextSeparator;

PROCEDURE getOneArg(): CARDINAL;
VAR
        s: CARDINAL;
BEGIN
        IF CommandLine.text[c] # EOS THEN
                IF isQuort(CommandLine.text[c]) THEN
                        QChar := CommandLine.text[c];
                        INC(c);
                        s := c;
                        nextQuort();
                ELSE
                        s := c;
                        nextSeparator();
                END;
                CommaFlag := FALSE;
                IF CommandLine.text[c] # EOS THEN
                        IF CommandLine.text[c] # COMMA THEN
                                CommandLine.text[c] := EOS;
                                INC(c);
                                skipBlanks();
                        END;
                        IF CommandLine.text[c] = COMMA THEN
                                CommaFlag := TRUE;
                                CommandLine.text[c] := EOS;
                                INC(c);
                        END;
                END;
        ELSE
                s := 0;
        END;
        RETURN s;
END getOneArg;

PROCEDURE isQuort(ch: CHAR): BOOLEAN;
BEGIN
        IF (ch = SQUORT) OR (ch = DQUORT) THEN
                RETURN TRUE;
        END;
        RETURN FALSE;
END isQuort;

PROCEDURE isSeparator(ch: CHAR): BOOLEAN;
BEGIN
        CASE ch OF
        SPACE: RETURN TRUE;
        | TAB: RETURN TRUE;
        | COMMA: RETURN TRUE;
        ELSE
                RETURN FALSE;
        END;
END isSeparator;

PROCEDURE getCmdLine();
VAR
        BDOSCmd: RECORD
                CASE BOOLEAN OF
                TRUE: Func: BdosFunctions;
                | FALSE: Cmd: WORD;
                END;
        END;
        junk: WORD;
BEGIN
        BDOSCmd.Func := prtStr;
        Msg := 'arguments>$';
        Bdos(BDOSCmd.Cmd,ADR(Msg),junk);

        CommandLine.maxLen := CHR(255);
        CommandLine.curLen := CHR(0);
        BDOSCmd.Func := rdCBuf;
        Bdos(BDOSCmd.Cmd,ADR(CommandLine),junk);
        CommandLine.text[ORD(CommandLine.curLen)] := EOS;

        BDOSCmd.Func := prtStr;
        Msg[0] := cr; Msg[1] := lf; Msg[2] := '$';
        Bdos(BDOSCmd.Cmd,ADR(Msg),junk);

        FOR nArgc := 0 TO MAXARGS-1 DO
                ArgList[nArgc] := EMPTY;
        END;

        nArgc := 0;
        c := 0;
        CommaFlag := FALSE;
        skipBlanks();
        WHILE (CommandLine.text[c] # EOS) AND (nArgc < MAXARGS) DO
                ArgList[nArgc] := getOneArg();
                skipBlanks();
        INC(nArgc);
        END;
        IF (CommandLine.text[c] = EOS) AND CommaFlag THEN
                ArgList[nArgc] := c;
                INC(nArgc);
        END;
END getCmdLine;

BEGIN
        getCmdLine();
END CmdArgs.

この修正にあわせて、"Find"モジュールの変更をしました。

久しぶりに、Modula-2でプログラミング -- その3 -- "CmdLine.mod"モジュールの応用"Find.mod"の紹介2023年01月26日 11:18

先に公開しました"CmdLine.mod"モジュールを使った応用を紹介します。

応用モジュール"Find.mod"は、指定された文字列をファイル中から探し表示します。このような感じです。

文字列"WriteLn"をファイル"find.mod"、"cmdargs.def"、"tstargs.mod"から探して表示します。

C0#find
arguments>WriteLn find.mod cmdargs.def tstargs.mod
find.mod[3]FROM InOut IMPORT Write,WriteCard,WriteString,WriteLn;
find.mod[35]    WriteLn;
find.mod[87]    WriteString('find');WriteLn;
find.mod[88]    WriteString('      TargetString File1 File2 FIle3,,,,');WriteLn; 
tstargs.mod[2]FROM InOut IMPORT Write,WriteInt,WriteLn,WriteString;
tstargs.mod[13] WriteString('Argc:=');WriteInt(Argc,3);WriteLn;
tstargs.mod[20]         Write(']');WriteLn;

このように、ファイル名、出現した行番号、出現した行を表示します。"CmdArgs.def"には、該当する文字列がありませんでした。

では、"Find.mod"モジュールの内容です。文字列の検索は"FindTarget()"手続きでします。 ストレートに書き下しましたので、ロジックを追えることと思います。

Find.mod

MODULE Find;
FROM CmdArgs IMPORT Argc,Argv;
FROM InOut IMPORT Write,WriteCard,WriteString,WriteLn;
FROM ASCII IMPORT nul,lf;
FROM Files IMPORT FILE,FileState,Open,Close,Read;
FROM OpSys IMPORT Bdos,BdosFunctions;
FROM SYSTEM IMPORT WORD;

CONST
        EOS = nul;
        MAXLINE = 128;
        FILENAMESIZE = 15;
        EOFMARK = 32C;

VAR
        FileName: ARRAY [0..FILENAMESIZE] OF CHAR;
        Target: ARRAY [0..MAXLINE] OF CHAR;
        LineBuffer: ARRAY [0..MAXLINE] OF CHAR;
        FileNumber,LineNumber: CARDINAL;
        inFile: FILE;
        EndOfFile: BOOLEAN;
        fs: FileState;
        BdosCmd: RECORD
                CASE BOOLEAN OF
                        TRUE: Func: BdosFunctions;
                        | FALSE: Cmd: WORD;
                END;
        END;

PROCEDURE putLine(Name:ARRAY OF CHAR;Line:CARDINAL;Buffer:ARRAY OF CHAR);
BEGIN
        WriteString(Name);
        Write('[');WriteCard(Line,1);Write(']');
        WriteString(Buffer);
        WriteLn;
END putLine;

PROCEDURE ReBoot();
VAR
        junk: WORD;
BEGIN
        BdosCmd.Func := boot;
        Bdos(BdosCmd.Cmd,junk,junk);
END ReBoot;

PROCEDURE findTarget(Target,Line:ARRAY OF CHAR): BOOLEAN;
VAR
        t,l: CARDINAL;
        found: BOOLEAN;
BEGIN
        found := FALSE;
        t := 0; l := 0;
        WHILE (Line[l] # EOS) AND (NOT found) DO
                IF Line[l] = Target[0] THEN
                        t := 1;
                        WHILE Line[l+t] = Target[t] DO
                                INC(t);
                        END;
                        IF Target[t] = EOS THEN
                                found := TRUE;
                        END;
                END;
                INC(l);
        END;
        RETURN found;
END findTarget;

PROCEDURE ReadLine(f:FILE;VAR Line:ARRAY OF CHAR);
VAR
        c: CARDINAL;
BEGIN
        c := 0;
        Read(f,Line[c]);
        WHILE (Line[c] # lf) AND (NOT EndOfFile) DO
                IF Line[c] = EOFMARK THEN
                        EndOfFile := TRUE;
                ELSE
                        INC(c);
                        Read(f,Line[c]);
                END;
        END;
        Line[c] := EOS;
END ReadLine;

PROCEDURE Usage();
BEGIN
        WriteString('find');WriteLn;
        WriteString('      TargetString File1 File2 FIle3,,,,');WriteLn; 
END Usage;

BEGIN
        IF Argc < 1 THEN
                Usage();
                ReBoot();
        END;
        Argv(0,Target);
        FileNumber := 1;
        WHILE FileNumber < Argc DO
                Argv(FileNumber,FileName);
                fs := Open(inFile,FileName);
                IF fs = FileOK THEN
                        EndOfFile := FALSE;
                        LineNumber := 1;
                        WHILE NOT EndOfFile DO
                                ReadLine(inFile,LineBuffer);
                                IF findTarget(Target,LineBuffer) THEN
                                        putLine(FileName,LineNumber,
                                                LineBuffer);
                                END;
                                INC(LineNumber);
                        END;
                        fs := Close(inFile);
                END;
                INC(FileNumber);
        END;
END Find.

久しぶりに、Modula-2でプログラミング--その2 CmdLineモジュールの紹介--2023年01月23日 20:58

コマンドライン・パラメーターを読みとり、分解する仕組みを実現したモジュールを公開します。 Modula-2で作成しました。Modula-2では、コンパイル単位を「モジュール」と呼びます。モジュールは3種類あり、 「定義モジュール(DEFINITION MODULE)」、「実現モジュール(IMPLEMENTATION MODULE)」、 「モジュール(MODULE") です。

「定義モジュール」は、モジュールのインターフェイスを記述したもので、他のモジュールに公開する定数や手続きを記述します。

「実現モジュール」は、名前の通り、モジュールの機能を書き下したプログラムです。

「モジュール」は、いわゆるメインプログラムです。

まずは、定義モジュール"CmdArgs.def"です。

DEFINITION MODULE CmdArgs;

EXPORT QUALIFIED Argv,Argc;

VAR
        Argc: CARDINAL;

PROCEDURE Argv(n: CARDINAL;VAR ArgString: ARRAY OF CHAR);

END CmdArgs.

モジュール"CmdArgs"が提供(EXPORT)する手続き"Argv"と変数"Argc"を定義しています。 これを事前コンパイルしておき、このモジュールを利用するモジュールをコンパイルする際に読み込まれ、 妥当性のチェックに使われます。

おつぎは、実現モジュール"CmdArgs.mod"です。

CmdArgs.mod

IMPLEMENTATION MODULE CmdArgs;
FROM ASCII IMPORT nul,ht,lf,cr;
FROM SYSTEM IMPORT ADR,WORD;
FROM OpSys IMPORT BdosFunctions,Bdos,CPMStringBuffer;

CONST
        SPACE = ' ';
        TAB = ht;
        COMMA = ',';
        SQUORT = "'";
        DQUORT = '"';
        EOS = nul;
        MAXARGS = 20;
        EMPTY = -1;

VAR
        ArgList: ARRAY [0..MAXARGS-1] OF INTEGER;
        CommandLine: CPMStringBuffer;
        QChar: CHAR;
        c,s: CARDINAL;
        CommaFlag: BOOLEAN;
(*      Argc: CARDINAL; defined in CmdArgs.Def  *)
        Msg: ARRAY [0..80] OF CHAR;

PROCEDURE skipBlanks();
BEGIN
        WHILE isBlankChar(CommandLine.text[c]) DO
                INC(c);
        END;
END skipBlanks;

PROCEDURE skipSeparator();
BEGIN
        WHILE isSeparator(CommandLine.text[c]) DO
                INC(c);
        END;
END skipSeparator;

PROCEDURE isBlankChar(ch: CHAR): BOOLEAN;
BEGIN
        IF (ch = SPACE) OR (ch = TAB) THEN
                RETURN TRUE;
        END;
        RETURN FALSE;
END isBlankChar;

PROCEDURE Argv(n: CARDINAL;VAR ArgString: ARRAY OF CHAR);
VAR
        s,d: CARDINAL;
BEGIN
        IF Argc < n THEN
                ArgString[0] := EOS;
        ELSIF ArgList[n] = EMPTY THEN
                ArgString[0] := EOS;
        ELSE
                s := ArgList[n];
                d := 0;
                WHILE CommandLine.text[s] # EOS DO
                        ArgString[d] := CommandLine.text[s];
                        INC(s);INC(d);
                END;
                ArgString[d] := EOS;
        END;
END Argv;

PROCEDURE nextQuort();
BEGIN
        WHILE (CommandLine.text[c] # EOS)
                AND (CommandLine.text[c] # QChar) DO
                INC(c);
        END;
END nextQuort;

PROCEDURE nextSeparator();
BEGIN
        WHILE (CommandLine.text[c] # EOS)
                AND (NOT isSeparator(CommandLine.text[c])) DO
                INC(c);
        END;
END nextSeparator;

PROCEDURE getOneArg(): CARDINAL;
VAR
        s: CARDINAL;
BEGIN
        IF CommandLine.text[c] # EOS THEN
                IF isQuort(CommandLine.text[c]) THEN
                        QChar := CommandLine.text[c];
                        INC(c);
                        s := c;
                        nextQuort();
                ELSE
                        s := c;
                        nextSeparator();
                END;
                CommaFlag := FALSE;
                IF CommandLine.text[c] # EOS THEN
                        IF CommandLine.text[c] # COMMA THEN
                                CommandLine.text[c] := EOS;
                                INC(c);
                                skipBlanks();
                        END;
                        IF CommandLine.text[c] = COMMA THEN
                                CommaFlag := TRUE;
                                CommandLine.text[c] := EOS;
                                INC(c);
                        END;
                END;
        ELSE
                s := 0;
        END;
        RETURN s;
END getOneArg;

PROCEDURE isQuort(ch: CHAR): BOOLEAN;
BEGIN
        IF (ch = SQUORT) OR (ch = DQUORT) THEN
                RETURN TRUE;
        END;
        RETURN FALSE;
END isQuort;

PROCEDURE isSeparator(ch: CHAR): BOOLEAN;
BEGIN
        CASE ch OF
        SPACE: RETURN TRUE;
        | TAB: RETURN TRUE;
        | COMMA: RETURN TRUE;
        ELSE
                RETURN FALSE;
        END;
END isSeparator;

PROCEDURE getCmdLine();
VAR
        BDOSCmd: RECORD
                CASE BOOLEAN OF
                TRUE: Func: BdosFunctions;
                | FALSE: Cmd: WORD;
                END;
        END;
        junk: WORD;
BEGIN
        BDOSCmd.Func := prtStr;
        Msg := 'arguments>$';
        Bdos(BDOSCmd.Cmd,ADR(Msg),junk);

        CommandLine.maxLen := CHR(255);
        CommandLine.curLen := CHR(0);
        BDOSCmd.Func := rdCBuf;
        Bdos(BDOSCmd.Cmd,ADR(CommandLine),junk);
        CommandLine.text[ORD(CommandLine.curLen)] := EOS;

        BDOSCmd.Func := prtStr;
        Msg[0] := cr; Msg[1] := lf; Msg[2] := '$';
        Bdos(BDOSCmd.Cmd,ADR(Msg),junk);

        FOR Argc := 0 TO MAXARGS-1 DO
                ArgList[Argc] := EMPTY;
        END;

        Argc := 0;
        c := 0;
        CommaFlag := FALSE;
        skipBlanks();
        WHILE (CommandLine.text[c] # EOS) AND (Argc < MAXARGS) DO
                ArgList[Argc] := getOneArg();
                skipBlanks();
        INC(Argc);
        END;
        IF (CommandLine.text[c] = EOS) AND CommaFlag THEN
                ArgList[Argc] := c;
                INC(Argc);
        END;
END getCmdLine;

BEGIN
        getCmdLine();
END CmdArgs.

手続き"getCmdLine()"は、このモジュールが初期化されるときに動きます。"getCmdLine()"は、プロンプト "arguments>"を表示し、引数を読みとります。その後、前回示したルールに従って引数を分解します。

変数"Argc"は、分解後の引数の数です。

手続き"Argv(n,Param)"は、"n"番目の引数(nilで終わる文字列)を "Param"にコピーして返します。 存在しない引数の時は、"Param"は、長さ0の文字列になります。第一引数は引数は、"n=0"です。

何の変哲のない下請け手続きで書き下しましたので、ロジックを簡単に追えると思います。

次回は、"CmdArgs"モジュールを使用した例を紹介します。

久しぶりに、Modula-2でプログラミング2023年01月18日 06:46

CP/Mは、よくできたDOSですが、いくつか不満があります。そのひとつに、コマンド行パラメーターが すべて大文字になってしまうのです。これでは、findやsedのような文字列を検索したり、置換したりする アプリケーションで小文字を入力できないので、困ってしまいます。CP/Mが盛んに使われた時代を考えると 仕方のないことですが、何とかしたいものです。

入力されたコマンド行パラメーター入力をすべて小文字にするのは乱暴すぎます。折衷案として パラメータの入力を促し読みとる仕組みを作ることにしました。ついでに、少し賢い引数分解の仕組みを 組み込みました。

作成した仕組み"CmdArgs"は以下のルールで、引数を分解します。

  • 引数は、区切り文字(コンマ、スペース、タブ)で区切られる。
  • 最初のコンマの前が、スペース、タブである場合は、第一番目の引数は、ヌル文字列とみなす。
  • 最後の文字がコンマの場合は、最後に、ヌル文字列があるものとみなす。
  • 引数は、クオート文字('、または、")でくくることができる。 コンマ、スペース、タブを含むことができる。
  • クオート文字で始まる引数は、行末までにクオート文字が出現しない場合、行末末までのすべての文字を 含む。

プログラムは、"MODULA-2 Compiler for Z80-CP/M Version 2.01"で作成しました。

まずは、テストプログラム"TstArgs.mod"で、実際に引き数の入力や分解をみてください。

C0#tstargs
arguments>one  , two three "ONE TWO  ", '   THREE FOUR' four
Argc:=  6
  0[one]
  1[two]
  2[three]
  3[ONE TWO  ]
  4[   THREE FOUR]
  5[four]            

C0#tstargs
arguments>  , one two three   ,      <---カンマ直後に改行
Argc:=  5
  0[]
  1[one]
  2[two]
  3[three]
  4[] 

C0#tstargs
arguments> one  two 'Three,Four Five   <--- Fiveの後ろにはスペースがある
Argc:=  3
  0[one]
  1[two]
  2[Three,Four Five     ]

テストプログラム"TstArgs.mod"は、このようになります。

MODULE TstArgs;
FROM InOut IMPORT Write,WriteInt,WriteLn,WriteString;
FROM CmdArgs IMPORT Argc,Argv;   <--- コマンド行の引数を処理するモジュールを取り込む

CONST
        MAXSTRINGLENGTH = 80;

VAR
        Arg: ARRAY [0..MAXSTRINGLENGTH] OF CHAR;
        nArgs: CARDINAL;

BEGIN
        WriteString('Argc:=');WriteInt(Argc,3);WriteLn;
        nArgs := 0;
        WHILE nArgs < Argc DO
                WriteInt(nArgs,3);
                Write('[');
                Argv(nArgs, Arg);
                WriteString(Arg);
                Write(']');WriteLn;
                INC(nArgs);
        END;
END TstArgs.

コマンド行を処理するモジュール"CmdArgs.mod"については、分量があるので、次回に公開します。

System02 / MyOwn 6809 〜〜 回路図を公開します2022年10月20日 20:30

前回、前々回にお披露目した System02 と MyOwn 6809 の回路図を公開します。

まずは、 System02 です。(クリックすると拡大します。)
スペックは、CPUに MC68B02、RAMは 2KB、I/Oには MC68B21を配置しました。 クロックは、1MHzの水晶を使ったため250KHzです。

モニタROMはありません。どうやって使うかというと、DMAをつかって直接RAMにプログラムを書き込みます。

とても原始的な使い方ですが、スイッチをパチパチやっていると、コンピューターを 思うように操っている気になってくるから、不思議です。 プログラムが、きちんと動いたときの充実感は、また、別格です。

お次は、MyOwn 6809 です。(クリックすると拡大します。)
スペックは、CPUに MC68B09、RAM 8KBとROM 4KB、PTM MC68B40、ACIA MC68B50、ACIAのクロックジェネレーターに MC14111を 使ってます。 クロック用は、2MHzの水晶を使ったので 500KHz です。

PTMを搭載したので、ASSIST09モニターのトレースコマンドが使えます。念願を達成しました。

MyOwn 6809 〜〜 長年の夢がかないました 〜〜2022年10月09日 15:02

モトローラの6809を知ったのは、学生のころです。「Z-80とは違うのがあるんだ」ぐらいの認識でしたが、 就職して、先輩から6809の資料をいただき、ASSIST09モニタのことを知り、いつか動かしてみたいと考えていました。 以前、vintagechipsさんのルーズキット「SBC6809」を知り製作しましたが、PTMが無いためトレースコマンドを 動かすことができず、悔しくて「いつかは、ASSIST09をフルスペックで」と考えていました。

やっと夢が、かないました。ASSIST09がフルペックで動くボード完成しました。MyOwn6809です。構想をたて設計/製作と 中断をはさみ、足掛け3年ぐらいかかりました。実質、一年というところでしょうか。

MyOwn6809は、MC68B09を中心に、ACIA 68B50、PTM 68B40と、RAM 8KB、ROM 2KBを配しました。 ボーレイトジェネレータに、贅沢にMC14111を アドレスデコードは手抜きをするために、GAL 20V8を使ってます。 MPUの状況をモニタする回路も仕込みました。 誰が考えても同じようになるH/W構成です。ちなみに、配線は全て手半田です。

ASSIST09は、ネットで見つけたソースリストを使っています。完成品と思っていたのですが、 MyOwn6809が完成にこぎつけるまで、このソースリストが最後まで足を引っ張りました。PTMの設定に問題がありました。 ソースリスを二ヶ所修正しました。まず、PTMの初期設定の部分で、

	CLR	PTMTM1-PTM,X
	CLR	PTMTM1+1-PTM,X
	LDD	#$FFFF
	STA	PTMC2-PTM,X
	STA	PTMC13-PTM,X
	CLR	PTMTM1-PTM,X
	CLR	PTMTM1+1-PTM,X
	LDD	#$01A6
	STA	PTMC2-PTM,X
	STA	PTMC13-PTM,X

に、変更。トレースコマンドにあるPTMの動作を設定ところを
	STU	<LASTOP
	LDU	<VECTAB+.PTM
	LDD	#$0000
	STD	PTMM1-PTM,U
	STU	<LASTOP
	LDU	<VECTAB+.PTM
	LDD	#$0701
	STD	PTMM1-PTM,U

に変更し、ビルドしました。これで、トレースコマンドを含む全コマンドが使用可能になりました。

多くの製作例を参照して製作に当たりましたが、最後まで自分を信じることで完成にたどり着けたと考えています。 はぁ〜、長かった。

次は、68000とCP/M 68kに挑戦です。