###### tags: `RCWT` `Wiki` # RCWT Wiki 最終更新2020/03/28 github: [C++](https://github.com/sKyrBBit/NoCMake), [Rust](https://github.com/sKyrBBit/RRCWT) **(注)** C++での実装とRustでの実装ではフォーマットおよび命令セットが異なっている。TODO 統一 ## 期限 次回のプラサミ ## Summary RCWTは言語処理系における使用を目的としたVMであり - レジスタマシン - CISC の特徴を持つ。また命令セットは - 32bit - 3番地コード を基本としている。RCWTは **R**esister Machine, **C**ISC, **W**ord Code, **T**hree-Address Codeの頭文字をとったものである。設計方針はsimple and friendly。フロントエンドとしてrlispおよびincrementalを開発している(未完成)。 ## How to use 必要なツールは以下 - Git - Gnu Make - Clang - a processor for Rust - a processor for Java ``` 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 ``` ## ロード 以下の手続きを順に実行する - initialize - load - setup ### initialize 目的:直前にロードしたファイルが実行中のロードに影響を与えないようにする 機能:ロード時に使用されるメモリやレジスタを初期化する ### load 目的:プログラムをVMにとって実行可能な形式にする、アドレスをメモリに対する一意な添字にする 機能:プログラムをファイルからメモリに読み込む、シンボルを再配置しリンクする **(注)** 読み込み時にリンクするのが望ましいが、不可能または何らかの目的でリンクすべきでないという場合は、実行時そのシンボルが初めて参照されるまでに解決することが保障されていればよい(実行時リンクはdirect-threading codeでは実現不可能?) ### setup 目的:円滑にプログラムを実行できる状態に整える 機能:エントリーポイントを調整する、セットアップコードを生成する ## リンク 以下の手続きを順に実行する - load - resolve ### resolve 目的:シンボルが実際のアドレスを指すことを保証する 機能:シンボルテーブル、再配置アドレスにパッチをあてる ### 命令 32bitの固定長であり、3番地コードを基本としている。`0xaabbccdd`という命令の場合、`aa`が命令の種類を定め、`bb`, `cc`, `dd`は命令の引数として扱われる。引数の個数が3より少ない場合、`00`が与えられることが求められる。 例:`r1 = r2 + r3`は`0x10010203` という`addr`命令で表せる。 型を表す文字を加える場合は接頭詞、機能を表す文字を加える場合は接尾詞とする。 #### 接尾詞 - Register 右辺がレジスタ - Immediate 右辺が即値 - Lock Free 他の処理が割り込まない #### 命令セット ``` /* 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, ``` ## Note - リトルエンディアンを優先してサポートしている。 - JITコンパイルにはClangが必要である。 ## TODO - 関数・クラスの実装 - ネイティブ呼び出し(dll) - コメントを増やす - DOC 目的 - DOC 動機/背景 - DOC Constrains ```yaml # 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"] } ``` ![](https://i.imgur.com/EINPj0G.png) ## TableGen 文献が少ないため仕様不明。以下はきつねさんのほぼ写経。 ```tablegen // 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>; ```