シミュレータが完成
2007年6月24日
シミュレータが、(おそらく)完成した。最後に残っていた、複合命令まわりのコードを仕上げた。いくつかの複合命令を実行してみたが、うまく動いている様子。
主な変更点を、抜粋しておく。
memory.cpp
main.cpp
register.cpp
次はいよいよ、シミュレータを用いて円周率を計算する。これが出来れば、コンピューターとしては最低限の機能を備えていることになるから、いよいよ設計図の作成にとりかかることになる。
<%media(20070625-simulator.zip|simulator.zip)%>
主な変更点を、抜粋しておく。
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)%>