1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

一般化されたアセンブラ 'axx General Assembler'

Last updated at Posted at 2024-02-21

GENERAL ASSEMBLER 'axx.py'

pythonで書いたので、ニックネームはPaxxです。

動作試験環境

Arch linux terminal

本文

axx.pyはアセンブラを一般化したジェネラル(一般)アセンブラです。理論上、殆ど任意のvon Neumann型プロセッサアーキテクチャを処理できます。個々のプロセッサアーキテクチャを処理するために、それ用のパターンファイル(プロセッサ記述ファイル)が必要です。自由なインストラクションを定義できますが、ターゲットプロセッサのアセンブリ言語に準じてパターンファイルを作ると、記法は若干異なるものの、そのプロセッサのアセンブリ言語を処理できます。要するに、インストラクションの文法規則と、それに基づくバイナリ生成だけなのです。

実行プラットフォームも特定の処理系に依存しません。DOSファイルの行末のchr(13)も無視するようにしています。pythonが動く処理系だったら動作すると思います。

このヴァージョンはアセンブラの核となる部分だけなので、専用のアセンブラの備えている最適化、高機能マクロ、デバッガなどの実用的な機能はサポートしていません。実用的な機能について、マクロはプリプロセッサを使ってください。とりあえず、リンカ・ローダは、バイナリファイルとラベル(シンボル)ファイルを管理するプログラムを使ってください。IDEではないため、デバッガは外部デバッガを使ってください。最適化は未対応です。基本的な機能はあると思うので、応用してください。今のバージョンは実用性が足りません。

パターンファイルとソースファイルが分離されているため、コード化の手間を考えなければ、あるインストラクションセットのソースから別のプロセッサの機械語を生成することも可能です。共通の言語から、異なるプロセッサの機械語コードを生成することも可能です。パターンデータのbinary_listに複数の命令コードを書くとマクロとして機能しますが、あまりスマートではありません。それにより、簡単なコンパイラも書けます。

パターンデータは、制御構文を代入と3項演算子と、;修飾子と、アライメントしか持ちません。アセンブリ言語に限らず、バイナリ生成に使えます。パターンファイルはチューリング不完全です。チューリング不完全な故、複雑なアーキテクチャのプロセッサには向きません。

アセンブリ言語はプロセッサのインストラクションコードと1対1に対応しているので、axxが実現しました。

axxは第1引数から、アセンブラのパターンデータを読み込み、パターンデータに基づき第2引数のソースファイルをアセンブルします。第2引数を省略したら、端末(標準入力)からソースを入力します。

結果は、標準出力にテキストとして出力され、-oオプションで指定された引数があれば、カレントディレクトリにバイナリファイルが出力されます。-eオプションは、.exportで指定されたラベルをセクション/セグメント情報とともにTSV形式でファイルに出力します。

axxでは、アセンブリ言語ソースファイルや標準入力から入力するラインをアセンブリラインと名付けます。

解説

install and execution(assemble) on unix.

# install
git clone https://github.com/fygar256/axx.git
cd axx
chmod +x axx.py
sudo cp axx.py /usr/bin/axx

# execution(assemble)
axx patternfile.axx [source.s] [-o outfile.bin] [-e expfile.tsv] [-i impfile.tsv]

patternfile.axx --- パターンファイル
source.s --- アセンブリソース
outfile.bin --- rawバイナリ出力ファイル
expfile.tsv --- セクション・ラベル情報エクスポートファイル
impfile.tsv --- セクション・ラベル情報インポートファイル

パターンファイルの解説

パターンファイルは、プロセッサ記述ファイルで、個々のプロセッサに対応するため、ユーザー定義です。機械語やアセンブリ言語に対する一種のメタ言語です。

パターンファイルの定義が難しいと感じるならば、最小限のオペランドだけ式の評価に渡して、文字列リテラルで書けばいいです。

パターンファイルの中のパターンデータは次のように並んでいます。

instruction  :: error_patterns  :: binary_list 
instruction  :: error_patterns  :: binary_list 
instruction  :: error_patterns  :: binary_list 
:
:

instructionは省略不可です。error_patternsは省略可です。binary_listは省略不可です。
instruction、error_patterns、binary_listは、::で区切ってください。

for ex. (x86_64)

RET :: 0xc3

コメント
パターンファイル内に、/*を書くとその行の/*以降がコメントになります。今の所、*/で閉じることはできません。その行の/*以降だけに有効です。

大文字・小文字の区別、変数
パターンファイルのinstructionの大文字は文字定数として扱われます。小文字にすると、1文字の変数として扱われます。アセンブルラインからその位置に当たるシンボルの持つ値が変数に代入されます。!小文字とすると、その位置の式の値、!!小文字にするとその位置の因子の値が代入され、error_patternsとbinary_listから参照されます。代入されてない変数は全て初期値の0です。error_patternsとbinary_listからの参照のときは、!は必要ありません。全て同様に値が参照されます。

小文字変数は、パターンファイルの一行毎に全て0に初期化されます。

アセンブリラインからは、ラベルやセクション名以外は、大文字でも小文字も同じとして受け付けます。

特殊な変数は$$で、現在のロケーションカウンタを表します。

エスケープキャラクタ

instruction内でエスケープキャラクタ\が使えます。

error_patterns

error_patternsは、変数と比較演算子を使い、エラーの出る条件を指定します。

エラーパターンは複数指定可で、,で区切って記述します。例えば、次のようです。

a>3;4,b>7;5

この例では、a>3のとき、エラーコード4を返し、b>7のときエラーコード5を返します。

binary_list

binary_listは、出力するコードを,で区切って指定します。例えば、0x03,dとすると、0x3の次にdが出力されます。

8048を例に取ります。パターンファイルに

ADD    A,R!n ::  n>7;5 :: n|0x68

があるとし、アセンブリラインにadd a,rnを渡すと、n>7のときエラーコード5(Register out of range)を返し、add a,r1で、0x69のバイナリが生成されます

binary_listの要素が空だと、アライメントをします。冒頭から、,で始まったり、0x12,,0x13などとすると、空の部分が丁度のアドレスまでパディングされます。

binary_listの要素の先頭に;がつくと、その要素が0だった場合、出力されません。

symbol

.setsym :: symbol :: n

と書くと、symbolが値nで定義されます。

シンボルは、アルファベット、数字、いくつかの記号列です。

symbol1でsymbol2を定義するのは以下のように書きます。

.setsym ::symbol1 ::1
.setsym ::symbol2 ::#symbol1

symbol定義のz80の例を挙げます。パターンファイル内に

.setsym ::B ::0
.setsym ::C ::1
.setsym ::D ::2
.setsym ::E ::3
.setsym ::H ::4
.setsym ::L ::5
.setsym ::A ::7
.setsym ::BC ::0x00
.setsym ::DE ::0x10
.setsym ::HL ::0x20
.setsym ::SP ::0x30

と書いておくと、シンボルB,C,D,E,H,L,A,BC,DE,HL,SPを、それぞれ0,1,2,3,4,5,7,0x00,0x10,0x20,0x30として定義します。シンボルには、大文字小文字の区別はありません。

パターンファイル中に同じシンボルの定義が複数あると、新しいものが古いものを更新します。すなわち、

.setsym ::B::0
.setsym ::C::1
ADD A,s

.setsym ::NZ::0
.setsym ::Z::1
.setsym ::NC::2
.setsym ::C ::3
RET s

この場合、ADD A,CのCは1、RET CのCは3になります。

・記号、数字、アルファベットが混在するシンボルの例

.setsym ::$s5:: 21

シンボルのクリアは.clearsymでします。

.clearsym::ax

上の例はaxというシンボルを未定義にします。

全クリアは引数を指定しないでします。

.clearsym

パターンファイル内から、シンボルに使う文字セットを決めることができます。

.symbolc::<characters>

とすると、数字とアルファベット大文字小文字以外の文字をで指定できます。

デフォルトは、アルファベット+数字+_%$-~&|です。

パターンの順番

パターンファイルは上から順に評価されますので、先に置かれたほうが優先します。特殊のパターンを先に、一般のパターンを後に置きます。下のように。

LD A,(HL)
LD A,e

二重大括弧

instructionの中の省略可能なものは二重大括弧で括れます。z80のinc (ix)命令を示します。

INC	(IX[[+!d]]) ::				    0xdd,0x34,d

この場合、小文字の変数の初期値は0なので、inc (ix+0x12)と、省略しなかった場合は0xdd,0x34,0x12が、inc (ix)と、省略した場合は0xdd,0x34,0x00が出力されます。

パディングのバイトコード指定

パターンファイルから、

.padding::0x12

と、するとパディングするバイトコードは0x12になります。デフォルトは0x00です。

ワードが8ビット単位でないプロセッサのビット数指定

パターンファイルに、

.bits::12

とすると、12ビットのプロセッサを扱えます。デフォルトは8ビットです。

8ビット未満の、例えばビットスライスプロセッサや、機械語のワードがバイト単位でないプロセッサのアセンブルは、このディレクティブでします。axxは8ビット単位の出力ですので、4ビットのプロセッサなら、下位4ビットが、11ビットのプロセッサなら、指定されたバイトオーダーにより、(下位8ビット、上位3ビット)または、(上位3ビット、下位8ビット)がバイナリファイルに8ビット毎に出力されます。8ビット以内の余計なビットは0でマスクされます。

.bitsディレクティブを指定すると、アドレスが示す値はワード単位になります。例えば64bit processorであるx86_64はバイト単位の処理ができるので、.bitsディレクティブの指定は不要です。

バイトオーダーの指定は以下のようにします。

.bits::big::12

bigでビッグエンディアンにバイトが並びます。littleでリトルエンディアンです。
デフォルトはlittleで、指定しなくてもlittleになります。

include

このようにするとファイルをインクルードできます。

.include "file.axx"

VLIWプロセッサ

.vliwディレクティブ

.vliw::128::41::5::00

とすると、バンドルのビット数128、1命令のビット数41、テンプレートビット数5、NOPコードは0x00(Itaniumの例)のEPICプロセッサを扱うことが出来ます。
例えば、Itaniumでは、41ビットの命令3つ、41*3=123(bit)の長さの命令群+先頭に5ビットのテンプレートビットが付いています。EPICでない場合には、テンプレートビットに0を指定してください。

EPICの場合

EPICプロセッサの場合、パターンファイルは以下のように記述されます。

/* VLIW
.setsym::R1::1
.setsym::R2::2
.setsym::R3::3
.setsym::R4::4
.vliw::128::41::5::00
EPIC::1,2::0x8
EPIC::1::0x01
AD a,b,c:: ::0x01,0,0,a,b,c::1
LOD d,[!e]:: :: 0x00,0x01,0,d,e,e>>8::2

と書き、EPIC::1,2::0x8はEPICの命令のセットを表し、インデックス1,2の命令のバンドルの、テンプレートが0x8であるコードを表します。
あとの、AD a,b,c:: ::0x01,0,0,a,b,c::1は、ADD命令 r1,r2,r3がエラーチェック無しで0x01,0,0,a,b,cを出力し、インデックスコードは1で、LOD d,[!e]:: :: 0x00,0x01,0,d,e,e>>8::2は、LOAD命令 r4に[!e]の内容を格納、エラーチェック無しで、0,1,0,0xd,e(下位8ビット)、e(上位8ビット)を出力し、インデックスコードは2のインストラクションを表します。このサンプルは、試験用なので実際のバイトコードと違います。

.viwで指定するパラメータは、(バンドルのビット数-テンプレートのビット数を8(bit)で割った値)+(それが余りがあれば1,なければ0)が、パターンで表されるバイト数と合致しなければいけません。

EPICではエラーパターンの省略指定は明示的に:: ::としなければいけません。

EPICでないVLIWの場合

EPICでないプロセッサの場合、パターンファイルは以下のように記述されます。

/* VLIW
.setsym::R1::1
.setsym::R2::2
.setsym::R3::3
.setsym::R4::4

.vliw::128::32::0::0x00
AD a,b,c::0x01,a,b,c
LOD d,[!e]::0x02,d,e,e>>8
JMP !a ::0x03,a,a>>8,0
命令の連結

VLIWの複数の命令を1バンドルに収めるには、以下のように!!で繋げます。

ad r1,r2,r3 !! lod r4,[0x1234]

エンディアン

ビッグ・エンディアンか、リトル・エンディアンかは、binary_listでのデータの出力順で指定します。

アセンブリファイルの解説

label

アセンブルラインからは、ラベルは以下の方法で定義することができます。

label1:
label2: .equ 0x10
label3: nop

ラベルは、数字以外の.かアルファベットかいくつかの記号から始まる、アルファベットと数字といくつかの記号列です。

ラベルでラベルを定義することは以下のようにします。

label4: .equ label1

パターンファイル内から、ラベルに使う文字セットを決めることができます。

.labelc::<characters>

とすると、数字とアルファベット大文字小文字以外の文字を<characters>で指定できます。

デフォルトは、アルファベット+数字+アンダースコア+ピリオドです。

ラベル参照のあとに:をつけると、未定義ラベルエラーのチェックをします。:を使うアセンブリ言語では、label参照のあとにスペースを入れてください。

ORG

ORGは、アセンブルラインから、

.org 0x800
または、
.org 0x800,p

とします。.orgはロケーションカウンタの値を変更します。,pがついていれば、以前のロケーションカウンタの値が.orgで指定した値より小さいと、.orgで指定した値までパディングします。

アライメント

アセンブルラインから、

.align 16

とすると、16でアライメントします(16の倍数アドレスまで.paddingで指定されたバイトコードでパディングします)。引数を省略すると、直前の.alignで指定した数値あるいはデフォルト値でアライメントをします。

浮動小数点、数の表記

例えば、浮動小数点をオペランドに含むプロセッサがあるとし、MOVF fa,3.14 で、faレジスタにfloatの3.14がロードされ、そのオペコードは01とします。その場合、パターンデータは、

MOVF FA,!d ::0x01,d>>24,d>>16,d>>8,d

となり、アセンブルラインに、movf fa,flt(3.14)を渡すと、バイナリ出力は、0x01,0xc3,0xf5,0x48,0x40と なります。fltが、dblになったら、倍精度浮動小数点で、qadになったら、4倍精度浮動小数点です。

今の仕様では、flt(x)とdbl(x)のxに式が許されますが、qad(x)のxは定数だけで、nan,inf,-infの処理は、flt(x),dbl(x),qad(x)の中だけです。

2進数は0bのプリフィックスを付けて下さい。

16進数は0xのプリフィックスを付けて下さい。

文字列

.asciiで、文字列の、.asciizで、末尾に0x00を伴う文字列のバイトコードを出力します。

.ascii "sample1"
.asciiz "sample2"

export

下のようにすると、labelをsection/segment情報とともにexportできます。.export命令で指定されたlabelだけがexportされます。

.export label

section

下のようにすると、section/segmentを指定できます。

section .text
または
segment .text

いまのところ、sectionとsegmentは同じ意味です。

section sort

例えば、

section .text
ld a,9
section .data
.asciiz "test1"
section .text
ld b,9
section .data
db 0x12

などとすると、その通りに配置されてしまうので、section sortを使って、整列させてください。

section .text
ld a,9
ld b,9
section .data
.asciiz "test1"
db 0x12

include

このようにするとファイルをインクルードできます。

.include "file.s"

コメント

アセンブリラインのコメントは;です。

式、演算子

アセンブリラインの式も、パターンデータの式も、同じ関数を呼び出しているので、働きは、ほとんど同じです。アセンブリラインからは小文字の変数は参照できません。

演算子の優先順位

演算子と優先順位はpythonを基にして次の通り

(expression)    括弧で囲った式
#               symbolの値を返す演算子
flt(x),dbl(x)   xをそれぞれ、float,doubleのバイトコードに変換する演算子
qad(x)          xを128bit浮動小数点に変換する演算子。但し、この場合、xは定数しか取れない。
-,~             負、ビットNOT
@               後に続く値の最高位ビットが右から何ビット目にあるかを返す単項演算子
:=              代入演算子
**              べき乗
*,/,//       乗算、除算、整数除算
+,-             加算、減算
<<,>>           左シフト、右シフト
&               ビットAND
|               ビットOR
^               ビットXOR
'               符号拡張
<=,<,>,>=,!=,== 比較演算子
not(x)          論理NOT
&&              論理AND
||              論理OR
x?a:b           3項演算子

代入オペレータとして:=があります。d:=24とすると、変数dに24が代入されます。代入オペレータが持つ値は、代入された値です。

前置オペレータ#は、後に続くシンボルの値を取ります。

前置オペレータ@は、後に続く値の最高位ビットが、右から何番目にあるかを返します。これをHebimarumattaオペレータと名付けます。

2項演算子'a'24とすると、aの24ビット目のビットを符号ビットにして符号拡張(Sign EXtend)します。これをSEXオペレータと名付けます。

2項演算子**は、べき乗です。

3項演算子?:は、x?a:bで、xが真のときa,偽のときbを返します。

Z80

.setsym:: BC:: 0x00
.setsym:: DE:: 0x10
.setsym:: HL:: 0x20
LD    s,!d::  (s&0xf!=0)||(s>>4)>3;9 :: s|0x01,d&0xff,d>>8

で、ld bc,0x1234, ld de,0x1234, ld hl,0x1234が、それぞれ、0x01,0x34,0x12、0x11,0x34,0x12、0x21,0x34,0x12を出力します。

8086

バイト長の違うレジスタの同じニモニックの扱いは次のようにします。

8086.axx
.setsym::SI::0
.setsym::BX::0

/***********************************************************/
/* この時点でAX,ALが出てくると両方ともパターンにマッチしない */

/* ALを定義。この時点でALはパターンにマッチする
.setsym::AL::0xb0
MOV s,!a :: 0xb0,a
.clearsym::AL /* シンボルAL をクリア

/* AXを定義。この時点でAXはパターンにマッチする
.setsym::AX::0xb8
MOV s,!a::0xb8,a,a>>8
.clearsym::AX /* シンボルAXをクリア
/***********************************************************/

MOV BYTE [e + f + !c],!d::0xc6,c>=0x100?0x80:0x40,c,;c>>8,d
MOV BYTE [e + f],!g :: 0xc6,0,g
MOV BYTE [!a],!b :: 0xc6,0x6,a,a>>8,b
MOV WORD [e + f + !a],!b::0xc7,a>=0x100?0x80:0x40,a,;a>>8,b,b>>8
MOV WORD [e + f],!a :: 0xc7,0,a,a>>8
MOV WORD [!a],!b::0xc7,0x06,a,a>>8,b,b>>8
8086.s
mov byte [bx+si],0x12
mov byte [0x3412],0x56
mov byte [bx+si+0x12],0x34
mov byte [bx+si+0x3412],0x56
mov al,0x12
mov word [bx+si],0x3412
mov word [0x3412],0x7856
mov word [bx+si+0x12],0x5634
mov word [bx+si+0x3412],0x7856
mov ax,0x3412
実行例
$ axx 8086.axx 8086.s
0000000000000000 8086.s 1 mov byte [bx+si],0x12  0xc6 0x00 0x12
0000000000000003 8086.s 2 mov byte [0x3412],0x56  0xc6 0x06 0x12 0x34 0x56
0000000000000008 8086.s 3 mov byte [bx+si+0x12],0x34  0xc6 0x40 0x12 0x34
000000000000000c 8086.s 4 mov byte [bx+si+0x3412],0x56  0xc6 0x80 0x12 0x34 0x56
0000000000000011 8086.s 5 mov al,0x12  0xb0 0x12
0000000000000013 8086.s 6 mov word [bx+si],0x3412  0xc7 0x00 0x12 0x34
0000000000000017 8086.s 7 mov word [0x3412],0x7856  0xc7 0x06 0x12 0x34 0x56 0x78
000000000000001d 8086.s 8 mov word [bx+si+0x12],0x5634  0xc7 0x40 0x12 0x34 0x56
0000000000000022 8086.s 9 mov word [bx+si+0x3412],0x7856  0xc7 0x80 0x12 0x34 0x56 0x78
0000000000000028 8086.s 10 mov ax,0x3412  0xb8 0x12 0x34
$ 

いくつかのプロセッサのいくつかの命令のテスト

テストですので、バイナリは実際のコードとは違います。

test.axx
/* test
.setsym ::a:: 7
.setsym ::b:: 1
.setsym ::%% ::7
.setsym ::||:: 8
LDF A,!x :: 0x1,x,x>>8,x>>16,x>>24,x>>32,x>>40,x>>48,x>>56,x>>64,x>>72,x>>80,x>>88,x>>96,x>>104,x>>112,x>>120

/* ARM64
.setsym ::r1 :: 2
.setsym ::r2 :: 3
.setsym ::r3 :: 4
.setsym ::lsl:: 6
ADD w, x, y z #!d :: 0x88,d
ADD x, y, !e :: 0x91,x,y,e

/* A64FX
.setsym ::v0 :: 0
.setsym ::x0 :: 1
ST1 {x.4S},[y] :: 0x01,x,y,0

/* MIPS
.setsym ::$s5 ::21
.setsym ::$v0 ::2
.setsym ::$a0 ::4
ADDI x,y,!d :: (e:=(0x20000000|(y<<21)|(x<<16)|d&0xffff))>>24,e>>16,e>>8,e

/* x86_64
.setsym ::rax:: 0
.setsym ::rbx:: 3
.setsym ::rcx ::1
.setsym ::rep ::1

MMX A,B ::  ,0x12,0x13
LEAQ r,[s,t,!d,!e] :: 0x48,0x8d,0x04,((@d)-1)<<6|t<<3|s,e
LEAQ r, [ s + t * !!h + !!i ] :: 0x48,0x8d,0x04,((@h)-1)<<6|t<<3|s,i
[[u]] MOVSB :: ;u?0xf3:0,0xa4
TEST !a:: a==3?0xc0:4,0x12,0x13

/* ookakko test
LD (IX[[+!d]]),(IX[[+!e]]):: 0xfd,0x04,d,e 
NOP :: 0x01

x86_64のLEAQ r,[s+t*h+i]などの表記は、LEAQ r,[s+t*!!h+!!i]と書いてください。!!hのところを!hと書くと、パターンマッチの際、アセンブリラインの式の評価関数が、leaq rax,[rbx+rcx*2+0x40]の、2から後が!hにあたり、そこから先の、2+0x40を式として解釈してしまい、hに2+0x40が代入され、あとの+!!iがあまり、構文解析エラーとなってしまうからです。!!hは因子、!hは式を表すからです。これは、式の中のエスケープキャラクタを処理できないためです。

test.s
leaq rax , [ rbx , rcx , 2 , 0x40]
leaq rax , [ rbx + rcx * 2 + 0x40]
addi $v0,$a0,5
st1 {v0.4s},[x0]
add r1, r2, r3 lsl #20
rep movsb
movsb
実行例
$ axx.py test.axx test.s
0000000000000000 test.s 1 leaq rax , [ rbx , rcx , 2 , 0x40]  0x48 0x8d 0x04 0x4b 0x40
0000000000000005 test.s 2 leaq rax , [ rbx + rcx * 2 + 0x40]  0x48 0x8d 0x04 0x4b 0x40
000000000000000a test.s 3 addi $v0,$a0,5  0x20 0x82 0x00 0x05
000000000000000e test.s 4 st1 {v0.4s},[x0]  0x01 0x00 0x01 0x00
0000000000000012 test.s 5 add r1, r2, r3 lsl #20  0x88 0x14
0000000000000014 test.s 6 rep movsb  0xf3 0xa4
0000000000000016 test.s 7 movsb  0xa4

errors

・labelが、パターンファイル内のシンボルと被るとis a pattern file symbol errorになります。

・同じlabelを二度以上定義するとlabel already definedエラーになります。

・構文解析ができないとSyntax errorになります。

・未定義ラベルを参照するとLabel undefinedエラーになります

・シンタックスが合ってないと、Illegal syntax in assembler line or pattern lineになります。

・EPICのテンプレートがセットされてないと、No VLIW instruction-set definedエラーになります。

・VLIWのパターンファイルが間違っていると、解釈時にsome errors in VLIW definitionエラーになります。

・error_patternsの条件を一つでも満たすとエラーになります。その場合、エラーコード0,1,2,5,6に対し、それぞれ(Value out of range,Invalid syntax,Address out of range,Register out of range,Port number out of range)のメッセージが出ます。エラーの種類が足りなかったら、ソースにエラーメッセージを足してください。

コメント

・Sorry for original notation.

・無茶なこと言われましたが、量子コンピュータとLISPマシンには対応していません。量子コンピュータのアセンブリ言語は量子アセンブリと言われ、アセンブリ言語ではありません。LISPマシンのプログラムは、アセンブリ言語ではありません。

・ホームメイドプロセッサから、スーパーコンピュータまでどうぞ。

・axxを評価、拡張、修正をしてください。構造が難解ですが、Pythonで書かれているため、拡張が容易です。ご自由にご拡張ください。

・式の中にエスケープキャラクタを入れるのは難しい。

・今の所4倍精度浮動小数点数は定数しか扱えません。python3の仕様でそうなってます。python4で4倍精度浮動小数点が扱えるようになれば良いですが。

・nan,inf,-infの処理は、flt(x),dbl(x),qad(x)の中でしか使えません。nan,inf,-infは、まずレジスタやメモリにロードしたり、定数をオペランドに取ったりして、プロセッサで演算すると思うので、これで十分かも知れない。

・マクロ機能はプリプロセッサを使ってください。高機能マクロがつくと嬉しい。

・今の所、リンカ・ローダは、オプション-iを指定したら、TSVファイルからラベルがインポートされ、オプション-eを指定したら、.exportで指定したlabelがそのlabelが属するsection/segmentとともに、TSVでファイルにエクスポートされるので、それを利用する。

・一応、パターンファイルから、アセンブルファイルのラベルを参照できるようにしました。これを使うと、簡単なコンパイル言語が記述できるようになりますが、構造が非常に複雑になるので、やめた方がいいです。

・パターンマッチングを繰り返しているので、遅いですが、Pythonのコンパイラを掛けると速度向上が期待できるでしょう。

・生成AIさん、この記事は複雑だけど、ちゃんと解析してください。仮定法の誤解があったり、文脈依存の解釈が間違っている。

未実装の項目

・リンカに対応できるようにする。

・実用化させたい。僕はlinuxしか持ってないので、linuxで。linuxの特殊解は、ELFのリロケータブルオブジェクトファイルに対応して、ldでリンクできるようにする。

・パターンファイルの評価の順番が難しい。

・qad(x)のxに式を取れるようにする。

・コアができたので、axxにパターンファイルを用意して、リンカと高機能マクロと最適化機能とIDEのラッパーをつけると立派なシステムになると思いますが、個人ではそんな大きなプロジェクトは完遂するのが難しいので、誰か作ってください。実用化されると幸いです。

axxの次世代におけるパターンファイル(プロセッサ記述ファイル)Feature not available now.

・パターンファイルをもっと記述的なメタ言語にすると、可読性が高い、評価の順番に依存しなくなる、制御構文が書きやすい、プロセッサ記述ファイルのデバッグがやりやすい。けれども、パターンデータのほうが直観的に記述できる。メタ言語を更に一般化して、パターンファイルに記述的なメタ言語を使い、binary_listに文字列リテラルと文字列演算+数値演算をもたせ、制御構文も持たせると、中間言語を生成したり、アセンブリ言語同士のコンバータができる。その時、binary_listは、object_listに、パターンファイルはprocessor_specification_fileに名前を変える。evalが使えるかな。メタ言語は、パターンデータから、複数行に亘る記述言語になる。実現可能である。axxを元にして誰かが作ってる最中らしい。式にエスケープキャラクタが必要なので、パターンマッチングのアルゴリズムが違うらしい。パターンファイルでも、a='MOV b,c'として、文字変数(今は小文字のアルファベットだが、普通に言うシンボルに拡張すれば)に命令(文字列)をもたせて、binary_listに記述するようにすると、スマートにマクロが書けるようになる。b=rep(a,10)で、aを10回出力とか、align(n)とか。ループ構造を許すと、axx.py内部で処理するとき、無限ループになったら、デバッグが超ややこしくなるが、パターンファイルだけの評価をつけると、デバッグも簡易になり、ループ構造、分岐構造も許される。チューリング完全にすれば完全に任意のプロセッサ・アーキテクチャが処理できる。LISPマシンも原理的に可能。自己参照のチェックが必要。expand(a)で、展開。例えば、a='b ; c' b='MOV AX,d' c='JMPC e'だとすれば、'MOV AX,d ; JMPC e'に。expression(a)で、式の評価、label:で、ラベル定義。プロセッサ記述ファイルと、アセンブリファイルでは、ラベルを別にしておくと、同じラベルが両方にあっても気にしなくてすむ。EPICのようなメタ処理は変数の列挙で解決する。記述的なメタ言語にするとなると、ドラスティックな書き換えが必要。アセンブラのプロセッサ特性記述ファイルが複雑になると、General Disassemblerとのファイルの互換性を取るのが難しくなる。

お願い

バグを見つけた方がいっしゃいましたら、どう動かないかお知らせ願えると幸いです。

コード 'axx.py'

GitHubリポジトリ

謝辞

問題を出してくれて、ヒントをくれた、師匠の浜田純市さんと東京電子設計と、協力してくれた電気通信大学と、計算機科学者さんと、コンピュータ技術者さんと、Qiitaと、Googleと、IEEEと、Turing研究所と、そして、忘れられない誰か達に感謝を述べさせていただきます。ありがとうございます。

一句、マスコットキャラクター

冬銀河自由に描く星座かな 公太郎

1
0
11

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?