シミュレーション

シミュレータが完成

2007年6月24日

シミュレータが、(おそらく)完成した。最後に残っていた、複合命令まわりのコードを仕上げた。いくつかの複合命令を実行してみたが、うまく動いている様子。

主な変更点を、抜粋しておく。

memory.cpp
// The Basic Sub Routines
class BSR : public MEMORY {
public:
    unsigned short ip;
    void inc(){
        ip++;
    }
    unsigned char read(){
        setSegment(ip>>8);
        setAddr(ip&0xff);
        return ((MEMORY*)this)->read();
    }
    void reset(unsigned char command){
        switch (command){
        case 0xc0: ip=0x00; return; // mov a1,XXh
        case 0xc1: ip=0x05; return; // mov a2,XXh
        case 0xc2: ip=0x0a; return; // mov b1,XXh
        case 0xc3: ip=0x0f; return; // mov b2,XXh
        case 0xc4: ip=0x14; return; // call x
        case 0xc5: ip=0x17; return; // ret far
        case 0xc6: ip=0x1a; return; // call x:[b2]
        case 0xc7: ip=0x21; return; // jmp x:[b2]
        case 0xc8: ip=0x28; return; // jmp ip+x
        case 0xc9: ip=0x35; return; // jmp ip-x
        case 0xca: ip=0x42; return; // ret far+1
        case 0xcb: ip=0x50; return; // call ip+x
        case 0xcc: ip=0x53; return; // call ip-x
        case 0xcd: ip=0x60; return; // not a1
        case 0xce: ip=0x66; return; // and a1,a2
        case 0xcf: ip=0x70; return; // or a1,a2
        case 0xd0: ip=0x7a; return; // rtr a1
        case 0xd1: ip=0x89; return; // rtl a2
        case 0xd2: ip=0x98; return; // shr a1
        case 0xd3: ip=0xa0; return; // shl a2
        case 0xd4: ip=0xa8; return; // exc a1,a2
        case 0xd5: ip=0xad; return; // exc a1,x
        case 0xd6: ip=0xb2; return; // exc a2,x
        case 0xd7:

        case 0xff:
        default:
            ip=0;
        }
    }
};

void setBSR(BSR* bsr){
    int i;
    unsigned char data[256];
    char* asmdata[]={
    // mov al,XXh
        "push x",       //00
        "mov x,[ip++]",
        "mov a1,x",
        "pop x",
        "nop",
    // mov a2,XXh
        "push x",       //05
        "mov x,[ip++]",
        "mov a2,x",
        "pop x",
        "nop",
    // mov b1,XXh
        "push x",       //0a
        "mov x,[ip++]",
        "mov b1,x",
        "pop x",
        "nop",
    // mov b2,XXh
        "push x",       //0f
        "mov x,[ip++]",
        "mov b2,x",
        "pop x",
        "nop",
    // call x
        "push ip",      //14
        "mov ip,x",
        "nop",
    // ret far
        "pop ip",       //17 
        "pop cs",
        "nop",
    // call x:[b2]
        "mov [b2-3],x",  //1a
        "mov x,[b2]",
        "mov [b2-2],x",
        "push cs",
        "push ip",
        "mov x,[b2-1]",
        "jmp x:[b2]",
    // jmp x:[b2]
        "mov cs,x",        //21
        "mov x,[b2]",
        "mov ip,x",
        "nop",
        "nop",
        "nop",
        "nop",
    // jmp ip+x
        "push a1",      //28
        "mov [b2],x",
        "mov x,ip",
        "mov a1,x",
        "add a1,[b2]",
        "mov ip,x",
        "pop a1",
        "if nc",
        "nop",
        "mov x,cs",
        "inc x",
        "mov cs,x",
        "nop",
    // jmp ip-x
        "push a1",      //35
        "mov [b2],x",
        "mov x,ip",
        "mov a1,x",
        "sub a1,[b2]",
        "mov ip,x",
        "pop a1",
        "if nc",
        "nop",
        "mov x,cs",
        "dec x",
        "mov cs,x",
        "nop",
    // ret far+1
        "pop cs",        //42
        "pop ip",
        "mov [b2],x",
        "mov x,ip",
        "inc x",
        "mov ip,x",
        "mov x,[b2]",
        "if nz",
        "nop",
        "mov x,cs",
        "inc x",
        "mov cs,x",
        "mov x,[b2]",
        "nop",
    // call ip+x
        "push cs",        //50
        "push ip",
        "jmp ip+x",
    // call ip-x
        "push cs",        //53
        "push ip",
        "jmp ip-x",
        "nop",
        "nop",
        "nop",
        "nop",
        "nop",
        "nop",
        "nop",
        "nop",
        "nop",
        "nop",
    // not a1
        "push a2",        //60
        "sub a1,a1",
        "mov a2,x",
        "nor a1,a2",
        "pop a2",
        "nop",
    // and a1,a2
        "push a1",        //66
        "push a2",
        "nand a1,a2",
        "mov a1,x",
        "sub a1,a1",
        "mov a2,x",
        "nor a1,a2",
        "pop a2",
        "pop a1",
        "nop",
    // or a1,a2
        "push a1",        //70
        "push a2",
        "nor a1,a2",
        "mov a1,x",
        "sub a1,a1",
        "mov a2,x",
        "nor a1,a2",
        "pop a2",
        "pop a1",
        "nop",
    // rtr a1
        "push x",        //7a
        "push a2",
        "mov xh,0h",
        "mov xl,0h",
        "if c",
        "mov xh,8h",
        "mov a2,x",
        "shr a1",
        "push f",
        "add a1,a2",
        "mov a1,x",
        "pop f",
        "pop a2",
        "pop x",
        "nop",
    // rtl a2
        "push x",        //89
        "push a1",
        "mov xh,0h",
        "mov xl,0h",
        "mov a1,x",
        "if c",
        "inc a1",
        "shl a2",
        "push f",
        "add a1,a2",
        "mov a2,x",
        "pop f",
        "pop a2",
        "pop x",
        "nop",
    // shr a1
        "push a2",        //98
        "push a1",
        "pop a2",
        "shr a2",
        "push a2",
        "pop a1",
        "pop a2",
        "nop",
    // shl a2
        "push a1",        //a0
        "push a2",
        "pop a1",
        "shl a1",
        "push a1",
        "pop a2",
        "pop a1",
        "nop",
    // exc a1,a2
        "push a1",        //a8
        "push a2",
        "pop a1",
        "pop a2",
        "nop",
    // exc a1,x        
        "push a1",        //ad
        "push x",
        "pop a1",
        "pop x",
        "nop",
    // exc a2,x        
        "push a1",        //b2
        "push x",
        "pop a1",
        "pop x",
        "nop",
        "nop",
        "nop",
        "nop",


        ""};
    for (i=0;asmdata[i][0]!=0;i++) data[i]=(unsigned char)assemble(asmdata[i]);
    bsr->setSegment(0);
    for (i=0;i<256;i++) {
        bsr->setAddr((unsigned char)i);
        bsr->write(data[i]);
    }
    bsr->setRom(0,255);
}
複合命令を記述した部分。まだスペースは4分の1ほどしか使用していないので、後でいろいろ追加するだろう。

main.cpp
/* Timing chart

   clock1 clock2 clock2'
    0  1   0  1   0  1
    |      |      |
    +--+   |      +--+ event 1
       |   |         |
    +--+   +--+      | event 2
    |         |      |
    +--+      |   +--+ event 3
       |      |   |
    +--+   +--+   |    event 4
    |      |      |

*/
/* Flags
    f register:
      [7] [6] [5] [4] [3] [2] [1] [0]
       |                       |   |
       |                       |   +-- Zero flag (z)
       |                       +------ Carry flag (c)
       +------------------------------ Basic Sub Routine flag
*/
void _main (){
    int ret;
    unsigned char org_cs,org_ip;
    unsigned short org_bsrip;
    ip.reset();
    f.reset();

    while(1){
        // Event 1
        // Prepare environment for reading command
        // Decrement b2 register for PUSH
        memory.setSegment(cs.getValue());
        memory.setAddr(ip.getValue());
        if ((command & 0xf0)==0x10 && !(command & 0x08)) {
            b2.dec( 0 );
        }
        if (ifBSR() && command==0x4d) ip.inc( 0 );
        
        // Event 2
        // Read command from memory
        if (ifBSR()) command=bsr.read();
        else command=memory.read();

        // Event 3
        // Prepare environment for command
        // increment ip
        // Increment b2 register for POP
        if ((command & 0xf0)==0x10 && (command & 0x08)) {
            b2.inc( 0 );
        }
        org_cs=cs.value;
        org_ip=ip.value;
        org_bsrip=bsr.ip;
        if (ifBSR()) {
            if ((command & 0xc0)!=0xc0) bsr.inc();
        } else ip.inc( 0 );

        // Event 4
        ret=mnemonic();

        debug(org_ip,org_cs,org_bsrip);
        if (ret) return;
    }
}
複合命令を追加したことにより、_main() 関数が書き換わっている。ここは、各種イベントのタイミングを決定する、センシティブな部分だ。

register.cpp
class REGISTER_B : public REGISTER{
private:
    REGISTER* segment;
    char isB1;
    unsigned char bsrStack[8];
    unsigned char bsrSP;
public:
    REGISTER_B(REGISTER* seg, char isB1v){
        segment=seg;
        isB1=isB1v;
    }
    void inc(char flag=1){
        if (isB1<0 && ifBSR()) {
            bsrSP=(bsrSP+1)&7;
        } else {
            value++;
            if (value==0) segment->inc(flag);
        }
    }
    void dec(char flag=1){
        if (isB1<0 && ifBSR()) {
            bsrSP=(bsrSP-1)&7;
        } else {
            value--;
            if (value==0) segment->dec(flag);
        }
    }
    void write(unsigned char data, unsigned char add=0){
        if (isB1<0 && ifBSR() && (command & 0xf0)==0x10) { // push statement in BSR
            bsrStack[bsrSP]=data;
            return;
        }
        memory.setSegment(segment->getValue());
        memory.setAddr(value+isB1*(add & 3));
        memory.write(data);
    }
    unsigned char read(unsigned char add=0, char debug=0){
        if (isB1<0 && ifBSR() && (command & 0xf0)==0x10 && !debug) { // pop statement in BSR
            return bsrStack[bsrSP];
        }
        memory.setSegment(segment->getValue());
        memory.setAddr(value+isB1*(add & 3));
        return memory.read();
    }
};
b2 レジスタを少し変更し、複合命令を実行中はpush/popに専用のスタック領域を用いるようにした。これにより、複合命令を実行しても[b2]の内容が保存される。このスタック領域は、8バイトほど用意しておけば十分だろう。

次はいよいよ、シミュレータを用いて円周率を計算する。これが出来れば、コンピューターとしては最低限の機能を備えていることになるから、いよいよ設計図の作成にとりかかることになる。

<%media(20070625-simulator.zip|simulator.zip)%>

コメント

コメントはありません

コメント送信