RCWT
Wiki
最終更新2020/03/28
github: C++, Rust
(注) C++での実装とRustでの実装ではフォーマットおよび命令セットが異なっている。TODO 統一
次回のプラサミ
RCWTは言語処理系における使用を目的としたVMであり
の特徴を持つ。また命令セットは
を基本としている。RCWTは Resister Machine, CISC, Word Code, Three-Address Codeの頭文字をとったものである。設計方針はsimple and friendly。フロントエンドとしてrlispおよびincrementalを開発している(未完成)。
必要なツールは以下
commands start with '$', but comments don't
clone
$ git clone https://github.com/sKyrBBit/RRCWT
$ cd RRCWT
build
$ make build
windows help
$ rrcwt -h
linux help
$ ./rrcwt -h
以下の手続きを順に実行する
目的:直前にロードしたファイルが実行中のロードに影響を与えないようにする
機能:ロード時に使用されるメモリやレジスタを初期化する
目的:プログラムをVMにとって実行可能な形式にする、アドレスをメモリに対する一意な添字にする
機能:プログラムをファイルからメモリに読み込む、シンボルを再配置しリンクする
(注) 読み込み時にリンクするのが望ましいが、不可能または何らかの目的でリンクすべきでないという場合は、実行時そのシンボルが初めて参照されるまでに解決することが保障されていればよい(実行時リンクはdirect-threading codeでは実現不可能?)
目的:円滑にプログラムを実行できる状態に整える
機能:エントリーポイントを調整する、セットアップコードを生成する
以下の手続きを順に実行する
目的:シンボルが実際のアドレスを指すことを保証する
機能:シンボルテーブル、再配置アドレスにパッチをあてる
32bitの固定長であり、3番地コードを基本としている。0xaabbccdd
という命令の場合、aa
が命令の種類を定め、bb
, cc
, dd
は命令の引数として扱われる。引数の個数が3より少ない場合、00
が与えられることが求められる。
例:r1 = r2 + r3
は0x10010203
というaddr
命令で表せる。
型を表す文字を加える場合は接頭詞、機能を表す文字を加える場合は接尾詞とする。
/* 00 */ &&L_NOP, /* 01 */ &&L_EXIT, /* 02 */ &&L_BP, /* 03 */ &&L_NOP,
/* 04 */ &&L_STORE, /* 05 */ &&L_LOAD, /* 06 */ &&L_PUSH, /* 07 */ &&L_POP,
/* 08 */ &&L_COPY, /* 09 */ &&L_NOP, /* 0a */ &&L_SOUT, /* 0b */ &&L_CASL,
/* 0c */ &&L_ADDL, /* 0d */ &&L_SUBL, /* 0e */ &&L_ANDL, /* 0f */ &&L_ORL,
/* 10 */ &&L_ADDR, /* 11 */ &&L_SUBR, /* 12 */ &&L_MULR, /* 13 */ &&L_DIVR,
/* 14 */ &&L_ADDI, /* 15 */ &&L_SUBI, /* 16 */ &&L_MULI, /* 17 */ &&L_DIVI,
/* 18 */ &&L_GT, /* 19 */ &&L_GE, /* 1a */ &&L_EQ, /* 1b */ &&L_CONST,
/* 1c */ &&L_AND, /* 1d */ &&L_OR, /* 1e */ &&L_NOT, /* 1f */ &&L_NOP,
/* 20 */ &&L_GOTO, /* 21 */ &&L_BACK, /* 22 */ &&L_NOP, /* 23 */ &&L_NOP,
/* 24 */ &&L_IFGT, /* 25 */ &&L_IFGE, /* 26 */ &&L_IFEQ, /* 27 */ &&L_IOUT,
/* 28 */ &&L_IIN, /* 29 */ &&L_NEW, /* 2a */ &&L_SET, /* 2b */ &&L_GET,
/* 2c */ &&L_CALL, /* 2d */ &&L_RET, /* 2e */ &&L_NOP, /* 2f */ &&L_NOP,
/* 30 */ &&L_SHLR, /* 31 */ &&L_SHRR, /* 32 */ &&L_NOP, /* 33 */ &&L_NOP,
/* 34 */ &&L_SHLI, /* 35 */ &&L_SHRI, /* 36 */ &&L_NOP, /* 37 */ &&L_NOP,
# option
{ "-d": "--debug",
"-e": "--error",
"-w": "--warning",
"-p": "--prompt",
"-i": "--interpreter" }
# grammar
{ "atom": ["NUMBER", "SYMBOL", "boolean"],
"tuple": ["(s . s)"],
"boolean": ["#t", "#f"],
"s": ["atom", "tuple"] }
文献が少ないため仕様不明。以下はきつねさんのほぼ写経。
// registers
class RCWTReg<bits<4> num, string n>: Register<n> {
field bits<4> num;
let Namespace = "RCWT";
}
def R0: RCWTReg<0x0, "R0">, DwarfRegNum<[0x0]>;
def R1: RCWTReg<0x1, "R1">, DwarfRegNum<[0x1]>;
def R2: RCWTReg<0x2, "R2">, DwarfRegNum<[0x2]>;
def R3: RCWTReg<0x3, "R3">, DwarfRegNum<[0x3]>;
def R4: RCWTReg<0x4, "R4">, DwarfRegNum<[0x4]>;
def R5: RCWTReg<0x5, "R5">, DwarfRegNum<[0x5]>;
def R6: RCWTReg<0x6, "R6">, DwarfRegNum<[0x6]>;
def R7: RCWTReg<0x7, "R7">, DwarfRegNum<[0x7]>;
def R8: RCWTReg<0x8, "R8">, DwarfRegNum<[0x8]>;
def R9: RCWTReg<0x9, "R9">, DwarfRegNum<[0x9]>;
def Ra: RCWTReg<0xa, "Ra">, DwarfRegNum<[0xa]>;
def Rb: RCWTReg<0xb, "Rb">, DwarfRegNum<[0xb]>;
def Rc: RCWTReg<0xc, "Rc">, DwarfRegNum<[0xc]>;
def Rd: RCWTReg<0xd, "Rd">, DwarfRegNum<[0xd]>;
def Re: RCWTReg<0xd, "Re">, DwarfRegNum<[0xe]>;
def Rf: RCWTReg<0xf, "Rf">, DwarfRegNum<[0xf]>;
def RCWTRegClass: RegisterClass<"RCWT", [i32], 32, (add
R0, R1, R2, R3,
R4, R5, R6, R7,
R8, R9, Ra, Rb,
Rc, Rd, Re, Rf
)>;
// function unit
def ALU: FuncUnit;
def IICAlu: InstrItinclass;
def IICLoad: InstrItinClass;
def IICStore: InstrItinClass;
def IICBranch: InstrItinClass;
def IICPseudo: InstrItinClass;
def RCWTGenericItineraries: ProcessorItineraries<[ALU], [], [
InstrItinData<IICAlu, [InstrStage<1, [ALU]>]>
InstrItinData<IICLoad, [InstrStage<1, [ALU]>]>
InstrItinData<IICStore, [InstrStage<1, [ALU]>]>
InstrItinData<IICBranch, [InstrStage<1, [ALU]>]>
InstrItinData<IICPseudo, [InstrStage<1, [ALU]>]>
]
// calling convention
def CC_RCWT: ConllingConv<[
CCIfType<[i8, i16], CCPromoteToType<i32>>
]>
// target
def RCWTInstrInfo: InstrInfo;
def :Processor<"rcwt0.1.0", RCWTGenericItineraries, []>;
def RCWTAsmWriter: AsmWriter {
string AsmWriterClassName = "InstrPrinter";
bit isMCAsmWriter = 1;
}
def RCWT: target {
let InstructionSet = RCWTInstrInfo;
let AssemblyWriter = [RCWTAsmWriter];
}
// instruction
class Format<bit val> {
bit Value = val;
}
def Pseudo: Format<0>;
def ThreeAddress: Format<1>;
class RCWTInstr<dag outs, dag ins, string asmstr, list<dag> pattern, InstrItinClass itin,
Format f>: Instruction {
field bits<32> Instr;
Format Form = f;
bits<8> Opcode = 0;
let Namespace = "RCWT";
let Size = 4;
let Instr{31-24} = Opcode;
OutOperandList = outs;
InOperandList = ins;
let AsmString = asmstr;
let pattern = pattern;
let Itinerary = itin;
bit FormBit = Form.Value;
let DecoderNamespace = "RCWT";
field bits<32> SoftFail = 0;
}
class RCWTInstrThreeAddress<bits<8> op, dag outs, dag ins, string asmstr, list<dag> pattern,
InstrItinClass itin>: RCWTInstr<outs, ins, asmstr, pattern, itin, ThreeAddress> {
bits<8> op0;
bits<8> op1;
bits<8> op2;
let Opcode = op;
let Instr{23-16} = op0;
let Instr{15-8} = op1;
let Instr{7-0} = op2;
}
class RCWTPseudo<dag outs, dag ins, string asmstr, list<dag> pattern>: RCWTInstr<outs, ins,
asmstr, pattern, IICPseudo, Pseudo> {
let isCodeGenOnly = 1;
let isPseudo = 1;
}
class ArithLogicInstr<bits<8> op, string asmstr, SDNode OpNode, InstrItinClass itin,
RegisterClass rc>: RCWTInstrThreeAddress<op, (outs rc:$op0), (ins rc:$op1, rc:$op2),
!strconcat(asmstr, "\t$op0, $op1, $op2"), [(set rc:$op0, (OpNode rc:$op1, rc:$op2))], itin> {
}
def ADDR: ArithLogicInstr<0x10, "addr", add, IICAlu, RCWTRegClass>;
def SUBR: ArithLogicInstr<0x11, "subr", add, IICAlu, RCWTRegClass>;
def MULR: ArithLogicInstr<0x12, "mulr", add, IICAlu, RCWTRegClass>;
def DIVR: ArithLogicInstr<0x13, "divr", add, IICAlu, RCWTRegClass>;
def GT: ArithLogicInstr<0x14, "gt", add, IICAlu, RCWTRegClass>;
def GE: ArithLogicInstr<0x15, "ge", add, IICAlu, RCWTRegClass>;
def EQ: ArithLogicInstr<0x16, "eq", add, IICAlu, RCWTRegClass>;