Delphi で覚える SC61860

# はじめに
その昔 PC-1246 を買ったので SC61860 のマシン語にとんとご縁のなかった私がひょんな事で PC-1245 を入手したばっかりに今頃になって SC61860 のマシン語でプログラムを書きたくて (以下略)。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/ff6874e0-5b94-444c-4dc1-384f83c3bc8f.png)
あ、`SC61860` というのは SHARP の昔のポケコンの CPU の事です。

# どうやって覚えるか
実機で覚えようとすると暴走で再入力とかやってられないのでエミュレータ的な何かを作ればいいんじゃね？と思い立ち Delphi で 作ってみる事にした。ちょっと大きめの BrainFuck ですな。

## ソース

SC61860 のマシン語を覚えられるくらいの内容。

```pascal:uSC61860.pas
unit uSC61860;

interface

uses
  System.SysUtils, System.Classes;

type
  TSC61860 = record
  private
    function GetData: UInt8;
    function GetMem(Index: UInt16): UInt8;
    procedure SetMem(Index: UInt16; const Value: UInt8);
  public
    Memory: array [$0000..$FFFF] of UInt8;
    H: UInt8;                            // Internal Aux. Register
    P: UInt8;                            // Internal RAM Pointer
    Q: UInt8;                            // Internal RAM Pointer
    R: UInt8;                            // Internal RAM Pointer (Stack Pointer)
    S: UInt8;                            // Unused
    C: Boolean;                          // Carry flag
    D: UInt8;                            // Working Register
    Z: Boolean;                          // Zero flag
    Port_IA: UInt8;
    Port_IB: UInt8;
    Port_Control: UInt8;
    Port_FO: UInt8;
    CaseCnt: UInt8;
    RamStart: UInt16;
    RamEnd: UInt16;
    VramStart: UInt16;
    VramEnd: UInt16;
    procedure Init;
    procedure LoadMemory(const Filename: string; StartAddr: uInt16 = $0000; EndAddr: uInt16 = $FFFF);
    procedure SaveMemory(const Filename: string; StartAddr: uInt16 = $0000; EndAddr: uInt16 = $FFFF);
    procedure Execute(Address: UInt16 = $0000);
    property Data: UInt8 read GetData;
    property RAM[Index: UInt16]: UInt8 read GetMem write SetMem;
    case Boolean of
      False:
        (
          PC: UInt16;                    // Program Counter
          DP: UInt16;                    // Data pointer
          I: UInt8;                      // Index Counter
          J: UInt8;                      // Index Counter
          A: UInt8;                      // Accumulator
          B: UInt8;                      // Secondary Accumulator
          X: UInt16;                     // 16 bit RAM pointer (XL = InternalRAM[$04], XH = InternalRAM[$05])
          Y: UInt16;                     // 16 bit RAM pointer (YL = InternalRAM[$06], LH = InternalRAM[$07])
          K: UInt8;                      // General Purpose Pointer
          L: UInt8;                      // General Purpose Pointer
          M: UInt8;                      // General Purpose Pointer
          N: UInt8;                      // General Purpose Pointer
          IR: array [$0C..$5B] of UInt8; // Internal RAM - Stack
          IA: UInt8;                     // Port IA
          IB: UInt8;                     // Port IB
          FO: UInt8;                     // Port FO
          OUTC: UInt8;                   // Control Port
        );
      True:
        (
          PCL: UInt8;
          PCH: UInt8;
          DPL: UInt8;
          DPH: UInt8;
          InternalRAM: array [$00..$5F] of UInt8
        );
   end;

var
  SC: TSC61860;

implementation

{ TSC61860 }

procedure TSC61860.Execute(Address: UInt16 = $0000);
var
  MCode: UInt8;
  v: UInt8;
  w: UInt16;
  x1, x2: UInt32;
begin
  if Address > 0 then
    PC := Address;
  MCode := Data;
  case MCode of
    $00: // LII n
      begin
        Inc(PC);
        I := Data;
      end;
    $01: // LIJ n
      begin
        Inc(PC);
        J := Data;
      end;
    $02: // LIA n
      begin
        Inc(PC);
        A := Data;
      end;
    $03: // LIB n
      begin
        Inc(PC);
        B := Data;
      end;
    $04: // IX
      begin
        Q := $00; // need debug
        Inc(X);
        DP := X;
      end;
    $05: // DX
      begin
        Q := $00; // need debug
        Dec(X);
        DP := X;
      end;
    $06: // IY
      begin
        Q := $00; // need debug
        Inc(Y);
        DP := Y;
      end;
    $07: // DY
      begin
        Q := $00; // need debug
        Dec(Y);
        DP := Y;
      end;
    $08: // MVW
      begin
        for var Cnt := 0 to I do
          InternalRAM[P + Cnt] := InternalRAM[Q + Cnt];
        Inc(P, I + 1);
        Inc(Q, I + 1);
      end;
    $09: // EXW
      begin
        for var Cnt := 0 to I do
          begin
            v := InternalRAM[P + Cnt];
            InternalRAM[P + Cnt] := InternalRAM[Q + Cnt];
            InternalRAM[Q + Cnt] := v;
          end;
        Inc(P, I + 1);
        Inc(Q, I + 1);
      end;
    $0A: // MVB
      begin
        for var Cnt := 0 to J do
          InternalRAM[P + Cnt] := InternalRAM[Q + Cnt];
        Inc(P, J + 1);
        Inc(Q, J + 1);
      end;
    $0B: // EXB
      begin
        for var Cnt := 0 to J do
          begin
            v := InternalRAM[P + Cnt];
            InternalRAM[P + Cnt] := InternalRAM[Q + Cnt];
            InternalRAM[Q + Cnt] := v;
          end;
        Inc(P, J + 1);
        Inc(Q, J + 1);
      end;
    $0C: // ADN
      begin
        var Num1: UInt8;
        var Num2: UInt8 := (A shr 4) * 10 + (A and $0F);
        var Num3: UInt8;
        for var Cnt:=0 to I do
          begin
            Num1 := (InternalRAM[P-Cnt] shr 4) * 10 + (InternalRAM[P-Cnt] and $0F);
            Num3 := Num1 + Num2;
            Num2 := Num3 div 100;
            Num3 := Num3 mod 100;
            InternalRAM[P-Cnt] := ((Num3 div 10) shl 4) or (Num3 mod 10);
          end;
        C := Num2 > 0;
        Z := True;
        for var Cnt:=0 to I do
          begin
            if InternalRAM[Cnt] > 0 then
              begin
                Z := False;
                Break;
              end;
          end;
      end;
    $0D: // SBN
      begin
        var Borrow: Boolean := False;
        var Num1: UInt8;
        var Num2: UInt8 := (A shr 4) * 10 + (A and $0F);
        var Num3: UInt8;
        for var Cnt:=0 to I do
          begin
            Num1 := (InternalRAM[P-Cnt] shr 4) * 10 + (InternalRAM[P-Cnt] and $0F);
            if Borrow then
              Dec(Num1);
            Borrow := Num2 > Num1;
            if Borrow then
              Num1 := Num1 + 100;
            Num3 := Num1 - Num2;
            Num2 := Num3 div 100;
            Num3 := Num3 mod 100;
            InternalRAM[P-Cnt] := ((Num3 div 10) shl 4) or (Num3 mod 10);
          end;
        C := Borrow;
        Z := True;
        for var Cnt:=0 to I do
          begin
            if InternalRAM[Cnt] > 0 then
              begin
                Z := False;
                Break;
              end;
          end;
      end;
    $0E: // ADW
      begin
        var Carry: Boolean := False;
        var Num1: UInt8;
        var Num2: UInt8;
        var Num3: UInt8;
        for var Cnt:=0 to I do
          begin
            Num1 := (InternalRAM[P-Cnt] shr 4) * 10 + (InternalRAM[P-Cnt] and $0F);
            Num2 := (InternalRAM[Q-Cnt] shr 4) * 10 + (InternalRAM[Q-Cnt] and $0F);
            Num3 := Num1 + Num2;
            if Carry then
              Inc(Num3);
            Num2 := Num3 div 100;
            Carry := Num2 > 0;
            Num3 := Num3 mod 100;
            InternalRAM[P-Cnt] := ((Num3 div 10) shl 4) or (Num3 mod 10);
          end;
        Z := True;
        for var Cnt:=0 to I do
          begin
            if InternalRAM[Cnt] > 0 then
              begin
                Z := False;
                Break;
              end;
          end;
      end;
    $0F: // SBW
      begin
        var Borrow: Boolean := False;
        var Num1: UInt8;
        var Num2: UInt8;
        var Num3: UInt8;
        for var Cnt:=0 to I do
          begin
            Num1 := (InternalRAM[P-Cnt] shr 4) * 10 + (InternalRAM[P-Cnt] and $0F);
            Num2 := (InternalRAM[Q-Cnt] shr 4) * 10 + (InternalRAM[Q-Cnt] and $0F);
            if Borrow then
              Dec(Num1);
            Borrow := Num2 > Num1;
            if Borrow then
              Num1 := Num1 + 100;
            Num3 := Num1 - Num2;
            InternalRAM[P-Cnt] := ((Num3 div 10) shl 4) or (Num3 mod 10);
          end;
        Z := True;
        for var Cnt:=0 to I do
          begin
            if InternalRAM[Cnt] > 0 then
              begin
                Z := False;
                Break;
              end;
          end;
      end;
    $10: // LIDP n m
      begin
        Inc(PC);
        w := Data shl 8;
        Inc(PC);
        w := w + Data;
        DP := w;
      end;
    $11: // LIDL n
      begin
        Inc(PC);
        DP := (DP and $FF) or Data;
      end;
    $12: // LIP n
      begin
        Inc(PC);
        P := (P and $80) or (Data and $7F);
      end;
    $13: // LIQ n
      begin
        Inc(PC);
        Q := (Q and $80) or (Data and $7F);
      end;
    $14: // ADB
      begin
        x1 :=  (B shl 8) or A;
        x2 := (InternalRAM[P + 1] shl 8) or InternalRAM[P];
        x1 := x2 + x1;
        C := x1 > $FFFF;
        Z := x1 = 0;
        InternalRAM[P + 1] := (x1 and $FFFF) shr 8;
        InternalRAM[P + 0] := (x1 and $00FF);
      end;
    $15: // SBB
      begin
        x1 :=  (B shl 8) or A;
        x2 := (InternalRAM[P + 1] shl 8) or InternalRAM[P];
        x1 := x2 - x1;
        C := x1 > $FFFF; // need debug
        Z := x1 = 0;
        InternalRAM[P + 1] := (x1 and $FFFF) shr 8;
        InternalRAM[P + 0] := (x1 and $00FF);
      end;
    $16: // (N/A) HALT
      ;
    $17: // (N/A) HALT
      ;
    $18: // MVWD
      begin
        for var Cnt := 0 to I do
          InternalRAM[P + Cnt] := Memory[DP + Cnt];
        Inc(DP, I);
        Inc(P, I + 1);
      end;
    $19: // EXWD
      begin
        for var Cnt := 0 to I do
          begin
            v := InternalRAM[P + Cnt];
            InternalRAM[P + Cnt] := Memory[DP + Cnt];
            RAM[DP + Cnt] := v;
          end;
        Inc(DP, I);
        Inc(P, I + 1);
      end;
    $1A: // MVBD
      begin
        for var Cnt := 0 to J do
          InternalRAM[P + Cnt] := Memory[DP + Cnt];
        DP := DP + J;
        P := P + J + 1;
      end;
    $1B: // EXBD
      begin
        for var Cnt := 0 to J do
          begin
            v := InternalRAM[P + Cnt];
            InternalRAM[P + Cnt] := Memory[DP + Cnt];
            RAM[DP + Cnt] := v;
          end;
      end;
    $1C: // SRW
      begin
        var v2: UInt8;
        for var Cnt := 0 to I - 1 do
          begin
            if Cnt < (I - 1) then
              v2 := (InternalRAM[P + Cnt + 1] shl 4)
            else
              v2 := 0;
            InternalRAM[P + Cnt] := (InternalRAM[P + Cnt] shr 4) or v2;
          end;
      end;
    $1D: // SLW
      begin
        var v2: UInt8;
        for var Cnt := 0 to I - 1 do
          begin
            if Cnt < (I - 1) then
              v2 := (InternalRAM[P + Cnt + 1] shr 4)
            else
              v2 := 0;
            InternalRAM[P + Cnt] := (InternalRAM[P + Cnt] shl 4) or v2;
          end;
      end;
    $1E: // FILM
      begin
        for var Cnt := 0 to I do
          InternalRAM[P + Cnt] := A;
        Inc(P, I + 1);
      end;
    $1F: // FILD
      begin
        for var Cnt := 0 to I do
          RAM[DP + Cnt] := A;
        Inc(DP, I);
      end;
    $20: // LDP
      begin
        A := P;
      end;
    $21: // LDQ
      begin
        A := Q;
      end;
    $22: // LDR
      begin
        A := R;
      end;
    $23: // (N/A) CLRA
      begin
        A := $00;
      end;
    $24: // IXL
      begin
        Q := $00; // need debug
        Inc(X);
        DP := X;
        A := Memory[DP];
      end;
    $25: // DXL
      begin
        Q := $00; // need debug
        Dec(X);
        DP := X;
        A := Memory[DP];
      end;
    $26: // IYS
      begin
        Q := $00; // need debug
        Inc(Y);
        DP := Y;
        RAM[DP] := A;
      end;
    $27: // DYS
      begin
        Q := $00; // need debug
        Dec(Y);
        DP := Y;
        RAM[DP] := A;
      end;
    $28: // JRNZP n
      begin
        Inc(PC);
        if not Z then
          Inc(PC, Data - 1);
      end;
    $29: // JRNZM n
      begin
        Inc(PC);
        if not Z then
          Dec(PC, Data + 1);
      end;
    $2A: // JRNCP n
      begin
        Inc(PC);
        if not C then
          Inc(PC, Data - 1);
      end;
    $2B: // JRNCM n
      begin
        Inc(PC);
        if not C then
          Dec(PC, Data + 1);
      end;
    $2C: // JRP n
      begin
        Inc(PC);
        Inc(PC, Data - 1);
      end;
    $2D: // JRM n
      begin
        Inc(PC);
        Dec(PC, Data + 1);
      end;
    $2E: // (N/A) HALT
      ;
    $2F: // LOOP n
      begin
        Inc(PC);
        Dec(InternalRAM[R]);
        C := InternalRAM[R] = $FF;
        Z := InternalRAM[R] = $00;
        if not C then
          Inc(PC, Data - 1); // -1
      end;
    $30: // STP
      begin
        P := A;
      end;
    $31: // STQ
      begin
        Q := A;
      end;
    $32: // STR
      begin
        R := A;
      end;
    $33: // (N/A) NOPT
      ;
    $34: // PUSH
      begin
        Dec(R);
        InternalRAM[R] := A;
      end;
    $35: // RST / MVWP (未定義命令)
      begin
        w := (B shl 8) or A;
        for var Cnt := 0 to I do
          InternalRAM[P + Cnt] := Memory[w + Cnt];
      end;
    $36: // (N/A) HALT
      ;
    $37: // RTN
      begin
        PC := (InternalRAM[R+1] shl 8) + InternalRAM[R] -1; // -1
        Inc(R, 2);
      end;
    $38: // JRZP n
      begin
        Inc(PC);
        if Z then
          Inc(PC, Data - 1);
      end;
    $39: // JRZM n
      begin
        Inc(PC);
        if Z then
          Dec(PC, Data + 1);
      end;
    $3A: // JRCP n
      begin
        Inc(PC);
        if C then
          Inc(PC, Data - 1);
      end;
    $3B: // JRCM n
      begin
        Inc(PC);
        if C then
          Dec(PC, Data + 1);
      end;
    $3C: // (N/A) HALT
      ;
    $3D: // (N/A) HALT
      ;
    $3E: // (N/A) HALT
      ;
    $3F: // (N/A) HALT
      ;
    $40: // INCI
      begin
        w := I + 1;
        C := w > $FF;
        Z := w = $00;
        Q := $00; // need debug
        I := w and $FF;
      end;
    $41: // DECI
      begin
        w := I - 1;
        C := w > $FF; // need debug
        Z := w = $00;
        Q := $00; // need debug
        I := w and $FF;
      end;
    $42: // INCA
      begin
        w := A + 1;
        C := w > $FF;
        Z := w = $00;
        Q := $00; // need debug
        A := w and $FF;
      end;
    $43: // DECA
      begin
        w := A - 1;
        C := w > $FF; // need debug
        Z := w = $00;
        Q := $00; // need debug
        A := w and $FF;
      end;
    $44: // ADM
      begin
        w := InternalRAM[P] + A;
        C := w > $FF; // need debug
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $45: // SBM
      begin
        w := InternalRAM[P] - A;
        C := w > $FF; // need debug
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $46: // ANMA
      begin
        w := InternalRAM[P] and A;
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $47: // ORMA
      begin
        w := InternalRAM[P] or A;
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $48: // INCK
      begin
        w := K + 1;
        C := w > $FF;
        Z := w = $00;
        Q := $00; // need debug
        K := w and $FF;
      end;
    $49: // DECK
      begin
        w := K - 1;
        C := w > $FF; // need debug
        Z := w = $00;
        Q := $00; // need debug
        K := w and $FF;
      end;
    $4A: // INCM
      begin
        w := M + 1;
        C := w > $FF;
        Z := w = $00;
        Q := $00; // need debug
        M := w and $FF;
      end;
    $4B: // DECM
      begin
        w := M + 1;
        C := w > $FF; // need debug
        Z := w = $00;
        Q := $00; // need debug
        M := w and $FF;
      end;
    $4C: // INA
      begin
        A := Port_IA;
      end;
    $4D: // NOPW
      begin

      end;
    $4E: // WAIT n
      begin
        Inc(PC);
      end;
    $4F: // CUP / IPXL
      begin
        // Not implemented yet
      end;
    $50: // INCP
      begin
        Inc(P);
      end;
    $51: // DECP
      begin
        Dec(P);
      end;
    $52: // STD
      begin
        RAM[DP] := A;
      end;
    $53: // MVDM
      begin
        RAM[DP] := InternalRAM[P];
      end;
    $54: // MVMP (READM)
      begin
        InternalRAM[P] := Memory[PC+1];
      end;
    $55: // MVMD
      begin
        InternalRAM[P] := Memory[DP];
      end;
    $56: // LDPC (READ)
      begin
        A := Memory[PC+1];
      end;
    $57: // LDD
      begin
        A := Memory[DP];
      end;
    $58: // SWP
      begin
        v := (A and $F0) shr 4;
        A := (A shl 4) or v;
      end;
    $59: // LDM
      begin
        A := InternalRAM[P];
      end;
    $5A: // SL
      begin
        A := (A shl 1) or Ord(C);
      end;
    $5B: // POP
      begin
        A := InternalRAM[R];
        Inc(R);
      end;
    $5C: // (N/A)  HALT
      ;
    $5D: // OUTA
      begin
        Port_IA := IA;
      end;
    $5E: // (N/A)  HALT
      ;
    $5F: // OUTF
      begin
        Port_FO := FO;
      end;
    $60: // ANIM n
      begin
        Inc(PC);
        w := InternalRAM[P] and Data;
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $61: // ORIM n
      begin
        Inc(PC);
        w := InternalRAM[P] or Data;
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $62: // TSIM n
      begin
        Inc(PC);
        Z := (InternalRAM[P] and Data) = 0;
      end;
    $63: // CPIM n
      begin
        Inc(PC);
        v := Data;
        if InternalRAM[P] > v then
          begin
            C := False;
            Z := False;
          end
        else if InternalRAM[P] < v then
          begin
            C := True;
            Z := False;
          end
        else
          begin
            C := False;
            Z := True;
          end;
      end;
    $64: // ANIA n
      begin
        Inc(PC);
        w := A and Data;
        Z := w = $00;
        A := w and $FF;
      end;
    $65: // ORIA n
      begin
        Inc(PC);
        w := A or Data;
        Z := w = $00;
        A := w and $FF;
      end;
    $66: // TSIA n
      begin
        Inc(PC);
        Z := (A and Data) = 0;
      end;
    $67: // CPIA n
      begin
        Inc(PC);
        v := Data;
        if A > v then
          begin
            C := False;
            Z := False;
          end
        else if A < v then
          begin
            C := True;
            Z := False;
          end
        else
          begin
            C := False;
            Z := True;
          end;
      end;
    $68: // (N/A) NOPT
      ;
    $69: // CASE2 (JST)
      begin
        w := 0;
        for var i:=0 to CaseCnt-1 do
          begin
            Inc(PC);
            v := Data;
            if A = v then
              begin
                Inc(PC);
                w := Data shl 8;
                Inc(PC);
                w := w or Data;
                PC := w - 1; // -1
                Break;
              end;
          end;
        if w = 0 then
          begin
            Inc(PC);
            w := Data shl 8;
            Inc(PC);
            w := w or Data;
            PC := w - 1;
          end;
      end;
    $6A: // (N/A) NOPT
      ;
    $6B: // TEST n
      begin
        Inc(PC);
        // Not implemented yet
      end;
    $6C: // (N/A) HALT
      ;
    $6D: // (N/A) HALT
      ;
    $6E: // (N/A) HALT
      ;
    $6F: // CDN / IPXH
      begin
        // Not implemented yet
      end;
    $70: // ADIM n
      begin
        Inc(PC);
        w := InternalRAM[P] + Data;
        C := w > $FF; // need debug
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $71: // SBIM n
      begin
        Inc(PC);
        w := InternalRAM[P] - Data;
        C := w > $FF; // need debug
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $72: // (N/A) RZ
      begin
        Z := False;
      end;
    $73: // (N/A) RZ
      begin
        Z := False;
      end;
    $74: // ADIA n
      begin
        Inc(PC);
        w := A + Data;
        C := w > $FF; // need debug
        Z := w = $00;
        A := w and $FF;
      end;
    $75: // SBIA n
      begin
        Inc(PC);
        w := A - Data;
        C := w > $FF; // need debug
        Z := w = $00;
        A := w and $FF;
      end;
    $76: // (N/A) RZ
      begin
        Z := False;
      end;
    $77: // (N/A) RZ
      begin
        Z := False;
      end;
    $78: // CALL n m
      begin
        w := PC + 3;
        InternalRAM[R-1] := w shr 8;
        InternalRAM[R-2] := w and $FF00;
        Dec(R, 2);
        Inc(PC);
        w := Data shl 8;
        Inc(PC);
        w := w + Data;
        PC := w - 1; // -1
      end;
    $79: // JP n m
      begin
        Inc(PC);
        w := Data shl 8;
        Inc(PC);
        w := w or Data;
        PC := w - 1;
      end;
    $7A: // CASE1 (SETT) l n m
      begin
        Inc(PC);
        CaseCnt := Data;
        Inc(PC);
        InternalRAM[R-1] := Data;
        Inc(PC);
        InternalRAM[R-2] := Data;
        Dec(R, 2);
      end;
    $7B: // (N/A) HALT
      ;
    $7C: // JPNZ n m
      begin
        Inc(PC);
        w := Data shl 8;
        Inc(PC);
        w := w or Data;
        if not Z then
          PC := w - 1;
      end;
    $7D: // JPNC n m
      begin
        Inc(PC);
        w := Data shl 8;
        Inc(PC);
        w := w or Data;
        if not C then
          PC := w - 1;
      end;
    $7E: // JPZ n m
      begin
        Inc(PC);
        w := Data shl 8;
        Inc(PC);
        w := w or Data;
        if Z then
          PC := w - 1;
      end;
    $7F: // JPC n m
      begin
        Inc(PC);
        w := Data shl 8;
        Inc(PC);
        w := w or Data;
        if C then
          PC := w - 1;
      end;
    $80..$BF: // LP
      begin
        P := Data - $80;
      end;
    $C0: // INCJ
      begin
        w := J + 1;
        C := w > $FF;
        Z := w = $00;
        Q := $00; // need debug
        J := w and $FF;
      end;
    $C1: // DECJ
      begin
        w := J - 1;
        C := w > $FF; // need debug
        Z := w = $00;
        Q := $00; // need debug
        J := w and $FF;
      end;
    $C2: // INCB
      begin
        w := B + 1;
        C := w > $FF;
        Z := w = $00;
        Q := $00; // need debug
        B := w and $FF;
      end;
    $C3: // DECB
      begin
        w := B - 1;
        C := w > $FF; // need debug
        Z := w = $00;
        Q := $00; // need debug
        B := w and $FF;
      end;
    $C4: // ADCM
      begin
        w := InternalRAM[P] + A + Ord(C);
        C := w > $FF;
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $C5: // SBCM
      begin
        w := InternalRAM[P] - A - Ord(C);
        C := w > $FF; // need debug
        Z := w = $00;
        InternalRAM[P] := w and $FF;
      end;
    $C6: // TSMA (未定義命令)
      begin
        Z := InternalRAM[P] = A;
      end;
    $C7: // CPMA
      begin
        if InternalRAM[P] > A then
          begin
            C := False;
            Z := False;
          end
        else if InternalRAM[P] < A then
          begin
            C := True;
            Z := False;
          end
        else
          begin
            C := False;
            Z := True;
          end;
      end;
    $C8: // INCL
      begin
        w := L + 1;
        C := w > $FF;
        Z := w = $00;
        Q := $00; // need debug
        L := w and $FF;
      end;
    $C9: // DECL
      begin
        w := L - 1;
        C := w > $FF; // need debug
        Z := w = $00;
        Q := $00; // need debug
        L := w and $FF;
      end;
    $CA: // INCN
      begin
        w := N + 1;
        C := w > $FF;
        Z := w = $00;
        Q := $00; // need debug
        N := w and $FF;
      end;
    $CB: // DECN
      begin
        w := N - 1;
        C := w > $FF; // need debug
        Z := w = $00;
        Q := $00; // need debug
        N := w and $FF;
      end;
    $CC: // INB
      begin
        A := Port_IB;
      end;
    $CD: // (N/A) NOPW
      ;
    $CE: // NOPT
      begin

      end;
    $CF: // (N/A) HALT
      ;
    $D0: // SC
      begin
        C := True;
        Z := True;
      end;
    $D1: // RC
      begin
        C := False;
        Z := True;
      end;
    $D2: // SR
      begin
        C := Odd(A);
        A := A shr 1;
      end;
    $D3: // WRIT (NOPW)
      begin

      end;
    $D4: // ANID n
      begin
        Inc(PC);
        w := Memory[DP] and Data;
        Z := w = $00;
        RAM[DP] := w and $FF;
      end;
    $D5: // ORID n
      begin
        Inc(PC);
        w := Memory[DP] or Data;
        Z := w = $00;
        RAM[DP] := w and $FF;
      end;
    $D6: // TSID n
      begin
        Inc(PC);
        Z := (Memory[DP] and Data) = 0;
      end;
    $D7: // CPID n
      begin
        Inc(PC);
        // Not implemented yet
      end;
    $D8: // LEAVE
      begin
        InternalRAM[R] := 0;
      end;
    $D9: // (N/A) NOPW
      ;
    $DA: // EXAB
      begin
        v := A;
        A := B;
        B := v;
      end;
    $DB: // EXAM
      begin
        v := A;
        A := InternalRAM[P];
        InternalRAM[P] := v;
      end;
    $DC: // (N/A) HALT
      ;
    $DD: // OUTB
      begin
        Port_IB := IB;
      end;
    $DE: // (N/A) HALT
      ;
    $DF: // OUTC
      begin
        Port_Control := OUTC;
      end;
    $E0..$FF: // CAL n
      begin
        w := PC + 2;
        InternalRAM[R-1] := w shr 8;
        InternalRAM[R-2] := w and $FF00;
        Dec(R, 2);
        w := (Data - $E0) shl 8;
        Inc(PC);
        w := w + Data;
        PC := w - 1; // -1
      end;
  end;
  Inc(PC);
end;

function TSC61860.GetData: UInt8;
begin
  result := Memory[PC];
end;

function TSC61860.GetMem(Index: UInt16): UInt8;
begin
  result := Memory[Index];
end;

procedure TSC61860.SetMem(Index: UInt16; const Value: UInt8);
begin
  if ((Index >= RamStart ) and (Index <= RamEnd )) or
     ((Index >= VramStart) and (Index <= VramEnd)) then
    Memory[Index] := Value;
end;

procedure TSC61860.Init;
begin
  Self := Default(TSC61860);
  R := $5B;

  RamStart  := $C000; // PC-1245/50
//RamStart  := $B800; // PC-1251
//RamStart  := $A000; // PC-1255
//RamStart  := $5800; // PC-1260
//RamStart  := $4000; // PC-1261/62
//RamStart  := $6000; // PC-1350
  RamEnd    := $C7FF; // PC-1245/5x
//RamEnd    := $67FF; // PC-126x
//RamEnd    := $6FFF; // PC-1350

  VramStart := $F800; // PC-1245/5x
//VramStart := $2000; // PC-126x
//VramStart := $7000; // PC-1350
  VramEnd   := $F8BF; // PC-1245/5x
//VramEnd   := $38BF; // PC-126x
//VramEnd   := $7FFF; // PC-1350
end;

procedure TSC61860.LoadMemory(const Filename: string; StartAddr,
  EndAddr: uInt16);
begin
  var MS := TMemoryStream.Create;
  try
    MS.LoadFromFile(Filename);
    MS.Read(Memory[StartAddr], Succ(EndAddr - StartAddr));
  finally
    MS.Free;
  end;
end;

procedure TSC61860.SaveMemory(const Filename: string; StartAddr,
  EndAddr: uInt16);
begin
  var MS := TMemoryStream.Create;
  try
    MS.Write(Memory[StartAddr], Succ(EndAddr - StartAddr));
    MS.SaveToFile(Filename);
  finally
    MS.Free;
  end;
end;

end.
```

キャリーフラグとゼロフラグが適当ではないかもしれない。実機と異なる挙動があったら都度修正する事にする。

## 使い方

Delphi プロジェクトの **uses** に `uSC61860` を追加して、

```pascal
uses
  ..., uSC61860;

```

適当な場所でコードを書く。

```pascal
procedure TForm1.Button1Click(Sender: TObject);
begin
  SC.Init;
//SC.LoadRom('pc1245mem.bin'); // Start Address 0x0000
  Memo1.Lines.Clear;

  SC.P := $3F;
  SC.Q := $3C;
  SC.I := $02;

  SC.InternalRAM[$3A] := $01;
  SC.InternalRAM[$3B] := $23;
  SC.InternalRAM[$3C] := $45;

  SC.InternalRAM[$3D] := $45;
  SC.InternalRAM[$3E] := $67;
  SC.InternalRAM[$3F] := $89;

  SC.RAM[$C400] := $0F;
  SC.Execute($C400);

  Memo1.Lines.Add(Format('3D=%.2x', [SC.InternalRAM[$3D]]));
  Memo1.Lines.Add(Format('3E=%.2x', [SC.InternalRAM[$3E]]));
  Memo1.Lines.Add(Format('3F=%.2x', [SC.InternalRAM[$3F]]));

  ...
end;
```

`SC.Execute()` を実行する度に 1 命令分逐次実行される。

# おわりに
コードを書いたので、命令セットにどんなものがあるのかはもう覚えた (w
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/f933b2c4-0ad0-c5b7-214e-0ee67424c237.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/21785/55ca4a0d-b87f-771e-b6a1-4ff433225e58.png)
先述のコードを元に、**トレーナー兼簡易アセンブラ** を[作成中](https://ht-deko.com/pokecom/software.html#02)。

**See also:**

 - [Pocket Computer PC-1350 Machine Language Reference Manual (yumpu.com)](https://www.yumpu.com/xx/document/read/4129074/pc1350-ml-ref-manual)
 - [Pocket Computer PC-1350 Machine Language Reference Manual (PockEmul)](https://pockemul.com/wp-content/uploads/2022/12/PC1350_ML_EN.pdf)
 - [SC61860 (aka ESR-H) Instruction Set (GitHub)](https://github.com/utz82/SC61860-Instruction-Set)
 - [PC-1245 (JP3TLC's homepage)](http://jp3tlc.com/pc12/pc12inst.shtml)
 - [PC-1251 CPU SC61860 (Enri's Home PAGE)](http://www43.tok2.com/home/cmpslv/Pc1251/Enr51cpu.htm)
 - [SHARP PC-1245/50/51/55 の使い方 (ht-deko.com)](https://ht-deko.com/pc1245/)