pdp11のディスアセンブラ

日曜日に池袋バイナリ勉強会に行ってきました。
で、pdp11のエミュレータのようなものの手順書を貰ったのだけど、
Mountain LionにしたばっかりでMacPorts動かないんですけど、、、。
makeとか出来ないんですけど、、、。
って感じだったので、コマンド表みたいなものを元に
ディスアセンブラを作ってみてました。

せっかくなので、Scalaのパターンマッチで書けば奇麗に書けるんじゃないか?
ってことで、書いてみたのが以下のソースです。

テストを途中まで書いていて、時間切れになったので、途中までしかテスト出来てませんが、結構奇麗に書けたんじゃないかと思います。

実行方法は、scalac pdp11.scalaコンパイルして、 scala pdp11.disasmでテストが動きます。

package pdp11

object disasm {
  //           4      6      6 = 16 bit
  case class C(h:Int, m:Int, l:Int)

  def apply(o:Any):String = {
    o match {
    case C(0, 000, 000) => "HALT"
    case C(0, 000, 001) => "WAIT"
    case C(0, 000, 002) => "RTI"
    case C(0, 000, 003) => "BPT"
    case C(0, 000, 004) => "IOT"
    case C(0, 000, 005) => "RESET"
    case C(0, 000, 006) => "RTT"
    case C(0, 000, 007) => "(unused)"

    case C(0, 001,  dd) => "JMP " + dd
    case C(0, 002,   r) if (r < 010) => "RTS r" + r
    case C(0, 002,   r) if (010 <= r && r <= 027) => "(unused)"
    case C(0, 002,   n) if (030 <= n && n <= 037) => "SPL " + (7 & n)
    case C(0, 002, 040) => "NOP"
    case C(0, 002,   _) => "cond codes"
    case C(0, 003,  dd) => "SWAB " + dd

    case C(0, 004, xxx) => "BR " + xxx
    case C(0, 010, xxx) => "BNE " + xxx
    case C(0, 014, xxx) => "BEQ " + xxx
    case C(0, 020, xxx) => "BGE " + xxx
    case C(0, 024, xxx) => "BLT " + xxx
    case C(0, 030, xxx) => "BGT " + xxx
    case C(0, 034, xxx) => "BLE " + xxx
    case C(0,   r,  dd) if ((070 & r) == 040) => "JSR " + (r & 7) + ", " + dd

    case C(0, 050,  dd) => "CLR " + dd
    case C(0, 051,  dd) => "COM " + dd
    case C(0, 052,  dd) => "INC " + dd
    case C(0, 053,  dd) => "DEC " + dd
    case C(0, 054,  dd) => "NEG " + dd
    case C(0, 055,  dd) => "ADC " + dd
    case C(0, 056,  dd) => "SBC " + dd
    case C(0, 057,  dd) => "TST " + dd


    case C(0, 060,  dd) => "ROR " + dd
    case C(0, 061,  dd) => "ROL " + dd
    case C(0, 062,  dd) => "ASR " + dd
    case C(0, 063,  dd) => "ASL " + dd
    case C(0, 064,  nn) => "MARK " + nn
    case C(0, 065,  ss) => "MFPI " + ss
    case C(0, 066,  dd) => "MTPI " + dd
    case C(0, 067,  dd) => "SXT " + dd
    case C(0,  d1,  d2) => "(unused)"


    case C(1,  ss,  dd) => "MOV " + ss + ", " + dd
    case C(2,  ss,  dd) => "CMP " + ss + ", " + dd
    case C(3,  ss,  dd) => "BIT " + ss + ", " + dd
    case C(4,  ss,  dd) => "BIC " + ss + ", " + dd
    case C(5,  ss,  dd) => "BIS " + ss + ", " + dd
    case C(6,  ss,  dd) => "ADD " + ss + ", " + dd

    case C(7,   r,  ss) if ((r & 070) == 000) => "MUL " + r + ", " + ss
    case C(7,   r,  ss) if ((r & 070) == 010) => "DIV " + (r & 7) + ", " + ss
    case C(7,   r,  ss) if ((r & 070) == 020) => "ASH " + (r & 7) + ", " + ss
    case C(7,   r,  ss) if ((r & 070) == 030) => "ASHC " + (r & 7) + ", " + ss
    case C(7,   r,  dd) if ((r & 070) == 040) => "XOR " + (r & 7) + ", " + dd
    case C(7, 050,   r) if ((r & 070) == 000) => "FADD " + (r & 7)
    case C(7, 050,   r) if ((r & 070) == 010) => "FSUB " + (r & 7)
    case C(7, 050,   r) if ((r & 070) == 020) => "FMUL " + (r & 7)
    case C(7, 050,   r) if ((r & 070) == 030) => "FDIV " + (r & 7)
    case C(7,   r,  nn) if ((r & 070) == 070) => "SOB " + r + "," + nn
    case C(7,  r1,  r2) => "(unused)"

    case C(8, 000, xxx) => "BPL " + xxx
    case C(8, 004, xxx) => "BMI " + xxx
    case C(8, 010, xxx) => "BHI " + xxx
    case C(8, 014, xxx) => "BLOS " + xxx
    case C(8, 020, xxx) => "BVC " + xxx
    case C(8, 024, xxx) => "BVS " + xxx
    case C(8, 030, xxx) => "BCC " + xxx
    case C(8, 034, xxx) => "BCS " + xxx
    case C(8,  v1,  v2) if(040 <= v1 && v1 <= 043) => "EMT"
    case C(8,  v1,  v2) if(044 <= v1 && v1 <= 047) => "TRAP"

    case C(8, 050,  dd) => "CLRB " + dd
    case C(8, 051,  dd) => "COMB " + dd
    case C(8, 052,  dd) => "INCB " + dd
    case C(8, 053,  dd) => "DECB " + dd
    case C(8, 054,  dd) => "NEGB " + dd
    case C(8, 055,  dd) => "ADCB " + dd
    case C(8, 056,  dd) => "SBCB " + dd
    case C(8, 057,  dd) => "TSTB " + dd
    case C(8, 060,  dd) => "RORB " + dd
    case C(8, 061,  dd) => "ROLB " + dd
    case C(8, 062,  dd) => "ASRB " + dd
    case C(8, 063,  dd) => "ASLB " + dd
    case C(8, 064,  dd) => "(unused)"
    case C(8, 065,  ss) => "MFPD " + ss
    case C(8, 066,  dd) => "MTPD " + dd
    case C(8,  d1,  d2) => "(unused)"

    case C(9,  ss,  dd) => "MOVB " + ss + ", " + dd
    case C(10, ss,  dd) => "CMPB " + ss + ", " + dd
    case C(11, ss,  dd) => "BITB " + ss + ", " + dd
    case C(12, ss,  dd) => "BICB " + ss + ", " + dd
    case C(13, ss,  dd) => "BISB " + ss + ", " + dd
    case C(14, ss,  dd) => "SUB " + ss + ", " + dd
    case C(15, d1,  d2) => "floating point " + d1 + ", " + d2
    }
  }

  var count = 0
  var ok = 0
  var ng = 0
  def test(o:C, expected:String) {
    val v = disasm(o)
    if (v != expected) {
      println("error " + o + " expected is " + expected + " but found '" + v + "'.")
      ng += 1
    } else {
      ok += 1
    }
    count += 1
    
  }
 
  def main(argv:Array[String]) {
    test(C(0,0,0),"HALT")
    test(C(0,0,1),"WAIT")
    test(C(0,0,2),"RTI")
    test(C(0,0,3),"BPT")
    test(C(0,0,4),"IOT")
    test(C(0,0,5),"RESET")
    test(C(0,0,6),"RTT")
    test(C(0,0,7),"(unused)")
    test(C(0,1,7),"JMP 7")
    test(C(0,2,1),"RTS r1")
    test(C(0,2,2),"RTS r2")
    test(C(0,2,3),"RTS r3")
    test(C(0,2,4),"RTS r4")
    test(C(0,2,8),"(unused)")
    test(C(0,2,010),"(unused)")
    test(C(0,2,027),"(unused)")
    test(C(0,2,030),"SPL 0")
    test(C(0,2,031),"SPL 1")
    test(C(0,2,037),"SPL 7")
    test(C(0,2,040),"NOP")
    test(C(0,2,041),"cond codes")
    test(C(0,2,077),"cond codes")
    test(C(0,3,000),"SWAB 0")
    test(C(0,3,077),"SWAB "+077)
    test(C(0,4,000),"BR 0")
    test(C(0,4,077),"BR "+077)
    test(C(0,010,000),"BNE 0")
    test(C(0,010,077),"BNE "+077)
    test(C(0,014,000),"BEQ 0")
    test(C(0,014,077),"BEQ "+077)
    test(C(0,020,000),"BGE 0")
    test(C(0,020,077),"BGE "+077)
    test(C(0,024,000),"BLT 0")
    test(C(0,024,077),"BLT "+077)
    test(C(0,030,000),"BGT 0")
    test(C(0,030,077),"BGT "+077)
    test(C(0,034,000),"BLE 0")
    test(C(0,034,077),"BLE "+077)
    test(C(0,040,000),"JSR 0, 0")
    test(C(0,047,077),"JSR 7, "+077)
    test(C(0,050,000),"CLR 0")
    test(C(0,050,077),"CLR "+077)
    test(C(0,051,000),"COM 0")
    test(C(0,051,077),"COM "+077)
    test(C(0,052,000),"INC 0")
    test(C(0,052,077),"INC "+077)
    test(C(0,053,000),"DEC 0")
    test(C(0,053,077),"DEC "+077)
    test(C(0,054,000),"NEG 0")
    test(C(0,054,077),"NEG "+077)
    test(C(0,055,000),"ADC 0")
    test(C(0,055,077),"ADC "+077)
    test(C(0,056,000),"SBC 0")
    test(C(0,056,077),"SBC "+077)
    test(C(0,057,000),"TST 0")
    test(C(0,057,077),"TST "+077)

    test(C(0,060,000),"ROR 0")
    test(C(0,060,077),"ROR "+077)
    test(C(0,061,000),"ROL 0")
    test(C(0,061,077),"ROL "+077)
    test(C(0,062,000),"ASR 0")
    test(C(0,062,077),"ASR "+077)
    test(C(0,063,000),"ASL 0")
    test(C(0,063,077),"ASL "+077)
    test(C(0,064,000),"MARK 0")
    test(C(0,064,077),"MARK "+077)
    test(C(0,065,000),"MFPI 0")
    test(C(0,065,077),"MFPI "+077)
    test(C(0,066,000),"MTPI 0")
    test(C(0,066,077),"MTPI "+077)
    test(C(0,067,000),"SXT 0")
    test(C(0,067,077),"SXT "+077)
    test(C(0,070,000),"(unused)")
    test(C(0,070,077),"(unused)")
    test(C(0,077,000),"(unused)")
    test(C(0,077,077),"(unused)")


    test(C(1,000,000),"MOV 0, 0")
    test(C(1,077,077),"MOV "+077+", "+077)
    test(C(2,000,000),"CMP 0, 0")
    test(C(2,077,077),"CMP "+077+", "+077)
    test(C(3,000,000),"BIT 0, 0")
    test(C(3,077,077),"BIT "+077+", "+077)
    test(C(4,000,000),"BIC 0, 0")
    test(C(4,077,077),"BIC "+077+", "+077)
    test(C(5,000,000),"BIS 0, 0")
    test(C(5,077,077),"BIS "+077+", "+077)
    test(C(6,000,000),"ADD 0, 0")
    test(C(6,077,077),"ADD "+077+", "+077)

    test(C(7,000,000),"MUL 0, 0")
    test(C(7,007,077),"MUL 7, "+077)
    test(C(7,010,000),"DIV 0, 0")
    test(C(7,017,077),"DIV 7, "+077)
    test(C(7,020,000),"ASH 0, 0")
    test(C(7,027,077),"ASH 7, "+077)
    test(C(7,030,000),"ASHC 0, 0")
    test(C(7,037,077),"ASHC 7, "+077)
    test(C(7,040,000),"XOR 0, 0")
    test(C(7,047,077),"XOR 7, "+077)


    test(C(7,050,000),"FADD 0")
    test(C(7,050,007),"FADD 7")
    test(C(7,050,010),"FSUB 0")
    test(C(7,050,017),"FSUB 7")
    test(C(7,050,020),"FMUL 0")
    test(C(7,050,027),"FMUL 7")
    test(C(7,050,030),"FDIV 0")
    test(C(7,050,037),"FDIV 7")
    
    test(C(7,050,040),"(unused)")
    test(C(7,050,077),"(unused)")
    test(C(7,067,000),"(unused)")
    test(C(7,067,077),"(unused)")
    
    test(C(010,000,000),"BPL 0")
    test(C(010,000,077),"BPL "+077)
    test(C(010,004,000),"BMI 0")
    test(C(010,004,077),"BMI "+077)
    test(C(010,010,000),"BHI 0")
    test(C(010,010,077),"BHI "+077)
    test(C(010,014,000),"BLOS 0")
    test(C(010,014,077),"BLOS "+077)
    test(C(010,020,000),"BVC 0")
    test(C(010,020,077),"BVC "+077)
    test(C(010,024,000),"BVS 0")
    test(C(010,024,077),"BVS "+077)
    test(C(010,030,000),"BCC 0")
    test(C(010,030,077),"BCC "+077)
    test(C(010,034,000),"BCS 0")
    test(C(010,034,077),"BCS "+077)

    test(C(010,040,000),"EMT")
    test(C(010,043,077),"EMT")
    test(C(010,044,000),"TRAP")
    test(C(010,047,077),"TRAP")
    
    test(C(010,050,000),"CLRB "+0)
    test(C(010,050,077),"CLRB "+077)
    test(C(010,051,000),"COMB "+0)
    test(C(010,051,077),"COMB "+077)
    test(C(010,052,000),"INCB "+0)
    test(C(010,052,077),"INCB "+077)
    test(C(010,053,000),"DECB "+0)
    test(C(010,053,077),"DECB "+077)
    test(C(010,054,000),"NEGB "+0)
    test(C(010,054,077),"NEGB "+077)
    test(C(010,055,000),"ADCB "+0)
    test(C(010,055,077),"ADCB "+077)
    test(C(010,056,000),"SBCB "+0)
    test(C(010,056,077),"SBCB "+077)
    test(C(010,057,000),"TSTB "+0)
    test(C(010,057,077),"TSTB "+077)

    test(C(010,060,000),"RORB "+0)
    test(C(010,060,077),"RORB "+077)
    test(C(010,061,000),"ROLB "+0)
    test(C(010,061,077),"ROLB "+077)
    test(C(010,062,000),"ASRB "+0)
    test(C(010,062,077),"ASRB "+077)
    test(C(010,063,000),"ASLB "+0)
    test(C(010,063,077),"ASLB "+077)
//    test(C(010,064,000),"MTPS "+0)
//    test(C(010,064,077),"MTPS "+077)
    test(C(010,064,000),"(unused)")
    test(C(010,064,077),"(unused)")
    test(C(010,065,000),"MFPD "+0)
    test(C(010,065,077),"MFPD "+077)
    test(C(010,066,000),"MTPD "+0)
    test(C(010,066,077),"MTPD "+077)
//    test(C(010,067,000),"MFPS "+0)
//    test(C(010,067,077),"MFPS "+077)
    test(C(010,067,000),"(unused)")
    test(C(010,067,077),"(unused)")
 
    test(C(011,000,000),"MOVB "+0+", "+0)
    test(C(011,077,077),"MOVB "+077+", "+077)
    test(C(012,000,000),"CMPB "+0+", "+0)
    test(C(012,077,077),"CMPB "+077+", "+077)
    test(C(013,000,000),"BITB "+0+", "+0)
    test(C(013,077,077),"BITB "+077+", "+077)
    test(C(014,000,000),"BICB "+0+", "+0)
    test(C(014,077,077),"BICB "+077+", "+077)
    test(C(015,000,000),"BISB "+0+", "+0)
    test(C(015,077,077),"BISB "+077+", "+077)
    test(C(016,000,000),"SUB "+0+", "+0)
    test(C(016,077,077),"SUB "+077+", "+077)
   /* 
    test(C(017,000,000),"CFCC")
    test(C(017,000,001),"SETF")
    test(C(017,000,002),"SETI")
    test(C(017,000,011),"SETD")
    test(C(017,000,012),"SETL")
    test(C(017,001,000),"LDFPS "+0)
    test(C(017,001,077),"LDFPS "+077)
    test(C(017,002,000),"STFPS "+0)
    test(C(017,002,077),"STFPS "+077)
    test(C(017,003,000),"STST "+0)
    test(C(017,003,077),"STST "+077)
    test(C(017,004,000),"CLRF "+0)
    test(C(017,004,077),"CLRF "+077)
    test(C(017,005,000),"TSTF "+0)
    test(C(017,005,077),"TSTF "+077)
    test(C(017,006,000),"ABSF "+0)
    test(C(017,006,077),"ABSF "+077)
    test(C(017,007,000),"NEGF "+0)
    test(C(017,007,077),"NEGF "+077)
    test(C(017,010,000),"MULF "+0+", "+000)
    test(C(017,013,077),"MULF "+3+", "+077)
    test(C(017,014,000),"MODF "+0+", "+000)
    test(C(017,017,077),"MODF "+3+", "+077)

    test(C(017,020,000),"ADDF "+0+", "+000)
    test(C(017,023,077),"ADDF "+3+", "+077)
    test(C(017,024,000),"LDF "+0+", "+000)
    test(C(017,027,077),"LDF "+3+", "+077)

    test(C(017,030,000),"SUBF "+0+", "+000)
    test(C(017,033,077),"SUBF "+3+", "+077)
    test(C(017,034,000),"CMPF "+0+", "+000)
    test(C(017,037,077),"CMPF "+3+", "+077)

    test(C(017,040,000),"STF "+0+", "+000)
    test(C(017,043,077),"STF "+3+", "+077)
    test(C(017,044,000),"DIF "+0+", "+000)
    test(C(017,047,077),"DIF "+3+", "+077)

    test(C(017,050,000),"STEXP "+0+", "+000)
    test(C(017,053,077),"STEXP "+3+", "+077)
    test(C(017,054,000),"STCFI "+0+", "+000)
    test(C(017,057,077),"STCFI "+3+", "+077)

    test(C(017,060,000),"STCFD "+0+", "+000)
    test(C(017,063,077),"STCFD "+3+", "+077)
    test(C(017,064,000),"LDEXP "+0+", "+000)
    test(C(017,067,077),"LDEXP "+3+", "+077)

    test(C(017,070,000),"LDCIF "+0+", "+000)
    test(C(017,073,077),"LDCIF "+3+", "+077)
    test(C(017,074,000),"LDCDF "+0+", "+000)
    test(C(017,077,077),"LDCDF "+3+", "+077)
*/
    test(C(017,000,000),"floating point "+0+", " + 000)
    test(C(017,000,001),"floating point "+0+", " + 001)
    test(C(017,000,002),"floating point "+0+", " + 002)
    test(C(017,000,011),"floating point "+0+", " + 011)
    test(C(017,000,012),"floating point "+0+", " + 012)
    test(C(017,001,000),"floating point "+1+", "+0)
    test(C(017,001,077),"floating point "+1+", "+077)
    test(C(017,002,000),"floating point "+2+", "+0)
    test(C(017,002,077),"floating point "+2+", "+077)
    test(C(017,003,000),"floating point "+3+", "+0)
    test(C(017,003,077),"floating point "+3+", "+077)
    test(C(017,004,000),"floating point "+4+", "+0)
    test(C(017,004,077),"floating point "+4+", "+077)
    test(C(017,005,000),"floating point "+5+", "+0)
    test(C(017,005,077),"floating point "+5+", "+077)
    test(C(017,006,000),"floating point "+6+", "+0)
    test(C(017,006,077),"floating point "+6+", "+077)
    test(C(017,007,000),"floating point "+7+", "+0)
    test(C(017,007,077),"floating point "+7+", "+077)
    test(C(017,077,077),"floating point "+077+", "+077)

    println("test " + count + " ok " + ok + " ng " + ng)
  }

}