大家好
很久以前,就有一种编写某种处理器的仿真器的愿望。
还有什么比发明自行车更好的呢?
自行车的名称是V16,是通过加上单词Virtual(虚拟)和实际上的位深度来表示的。
从哪里开始?
当然,您需要从对处理器的描述开始。
一开始,我计划编写一个DCPU-16仿真器,但是Internet上有如此多的奇迹,因此我决定只专注于“舔”最基本的DCPU-16 1.1。
建筑学
内存和端口
- V16寻址RAM的128Kb(65536字),也可以用作设备缓冲区和堆栈。
- 堆栈以地址FFFF开始,因此,RSP的标准值为0xFFFF
- V16 I / O端口有256个,它们的长度均为16位。 通过指令
IN b, a
和OUT b, a
进行读取和写入。
寄存器
V16有两组通用寄存器:主要寄存器和备用寄存器。
一个处理器只能使用一组,因此您可以使用XCR
指令在一组之间切换。
使用说明
所有指令的最大长度为三个字,并且首先完全定义
第一个字分为三个值:低字节是操作码,高字节是两个4位值的形式,是对操作数的描述。
打断
这里的中断不过是一个表,该表具有处理器将CALL
指令复制到的地址。 如果地址值为零,则中断不执行任何操作,仅复位HF标志。
所有这些都应翻译成伪代码和单词的示例:
MOV RAX, 0xABCD ; 350D ABCD MOV [RAX], 0x1234 ; 354D 1234
周期数
V16可以1、2或3小节执行一条指令。 每个存储器访问是一个单独的时钟周期。 指令不灵通!
让我们开始写作!
基本处理器结构的实现
一组寄存器。 只有四个寄存器,但是情况有所改善,处理器中有两个这样的寄存器组。 使用XCR
指令进行切换。
typedef struct Regs { uint16_t rax, rbx;
标志 与DCPU-16不同,V16具有条件跳转,子例程调用并从中返回。 目前,处理器具有8个标志,其中5个是条件标志。
实际上,处理器本身。 它还描述了中断地址表,可以将其称为描述符并找到对x86的另一个引用。
typedef struct CPU {
操作数。 获取值时,我们需要先读取,然后更改,然后将值写回到获取值的位置。
typedef struct Opd { uint8_t code : 4; uint16_t value; uint16_t nextw; } opd_t;
用于结构的功能
当描述了所有结构时,就需要使这些结构具有淬灭代码的神奇力量的功能。
cpu_t * cpu_create(void);
另外,我没有提到带有操作代码的大型枚举,但这不是必需的,仅是为了了解所有这些混乱情况中所需要的。
勾号()函数
此外,还有对静态函数的调用,这些静态函数仅用于从tick()
进行调用。
void cpu_tick(cpu_t *cpu) {
接下来要做什么?
为了找到这个问题的答案,我将模拟器从C重写到C ++了五次,反之亦然。
但是,现在可以确定主要目标:
- 固定常规中断(而不是仅调用函数并禁止接收其他中断,而要进行函数调用并将新的中断添加到队列中)。
- 螺丝设备以及与之通信的方式,操作码的好处是256。
- 教书
不要在Habr上写下任何异端 处理器以200 MHz的特定时钟速度运行。
结论
我希望这个“文章”对某人有用,有人会促使他们写类似的东西。
我的馅饼可以在github上查看。
另外,关于恐怖,我为该模拟器的旧版本提供了汇编程序(不,甚至不要尝试,模拟器至少会抱怨ROM格式错误)