シミュレータが完成
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)%>