高速キャリージェネレター付き8ビット加算・減算器の製作 ― 2025年02月06日 21:36
![](http://kida.asablo.jp/blog/img/2025/02/06/6f15a6.jpg)
高速キャリージェネレター付き8ビット加算・減算器の製作
デジタル回路の学び直しをしています。テキストは、大川喜邦著「デジタル回路」です。組合せ回路の部分が終わりました。組合せ回路のまとめとして、高速キャリージェネレーター付きの8ビット加算・減算器を基本的なTTLだけで設計、製作しました。最終的には、TTLが30個でできました。
。
ウラ面はこんな感じです。
手ハンダなので、スパゲティボールです。
基板上の"Value A"と"Value B"のスイッチに-128から127までの数値を設定し、加算・減算した結果を"Result"LEDに表示します。負の数は2の補数表現です。
回路図は、ここ にあります。
CPUの中のALUの一部を解析するとこんな感じになるのでしょうね。
Modula-2 でプログラミング -- 文字列探索プログラム find の製作 (その3) -- ― 2025年01月05日 21:19
前回紹介したfindプログラムは、FileSearchモジュールの不備で、ファイル一覧の構造が 丸見えになっていました。FileSearchモジュールに2つ手続きを追加して不具合を解消しました。
新しいFileSearchモジュールの定義モジュールは以下の通り。
DEFINITION MODULE FileSearch; FROM OpSys IMPORT FCB,FCBFileName; EXPORT QUALIFIED pFileList,FileNameNode, GetNextFile,GetFileName,LoginDisk,MakeFileList,DumpFileList; CONST DMABufferSize = 128; FileNameSize = 14; TYPE pFileList = POINTER TO FileNameNode; FileNameNode = RECORD FileName: ARRAY [0..FileNameSize] OF CHAR; Next: pFileList END; DMA = ARRAY [0..DMABufferSize-1] OF CHAR; PROCEDURE GetNextFile(FileLIst: pFileList): pFileList; PROCEDURE GetFileName(FileList: pFileList;VAR FileName: ARRAY OF CHAR); PROCEDURE LoginDisk(FCBBuf: FCB): CHAR; PROCEDURE MakeFileList(FIleMatch: ARRAY OF CHAR): pFileList; PROCEDURE DumpFileList(pList: pFileList); END FileSearch.手続き、次のファイルを取り出すGetNextFileとファイル名を取り出すGetFileNameを追加しました。 実現モジュールは以下の通り。
IMPLEMENTATION MODULE FileSearch; FROM InOut IMPORT WriteHex,Write,WriteString,WriteLn; FROM OpSys IMPORT FCB,FCBFileName,BdosFunctions,Bdos; FROM SYSTEM IMPORT ALLOCATE,TSIZE,ADR,WORD; FROM FileNames IMPORT StrToFCB,FCBToStr,NameState; CONST EOS = 0C; PROCEDURE GetNextFile(FileList: pFileList): pFileList; BEGIN RETURN FileList^.Next END GetNextFile; PROCEDURE GetFileName(FileList: pFileList; VAR FileName: ARRAY OF CHAR); VAR i: CARDINAL; BEGIN i := 0; WHILE ( FileList^.FileName[i] # EOS ) DO FileName[i] := FileList^.FileName[i]; INC(i) END; FileName[i] := EOS END GetFileName; PROCEDURE LoginDisk(FCBBuf: FCB): CHAR; VAR DiskCode: CARDINAL; Junk: WORD; BEGIN IF FCBBuf.name.disk = 0C THEN Bdos(retCDsk,Junk,DiskCode); RETURN (CHR(ORD(DiskCode)+ORD('A'))); ELSE RETURN (CHR(ORD(FCBBuf.name.disk)+ORD('A')-1)); END; END LoginDisk; PROCEDURE MakeFileList(FileMatch: ARRAY OF CHAR): pFileList; VAR Disk: CHAR; FCBBuffer: FCB; BdosRc: CARDINAL; DMABuffer: DMA; CPos: CARDINAL; NameStatus: NameState; pList: pFileList; pNewFileName: pFileList; FCBFile: FCBFileName; Formatted: BOOLEAN; Junk: WORD; BEGIN pList := NIL; (* Clear FCB Buffer and set file name *) FCBBuffer.name.text := ''; FCBBuffer.rest := ''; NameStatus := StrToFCB(FileMatch,FCBBuffer.name); Disk := LoginDisk(FCBBuffer); (* set DMA Bufer *) Bdos(setDMA,ADR(DMABuffer),Junk); (* find first much file *) Bdos(searchFst,ADR(FCBBuffer),BdosRc); WHILE BdosRc # 255 DO ALLOCATE(pNewFileName,TSIZE(FileNameNode)); FOR CPos := 0 TO 11 DO FCBFile.text[CPos] := DMABuffer[CPos+BdosRc*32] END; FCBFile.disk := CHR(ORD(Disk) - ORD('A') + 1); FCBToStr(FCBFile,pNewFileName^.FileName,FALSE); pNewFileName^.Next := pList; pList := pNewFileName; (* find next file *) Bdos(searchNxt,Junk,BdosRc); END; RETURN pList END MakeFileList; PROCEDURE WriteFileName(FileName: ARRAY OF CHAR); BEGIN WriteString(FileName); WriteLn END WriteFileName; PROCEDURE DumpFileList(pList: pFileList); BEGIN WHILE pList # NIL DO WriteFileName(pList^.FileName); pList := pList^.Next; END; END DumpFileList; END FileSearch.
これらの変更を反映したfindは、以下のとおり。
MODULE Find; FROM InOut IMPORT Write,WriteCard,WriteString,WriteLn; FROM Files IMPORT FILE,FileState,Open,Close,Read; FROM CmdArgs IMPORT Argc,Argv; FROM FileSearch IMPORT GetFileName,GetNextFile, FileNameNode,MakeFileList,pFileList; FROM BasicFileIO IMPORT FileIOStruct,pFileIOStruct, OpenFile,CloseFile,EOFFile,FileIOStatus; FROM StdFileIO IMPORT GetLine; CONST EOS = 0C; MAXLINE = 128; FILENAMESIZE = 14; EOFMARK = 32C; VAR FileName: ARRAY [0..FILENAMESIZE] OF CHAR; FileMatch: ARRAY [0..FILENAMESIZE] OF CHAR; Target: ARRAY [0..MAXLINE] OF CHAR; CPos,FileNumber,LineNumber,nArgc: CARDINAL; pList: pFileList; PROCEDURE putLine(FileName:ARRAY OF CHAR;Line:CARDINAL; Buffer: ARRAY OF CHAR); BEGIN WriteString(FileName); Write(' ');WriteCard(Line,1);Write(':'); WriteString(Buffer); WriteLn END putLine; 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 Usage(); BEGIN WriteString('find');WriteLn; WriteString(' TargetString File1 File2 FIle3,,,,');WriteLn END Usage; PROCEDURE MatchLines(FileName,TargetString: ARRAY OF CHAR); VAR pFileIO: pFileIOStruct; Line: ARRAY [0..MAXLINE-1] OF CHAR; Chars: CARDINAL; NLines: CARDINAL; Junk: FileIOStatus; BEGIN IF OpenFile(FileName,pFileIO) = Success THEN NLines := 1; WHILE NOT EOFFile(pFileIO) DO Chars := GetLine(pFileIO,Line); IF findTarget(TargetString,Line) THEN putLine(FileName,NLines,Line); END; INC(NLines); END; Junk := CloseFile(pFileIO) END END MatchLines; BEGIN nArgc := Argc(); IF nArgc < 1 THEN Usage(); HALT END; Argv(0,Target); FileNumber := 1; WHILE FileNumber < nArgc DO Argv(FileNumber,FileMatch); pList := MakeFileList(FileMatch); WHILE pList # NIL DO GetFileName(pList,FileName); MatchLines(FileName,Target); pList := GetNextFile(pList) END; INC(FileNumber) END END Find.
これで、FileSearchモジュール内部のデータ構造をFindが知る必要がなくなりました。
Modula-2でプログラミング -- 文字列探索プログラム find の制作(その1) ― 2024年12月28日 21:00
指定された文字列を 指定されたファイルの中から探し出すプログラム find を紹介します。 このように使います。
C0#find arguments>GetLine *.def *.mod C:STDFILEI.DEF 6: GetLine; C:STDFILEI.DEF 8:PROCEDURE GetLine(VAR pFileIO: pFileIOStruct; C:STDFILEI.MOD 10:PROCEDURE GetLine(VAR pFileIO: pFileIOStruct; C:STDFILEI.MOD 36:END GetLine; C:FIND.MOD 8:FROM StdFileIO IMPORT GetLine; C:FIND.MOD 71: Chars := GetLine(pFileIO,Line); 63K QP/M VER 2.7 (BIOS VER 1.0) (C) 1988.12.1. K.YOSHIDA 2018.10.28. MODEFIED BY H.KIDA C0#find arguments>GetChar *.def *.mod C:BASICFIL.DEF 7: ReadFile,GetChar; C:BASICFIL.DEF 28:PROCEDURE GetChar(VAR pFileIO: pFileIOStruct): CHAR; C:STDFILEI.MOD 3: pFileIOStruct,GetChar; C:STDFILEI.MOD 20: C := GetChar(pFileIO); C:BASICFIL.MOD 65:PROCEDURE GetChar(VAR pFileIO: pFileIOStruct): CHAR; C:BASICFIL.MOD 89:END GetChar; 63K QP/M VER 2.7 (BIOS VER 1.0) (C) 1988.12.1. K.YOSHIDA 2018.10.28. MODEFIED BY H.KIDA C0#
find は、ファイルを読みますので、ファイルアクセスのルーチンが必要になります。 Bdosを直接使うことができるので、かんたんなファイル読み込みモジュール BasicFileIO を作成しました。 更に、行単位のファイル読み出しが必要なので、上位のモジュール StdFileIO を作成しました。StdFileIOは、 Bdosとは、独立しています。
まず、 BasicFileIO です。基本的なファイルアクセスルーチンの集まりです。 今回は、読み出せれば良いので、書き込み関係のルーチンは作成していません。基本的なファイルのアクセスは、 一文字単位です、 定義モジュールは、以下のとおりです。
DEFINITION MODULE BasicFileIO; FROM OpSys IMPORT FCB,FCBFileName; EXPORT QUALIFIED FileIOStatus,FileIOStruct,pFileIOStruct, OpenFile,CloseFile,EOFFile, ReadFile,GetChar; CONST DMASize = 128; TYPE FileIOStatus = (Success,InvalidFileName, OpenError,CloseError,IOError); DMA = ARRAY [0..DMASize-1] OF CHAR; pFileIOStruct = POINTER TO FileIOStruct; FileIOStruct = RECORD FCBBuf: FCB; DMABuf: DMA; ReadPos: CARDINAL; WritePos: CARDINAL; EOFFlag: BOOLEAN; END; PROCEDURE OpenFile(FileName: ARRAY OF CHAR; VAR pFileIO: pFileIOStruct): FileIOStatus; PROCEDURE CloseFile(VAR pFileIO: pFileIOStruct): FileIOStatus; PROCEDURE ReadFile(VAR pFileIO: pFileIOStruct): FileIOStatus; PROCEDURE GetChar(VAR pFileIO: pFileIOStruct): CHAR; PROCEDURE EOFFile(pFileIO: pFileIOStruct): BOOLEAN; END BasicFileIO.
実装モジュールは、以下のとおりです。手続き GetChar では、CR LF と連続した場合、 LF を読み飛ばします。
IMPLEMENTATION MODULE BasicFileIO; FROM InOut IMPORT Write,WriteString,WriteLn; FROM OpSys IMPORT BdosFunctions,FCBFileName,Bdos,FCB; FROM FileNames IMPORT StrToFCB,NameState; FROM SYSTEM IMPORT ALLOCATE,ADR,TSIZE,WORD; CONST CR = 15C; LF = 12C; EOFMARK = 32C; PROCEDURE OpenFile(FileName: ARRAY OF CHAR; VAR pFileIO: pFileIOStruct): FileIOStatus; VAR BdosRc: CARDINAL; Junk: WORD; BEGIN (* Allocate FCB and DMA / pre-Set *) ALLOCATE(pFileIO,TSIZE(FileIOStruct)); pFileIO^.FCBBuf.name.text := ''; pFileIO^.FCBBuf.rest := ''; pFileIO^.DMABuf := ''; IF StrToFCB(FileName,pFileIO^.FCBBuf.name) # NameOK THEN RETURN InvalidFileName END; Bdos(setDMA,ADR(pFileIO^.DMABuf),Junk); Bdos(openF,ADR(pFileIO^.FCBBuf),BdosRc); IF BdosRc # 255 THEN pFileIO^.ReadPos := DMASize; pFileIO^.WritePos := 0; pFileIO^.EOFFlag := FALSE; RETURN Success ELSE RETURN OpenError END END OpenFile; PROCEDURE CloseFile(VAR pFileIO: pFileIOStruct): FileIOStatus; VAR BdosRc: CARDINAL; BEGIN Bdos(closeF,ADR(pFileIO^.FCBBuf),BdosRc); IF BdosRc = 0 THEN RETURN Success ELSE RETURN CloseError END END CloseFile; PROCEDURE ReadFile(VAR pFileIO: pFileIOStruct): FileIOStatus; VAR BdosRc: CARDINAL; BEGIN Bdos(readSeq,ADR(pFileIO^.FCBBuf),BdosRc); IF BdosRc = 0 THEN RETURN Success ELSE RETURN IOError END END ReadFile; PROCEDURE GetChar(VAR pFileIO: pFileIOStruct): CHAR; VAR C: CHAR; BEGIN IF DMASize = pFileIO^.ReadPos THEN IF ReadFile(pFileIO) = Success THEN pFileIO^.ReadPos := 0 ELSE pFileIO^.ReadPos := 0; pFileIO^.DMABuf[pFileIO^.ReadPos] := EOFMARK END END; C := pFileIO^.DMABuf[pFileIO^.ReadPos]; IF C = CR THEN IF pFileIO^.DMABuf[pFileIO^.ReadPos+1] = LF THEN INC(pFileIO^.ReadPos) END END; INC(pFileIO^.ReadPos); IF C = EOFMARK THEN pFileIO^.EOFFlag := TRUE END; RETURN C END GetChar; PROCEDURE EOFFile(pFileIO: pFileIOStruct): BOOLEAN; BEGIN RETURN pFileIO^.EOFFlag END EOFFile; END BasicFileIO.
GetChar で、 LF を読み飛ばす以外は、面倒くさいところは、ないでしょう。
この、 BasicFileIO モジュールをつかって、行単位の読み出しルーチンを作ってます。 StdFileIO モジュールです。 このモジュールは、 CP/M のファイル構造と独立です。必要最低限の行単位の読み出ししか作成していません。
定義モジュールは、以下の通り。
DEFINITION MODULE StdFileIO; FROM BasicFileIO IMPORT pFileIOStruct; EXPORT QUALIFIED GetLine; PROCEDURE GetLine(VAR pFileIO: pFileIOStruct; VAR LineBuffer: ARRAY OF CHAR): CARDINAL; END StdFileIO.
実装モジュールは、以下の通りです。
IMPLEMENTATION MODULE StdFileIO; FROM BasicFileIO IMPORT pFileIOStruct,GetChar; CONST EOS = 0C; EOFMARK = 32C; CR = 15C; PROCEDURE GetLine(VAR pFileIO: pFileIOStruct; VAR LineBuffer: ARRAY OF CHAR): CARDINAL; VAR C: CHAR; CPos: CARDINAL; BEGIN CPos := 0; LOOP C := GetChar(pFileIO); CASE C OF EOFMARK: LineBuffer[CPos] := EOS; RETURN CPos | CR: LineBuffer[CPos] := EOS; RETURN CPos END; LineBuffer[CPos] := C; INC(CPos); IF CPos = HIGH(LineBuffer) THEN LineBuffer[CPos] := EOS; RETURN CPos END END END GetLine; END StdFileIO.
GetLine は、一文字読み出しを繰り返し、 CR または EOF が来たら、その一文字前の文字までを一行とします。 また、バッファーのサイズ以上に読み取ろうとした場合は、強制的に一行にしてしまいます。溢れてしまうと困りますので。
find 本体の紹介は次回にします。
Modula-2でプログラミング -- FileFindの制作 ― 2024年11月02日 11:36
FIleSearche"モジュールを利用した、ファイマッチで指定されたファイル一覧を書き出すプログラム "FileFind"を作ってみました。
使い方は、このようにします。
C0#filefind arguments>f*.mod *.def C:FIND.MOD C:FILEFIND.MOD C:FILESEAR.MOD C:CONIO.DEF C:ADD16.DEF C:SILLY.DEF C:FILESEAR.DEF C:STDFILEI.DEF C:BDOSSTRU.DEF C:BASICFIL.DEF C:CMDARGS.DEF C:SCREEN.DEF
探すファイル名は、ファイルマッチを指定できます。複数指定できます。 この引数を受け取るには、以前紹介した自作の"CmdArgs"モジュール を使用しています。
プログラムは、このようになりました。
MODULE FileFind; FROM InOut IMPORT WriteString,WriteLn; FROM CmdArgs IMPORT Argc,Argv; FROM FileSearch IMPORT MakeFileList,DumpFileList; CONST MAXLINE = 128; VAR FileMatch: ARRAY [0..MAXLINE-1] OF CHAR; nArgc: CARDINAL; NthFile: CARDINAL; PROCEDURE Usage(); BEGIN WriteString('Usage: filefind filematch');WriteLn; END Usage; BEGIN nArgc := Argc(); IF nArgc < 1 THEN Usage(); HALT; END; NthFile := 0; WHILE NthFile < nArgc DO Argv(NthFile,FileMatch); DumpFileList(MakeFileList(FileMatch)); INC(NthFile); END; END FileFind.
次々にファイルマッチを取り出し、該当するファイル名のリストを"MakeFileList"で作成し、 そのリストを"DumpFileLIst"で書き出します。"DumpFileList"は、"FileSearch"モジュールに実装しました。 こうすることで、ファイル名の保持のしかたをメインルーチンが知る必要がありません。
Modula-2でプログラミング -- FileSearch ファイルを探すモジュールの修正 ― 2024年11月02日 10:29
前回、ファイルを探すモジュール"FileSearch"を制作しました。これを利用したプログラムを
いくつか作成して見た所、ファイル名リストのデータ構造の使い勝手が良くないことがわかりました
ので"FileSearch"モジュールを修正しました。
修正した"FileSearch"モジュールのDefinition Moduleです。
DEFINITION MODULE FileSearch; FROM OpSys IMPORT FCB,FCBFileName; EXPORT QUALIFIED pFileList,FileNameNode,DMA, LoginDisk,MakeFileList,DumpFileList; CONST DMABufferSize = 128; FileNameSize = 14; TYPE pFileList = POINTER TO FileNameNode; FileNameNode = RECORD FileName: ARRAY [0..FileNameSize] OF CHAR; Next: pFileList END; DMA = ARRAY [0..DMABufferSize-1] OF CHAR; PROCEDURE LoginDisk(FCBBuf: FCB): CHAR; PROCEDURE MakeFileList(FIleMatch: ARRAY OF CHAR): pFileList; PROCEDURE DumpFileList(pList: pFileList); END FileSearch.
大きな変更点は、ファイル名の持ち方をべたな文字列にした点です。
修正したImprementation Moduleは、このとおり。
IMPLEMENTATION MODULE FileSearch; FROM InOut IMPORT WriteHex,Write,WriteString,WriteLn; FROM OpSys IMPORT FCB,FCBFileName,BdosFunctions,Bdos; FROM SYSTEM IMPORT ALLOCATE,TSIZE,ADR,WORD; FROM FileNames IMPORT StrToFCB,FCBToStr,NameState; CONST EOS = 0C; PROCEDURE LoginDisk(FCBBuf: FCB): CHAR; VAR DiskCode: CARDINAL; Junk: WORD; BEGIN IF FCBBuf.name.disk = 0C THEN Bdos(retCDsk,Junk,DiskCode); RETURN (CHR(ORD(DiskCode)+ORD('A'))); ELSE RETURN (CHR(ORD(FCBBuf.name.disk)+ORD('A')-1)); END; END LoginDisk; PROCEDURE MakeFileList(FileMatch: ARRAY OF CHAR): pFileList; VAR Disk: CHAR; FCBBuffer: FCB; BdosRc: CARDINAL; DMABuffer: DMA; CPos: CARDINAL; NameStatus: NameState; pList: pFileList; pNewFileName: pFileList; FCBFile: FCBFileName; Formatted: BOOLEAN; Junk: WORD; BEGIN pList := NIL; (* Clear FCB Buffer and set file name *) FCBBuffer.name.text := ''; FCBBuffer.rest := ''; NameStatus := StrToFCB(FileMatch,FCBBuffer.name); Disk := LoginDisk(FCBBuffer); (* set DMA Bufer *) Bdos(setDMA,ADR(DMABuffer),Junk); (* find first much file *) Bdos(searchFst,ADR(FCBBuffer),BdosRc); WHILE BdosRc # 255 DO ALLOCATE(pNewFileName,TSIZE(FileNameNode)); FOR CPos := 0 TO 11 DO FCBFile.text[CPos] := DMABuffer[CPos+BdosRc*32] END; FCBFile.disk := CHR(ORD(Disk) - ORD('A') + 1); FCBToStr(FCBFile,pNewFileName^.FileName,FALSE); pNewFileName^.Next := pList; pList := pNewFileName; (* find next file *) Bdos(searchNxt,Junk,BdosRc); END; RETURN pList END MakeFileList; PROCEDURE WriteFileName(FileName: ARRAY OF CHAR); BEGIN WriteString(FileName); WriteLn END WriteFileName; PROCEDURE DumpFileList(pList: pFileList); BEGIN WHILE pList # NIL DO WriteFileName(pList^.FileName); pList := pList^.Next; END; END DumpFileList; END FileSearch.
大きな修正点は、見つかったファイルの名前をFCB形式からべたな文字列のファイル名に変換し、 それを保存している点です。 ファイル名の持ち方をべたな文字列にしたので、ファイル名を書き出すPROCEDURE "WriteFileName"を 修正しています。
他には、"BdosStruct"モジュールの使用をやめました。処理系が提供する Bdos関連機能の"OpSys"モジュールを一部修正し、"BdosStruct"モジュールが無くてもコンパイル できるようにしました。
Modula-2でプログラミング -- FileSearch ファイルを探すモジュールの制作 ― 2024年10月19日 09:49
ファイルを探すことは、結構よくあることです。CP/Mでプログラムを作る場合でも同じこと。 今回は、Modula-2からBDOSの機能を呼び出し、ファイルを探す"FileSearch"モジュールを紹介します。
"FileSearch"モジュールは、処理系が提供するモジュールをいくつか使用しています。
- "OpSys"モジュールは、BDOSやBIOSを呼び出すためのBdos手続きやFCBなどのレコード型などを提供しています。
- "FileNames"モジュールは、FCBのファイル名領域にファイル名を設定する手続きや、その手続きの戻り値の型を提供しています。
- "SYSTEM"モジュールは、メモリーの動的確保や変数のサイズなどを調べる手続きを提供しています。
このほかに自作モジュール"BdosStruct"があります。これは、BDOSを呼び出すBdos手続きがちょっと使いにくかったので、
処理系を騙す仕組みを作り込みました。
"FileSearch"モジュールのDefinition Moduleです。
DEFINITION MODULE FileSearch; FROM InOut IMPORT Write,WriteString,WriteLn; FROM OpSys IMPORT FCB,CPMStringBuffer,BdosFunctions,Bdos; FROM SYSTEM IMPORT ALLOCATE,SIZE,ADR,WORD; FROM FileNames IMPORT StrToFCB,NameState; FROM BdosStruct IMPORT BdosCommand,BdosReturn; EXPORT QUALIFIED pFileList,FileList,FileStruct,DMA, LoginDisk,MakeFileList,DumpFileList; CONST DMABufferSize = 128; TYPE FileStruct = RECORD CASE BOOLEAN OF TRUE: Disk: CHAR; Fill1: CHAR; Name: ARRAY [0..7] OF CHAR; Fill2: CHAR; Extention: ARRAY [0..2] OF CHAR; | FALSE: Text: ARRAY [0..13] OF CHAR; END; END; pFileList = POINTER TO FileList; FileList = RECORD File: FileStruct; Next: pFileList; END; DMA = ARRAY [0..DMABufferSize-1] OF CHAR; PROCEDURE LoginDisk(FCBBuf: FCB): CHAR; PROCEDURE MakeFileList(FileMatch: ARRAY OF CHAR): pFileList; PROCEDURE DumpFileList(pList: pFileList); END FileSearch.
Imprementation Moduleは、このとおり。
IMPLEMENTATION MODULE FileSearch; FROM InOut IMPORT Write,WriteString,WriteLn; FROM OpSys IMPORT FCB,BdosFunctions,Bdos; FROM SYSTEM IMPORT ALLOCATE,SIZE,ADR,WORD; FROM FileNames IMPORT StrToFCB,NameState; FROM BdosStruct IMPORT BdosCommand,BdosReturn,FileStruct,DMA; PROCEDURE LoginDisk(FCBBuf: FCB): CHAR; VAR BdosCmd: BdosCommand; Junk: WORD; DiskCode: BdosReturn; BEGIN IF FCBBuf.name.disk = 0C THEN BdosCmd.Func := retCDsk; Bdos(BdosCmd.Cmd,Junk,DiskCode.Rc); RETURN (CHR(ORD(DiskCode.Cc)+ORD('A'))); ELSE RETURN (CHR(ORD(FCBBuf.name.disk)+ORD('A')-1)); END; END LoginDisk; PROCEDURE MakeFileList(FileMatch: ARRAY OF CHAR): pFileList; VAR Disk: CHAR; FCBBuffer: FCB; BdosFunc: BdosCommand; BdosRc: BdosReturn; DMABuffer: DMA; ToPos, FromPos: CARDINAL; NameStatus: NameState; pList: pFileList; pNewFile: pFileList; NewFile: FileList; Junk: WORD; BEGIN (* Clear FCB Buffer and set file name *) FCBBuffer.name.text := ''; FCBBuffer.rest := ''; NameStatus := StrToFCB(FileMatch,FCBBuffer.name); (* get target disk *) Disk := LoginDisk(FCBBuffer); (* set DMA Bufer *) BdosFunc.Func := setDMA; Bdos(BdosFunc.Cmd,ADR(DMABuffer),Junk); (* initialize File Name List pointer *) pList := NIL; (* find first much file *) BdosFunc.Func := searchFst; Bdos(BdosFunc.Cmd,ADR(FCBBuffer),BdosRc.Rc); WHILE BdosRc.Cc # 255 DO (* copy from FCB buffer to file struct *) ALLOCATE(pNewFile,SIZE(NewFile)); pNewFile^.File.Disk := Disk; pNewFile^.File.Fill1 := ':'; ToPos := 0; FOR FromPos := 1 TO 8 DO pNewFile^.File.Name[ToPos] := DMABuffer[FromPos+BdosRc.Cc*32]; INC(ToPos); END; pNewFile^.File.Fill2 := '.'; ToPos := 0; FOR FromPos := 9 TO 11 DO pNewFile^.File.Extention[ToPos] := DMABuffer[FromPos+BdosRc.Cc*32]; INC(ToPos); END; (* insert new one *) pNewFile^.Next := pList; pList := pNewFile; (* find next file *) BdosFunc.Func := searchNxt; Bdos(BdosFunc.Cmd,Junk,BdosRc.Rc); END; RETURN pList END MakeFileList; PROCEDURE WriteFileStruc(FileStruc: FileStruct); BEGIN Write(FileStruc.Disk); Write(FileStruc.Fill1); WriteString(FileStruc.Name); Write(FileStruc.Fill2); WriteString(FileStruc.Extention); WriteLn; END WriteFileStruc; PROCEDURE DumpFileList(pList: pFileList); BEGIN WHILE pList # NIL DO WriteFileStruc(pList^.File); pList := pList^.Next; END; END DumpFileList; END FileSearch.
MakeFileList手続きが処理の中心です。ファイルを探すにはBDOSの機能番号16 最初のデータを探す(SearchFirst)、 機能番号17 次にデータを探す(SearchNext)を使います。 はじめに、FCBとDMAを準備します。そして、FCB領域を初期化します。
(* Clear FCB Buffer and set file name *) FCBBuffer.name.text := ''; FCBBuffer.rest := ''; NameStatus := StrToFCB(FileMatch,FCBBuffer.name);ここで躓きました。"FCBBuffer.rest"を初期化をしなかったために、 最初のデータを取得できたりできなかったりと、動作が不安定でした。 アセンブラでテストルーチンを書くとうまく動作します。悩みました。 使用したアセンブラでは、確保したデータ領域を自動的に0を埋め込んでいました。 しかし、Modula-2処理系では領域内の値は不定になるため、動作がおかしくなった様です。
最初のデータを見つけてしまえば、後は順に見つけることができました。
見つけたファイル名をリスト構造にして、返します。
DumpFileList手続きは、ファイル名リストを表示します。下受けルーチンとして、WriteFileStruc手続きを 使っています。
特に難しいロジックはありません。
BdosStructは、Definition Moduleだけです。以下のようになっています。
DEFINITION MODULE BdosStruct; FROM OpSys IMPORT BdosFunctions; FROM SYSTEM IMPORT WORD; EXPORT QUALIFIED BdosCommand,BdosReturn;2 TYPE BdosCommand = RECORD CASE BOOLEAN OF TRUE: Func: BdosFunctions; | FALSE: Cmd: WORD; END; END; BdosReturn = RECORD CASE BOOLEAN OF TRUE: Rc: WORD; | FALSE: Cc: CARDINAL; END; END; END BdosStruct.
次回は、これを応用したファイルマッチで指定されたファイルをリストするコマンド"FileFind"紹介します。
ヴィルト先生 ― 2024年01月06日 13:10
![](http://kida.asablo.jp/blog/img/2024/01/06/6a8722.jpg)
チューリッヒ連邦工科大学のOberonチームから、悲しい知らせが届きました。Pascal, Modulaといった プログラミング言語を世に送り出し、更にOberonという言語で記述したテキスト指向のオペレーティングシステムの開発者でもある ニクラウス ヴィルト先生が、なくなりました。
私が、ヴィルト先生のことを知ったのは、学生時代に参加したPascalの勉強会ででした。使用したテキストが、 ヴィルト先生らが書いた「Pascal(原題 Pascal User Manual and Report)」でした。この勉強会を通じて、Fortranとは違う プログラミング・パラダイムを知り、構造化されたプログラミングスタイルを身につけることができました。 このことは、仕事についてから、Cでのプログラム開発に、大いに役立ちました。 また、その後の、仕事においても、趣味においてでも、Pascalは重要な位置を締めてきました。
ヴィルト先生の著作を もう2冊持っています。「アルゴリズム+データ構造=プログラム(原題 ALGORITHMS+DATA STRUCTURES=PROGRAM)」と「アルゴリズムとデータ構造(原題 ALGORITHMS & DATA STRUCTURES)」です。この2冊は 兄弟になる著作でしょう。前者は、Pascalで、後者はModula-2でアルゴリズムの選択やそれに適したデータ構造の構築について 議論がなされています。これら3冊は、私にとってバイブル的存在であり、すぐに手に取れるところにおいています。
私がプログラマーとして成長するのに、大きな影響を受けたヴィルト先生のご冥福をお祈りましす。
ASSIT09で、8-Queens ― 2023年12月21日 17:18
![](http://kida.asablo.jp/blog/img/2023/12/21/6a59dd.jpg)
8-Queensを解くプログラムです。これは、8x8のマスにお互いが鑑賞しないようにQueenのコマの配置を求めるプログラムです。オリジナルで作成しようと頑張ったのですが、行き詰まってしまいました。いつものように、先人の方々のお知恵を拝借しました。調べてみると、ヴィルトの「アルゴリズム+データ構造=プログラム」にPascalで書かれたスマートな解がありました。暑中参照している「マイクロコンピュータのプログラミング」にもMicroPlanでの解が掲載されています。このMicroPlanの解を参照して、プログラムを作成しました。
さて、下敷きにしたプログラムは、Queenの配置を求めるルーチンが再帰的に書かれています。これをMC6809のアセンブラで書き下すのがキーポイントでしょう。想像しているより簡単に実現できました。MC6809にはスタックが、システムスタック Sとユーザースタック Uの2つがあります。このユーザースタックに、再帰的関数内部のローカル変数を退避させることでうまく行きました。 プログラム、アセンブルリスト、実行結果などは、こちらです。 8Queen.zip
いつものように、Lコマンドでロード・モジュールをダウンロードし、Cコマンドで、C000から実行させます。
Queenの配置が、次々と出てきます。
=== 8 Queens === 0 4 7 5 2 6 1 3 0 5 7 2 6 3 1 4 0 6 3 5 7 1 4 2 0 6 4 7 1 3 5 2 1 3 5 7 2 0 6 4 1 4 6 0 2 7 5 3 1 4 6 3 0 7 5 2 : : :例えば、"0 4 7 5 2 6 1 3"は、
カラム 0のQueenは、ロウ 0に カラム 1のQueenは、ロウ 4に カラム 2のQueenは、ロウ 7に カラム 3のQueenは、ロウ 5に カラム 4のQueenは、ロウ 2に カラム 5のQueenは、ロウ 6に カラム 6のQueenは、ロウ 1に カラム 7のQueenは、ロウ 3ににあることを示しています。こんな配置です。
0 1 2 3 4 5 6 7 0 Q . . . . . . . 1 . . . . . . Q . 2 . . . . Q . . . 3 . . . . . . . Q 4 . Q . . . . . . 5 . . . Q . . . . 6 . . . . . Q . . 7 . . Q . . . . .
ASSIT09で、マイクロトレック ― 2023年11月07日 20:48
Assist09で動くアプリケーションを考えていたところ、石田晴久編「マイクロコンピュータのプログラミング」に 掲載されている、「宇宙戦争ケームのプログラム」が目に止まりました。いわゆる、スタートレックものです。石田先生作の Tiny-BASICで書かれた100行程度のプログラムリストが掲載されています。これを人間コンパイラになって、 6809アセンブラに変換しました。もとのリストには幾つか不具合がありましたが、解決しました。 結果、約700行のプログラムができました。 ここから、アセンブラ・ソース、アセンブル・リスト、ロード・モジュールを含むZIPファイルをダウンロードできます。 mtrek.zip
Assist09で実行するには、Lコマンドでロード・モジュールをダウンロードし、Cコマンドで、C000から実行させます。
こんな感じです。
"CAPTAIN :"に続いて、コマンドを入力します。
コマンドは、1:ミサイル発射、2:セクター移動、3:新しいギャラクシーにワープ、です。ミサイルでクリンゴンをすべて
やっつければ"WIN"、時間切れやエネルー切れで、"LOOSE"です。
このプログラムは、ポジションインディペントなプログラムです。Lコマンドにオフセットをつけてロードしても、
問題なく動作します。
ASSIST09で、Hello World! ― 2023年10月29日 08:15
モトローラのMC6809を使った自作マイコン"MyOwn6809"は、Assist09というモトローラが発表した モニタープログラムを搭載しています。Assist09には、12のサービスルーチンがあります。
- INCHP 文字入力
- OUTCH 文字出力
- PDATA1 文字列送出
- PDATA 改行と文字列送出
- OUT2HS 1バイトの16進化
- OUT4HS 1ワードの16進化
- PCRLF 改行
- SPACE スペース送出
- MONITOR Assist09の起動
- VCTRSW ベクタ・スワップ
- BRKPT ユーザ・ブレイク・ポイント
- 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"がプログラムカウンタ相対を指定しています。
最近のコメント