首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++中6510 / C64模拟器,如何实现周期/时钟

C++中6510 / C64模拟器,如何实现周期/时钟
EN

Stack Overflow用户
提问于 2015-09-18 22:37:32
回答 3查看 1.5K关注 0票数 0

我正在尝试实现一个简单的C++ C64模拟器(6510 + SID,也许还有VIC2)。

到目前为止,我们只介绍了CPU的基础知识,所以我能够实现一个可以从内存中读取和执行指令的CPU,完全忽略了在真正的C64中,一些指令需要超过1个周期的事实。

据我所知:-在指令精确模拟中,每条指令都在一个CPU周期内执行-在周期中-精确模拟,一个需要3个周期的操作将被分成3个周期。

做额外的努力使模拟器周期精确有多重要?SID和VIC是否可以在没有SID和VIC的情况下模拟?

第二个问题:如果我创建一个主循环,在其中我调用985249次中央处理器的doCycle方法,SID,VIC来模拟0,985249 the,是否足够?

编辑:不太确定我是否理解正确:

代码语言:javascript
复制
void CPU::emulateCPUCycle(){
    cyclesLeft--;

    if (cyclesLeft<= 0){

        // fetch op-code
        uint8_t op = mem->read_byte(reg_pc);

        executeInstruction(op);

        cyclesLeft= numOfCyclesTable[op]; // contains the required cycle number per instruction

        // increase PC
        reg_pc++;

    }
    else
      // waste cycle
}
EN

回答 3

Stack Overflow用户

发布于 2015-09-18 23:46:18

“做额外的努力使模拟器周期精确有多重要? SID和VIC甚至可以在没有的情况下模拟吗?”

主要问题是你为什么要这样做。如果你的目标是能够以某种方式运行原始的c64游戏,那么你可能需要精确的计时,因为许多老游戏依赖于精确的计时。然而,即使你写了一个周期精确的仿真器,在现代的非实时操作系统(linux,windows,..)上也有可能达到这种程度的精度。实际工作的成本很低。

只需编写一个模拟器,它可以做正确的事情并忽略计时。这本身就是一个很难解决的问题

票数 1
EN

Stack Overflow用户

发布于 2015-09-20 08:33:39

数据手册/文档告诉您在模拟/模拟您计算时钟的指令时,每条指令的时钟数。例如,您需要/使用它来实现周期性中断。我不太了解c64,但是如果有一些基于时间的中断,你可以将其转换为时钟,如果累积的时钟>N,那么你就中断并从计数器中减去N。

通常,根据指令的不同,一些处理器具有不同的执行时间。例如,存储器版本vs寄存器版本可以具有额外的时钟。

我严重怀疑它们是流水线的,所以我严重怀疑是否有任何并行需要担心,只需根据每条指令的芯片文档累积时钟即可。

编辑:

不知道你想在那里做什么。这不是我要说的。通常在这些系统上,你会有一些计时器驱动的事件,例如,你会根据显示刷新(h或v)或出现的一些基于时间的中断来更新显示。对于c64,我假设键盘是由单独的逻辑处理的,然后你会得到某种类型的代码,但比方说手持或街机,主cpu可能也需要以一定的间隔对输入进行采样(可能还需要处理弹跳,但这是中断可能会为你涵盖的另一个主题)。因此,如果您在中断之前到达那里,这是可以的。在像游戏这样的实时系统中,你需要在下一个屏幕刷新之前准备好下一个屏幕,每次刷新。所以如果你很早就到了那里,你只需旋转并等待刷新。因此,你不需要让每条cpu指令都延迟,就好像你又重新运行了几兆赫。从这些用户界面事件开始,看看它是如何工作的。

你通常不想要一个递减计数器,除非你处理负数,这样可以更准确地将分数滚动到下一个时间段。假设每个中断有250个cpu周期,你在252中断,因为最后一条指令是3个时钟。将额外的2保存到下一时间段。减法250,2留在为该中断累加时钟的变量上。

去看看m6502或其他指令集模拟器,用来做这类事情的,有很多。mame是用它们加载的,尽管代码经过了386天的性能调整,我们不再需要像那样过度优化代码,但它就是这样。

来自我为6502编写的静态二进制翻译器

代码语言:javascript
复制
case 0xA1:
    printf("case 0x%04X: //%02X %02X %02X\n",opadd,opcode,rom[opadd+1],rom[opadd+2]);
    printf("    clockticks+=6;\n");
    temp=rom[opadd+1];
    printf("    value=0x%02X; value+=X;\n",temp); //this should clip
    printf("    temp=ReadMemory(value+1);\n");
    printf("    temp<<=8;\n");
    printf("    temp|=ReadMemory(value);\n");
    printf("    A=ReadMemory(temp);\n");
    printf("  ZN=A;\n");
    break;

然后在别处

代码语言:javascript
复制
    if(ticks>250)
    {
        ticks-=250;
        rom[0x2001] ^= 0xff;
        if (++nmi_count >= 24)
        {
              nmi_count = 0;
printf("INT\n");
              return(INT_NMI);
        }
    }

这是小行星,我后来弄清楚了特定的rom是如何工作的,以及代码在哪里,它等待中断发生,以允许代码前进到下一帧。中断也被用来采样硬币槽,我并不想模仿,etc...so我能够完全删除中断。

但是如果你在做一个通用的系统仿真器,那么你就不能走捷径。如果你想求出每条指令的平均值,你可以把它称为3个时钟或其他任何东西,而不是试图得到太准确的结果。

在这种情况下,如果分支发生,那么我们添加一个额外的时钟

代码语言:javascript
复制
case 0xF0:
    printf("case 0x%04X: //%02X %02X %02X\n",opadd,opcode,rom[opadd+1],rom[opadd+2]);
    printf("    clockticks+=2;\n");
    temp=rom[opadd+1];
    if(temp&0x80) temp-=0x100;
    temp2=(opadd+temp+2)&addrmask;
    printf("    if(ZN==0)//if zero\n");
    printf("    { \n");
    printf("        clockticks++;  \n");
    printf("        //showme(0x%04X,0x%02X);\n",opadd,opcode);
    printf("        PCSTART=0x%04X;\n",temp2);
    printf("        /**/return;\n");
    printf("        //goto L_%04X;\n",temp2);
    printf("    } \n");
    break;

如果你对准确性不是很感兴趣,并且使用平均时钟时间来节省编码或代码空间,那么你可能不会关心中断周期的额外时钟252与250是否足够好来抛出两个额外的时钟。我仍然认为递增计数器更容易,但这只是我…

票数 0
EN

Stack Overflow用户

发布于 2015-09-20 23:28:15

首先,我相信已经有足够多的c64仿真器/仿真器运行良好。https://www.c64-wiki.de/index.php/VICE (德国网站)。也许你会发现这个链接列表很有帮助:https://www.c64-wiki.de/index.php/Portal:Emulatoren (也是德语的,但是在不熟悉德语的情况下也可以使用这些链接;)

接下来,如果你打算学习编程,你可以从头开始。这是一个很好的实践。如果你想要更快的结果,你可以看看其他的开源模拟器,比如一个8位处理器的模拟器,比如avr这里:http://www.nongnu.org/simulavr/。这个模拟器是周期精确的。simulavr的目的是测量中断延迟以及所有其他执行时间测量。它还允许连接到其他硬件,如flashes,LCD,uarts和许多其他东西。您还可以在那里模拟多个内核,它们都以不同的时钟速度/周期时间运行。并且还模拟了附加的中断周期(获取irq向量)。此外,模拟指令流水线的行为,因为在内核流水线的下一周期内将不会看到对prot寄存器的读/写动作。因此,对于小型cpu内核来说,这是一个简单的起点。

关于你的问题:

做额外的努力使模拟器周期精确有多重要?SID和VIC是否可以在没有SID和VIC的情况下模拟?

尽可能精确的模拟是绝对重要的。c64软件通常是手工汇编的东西,以获得正确的计时,以便运行许多狂野的东西。这从扩展端口或软件uarts上的协议的比特碰撞开始。还有很多东西,比如屏幕缓冲区后面的阴影ram,对计算机来说是绝对重要的。

但事实上,我相信所有的工作都已经完成了,可以在网上找到……所以这是一个问题,你想要实现什么?通过制作或使用它来学习。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32654678

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档