Arduino与经典处理器的结合


逆向计算机具有不同程度的挑剔性。 有些满足于仿真。 其他人则更喜欢FPGA,因为事实证明不是仿真而是娱乐。 最后,服务第三个处理器。

但是处理器需要太多工作! 同样,难题是:采用相同年份的真实芯片,还是将所有内容都放入FPGA中,而将处理器留在外面? 但是,为什么需要FPGA? Arduino和经典处理器的结合万岁!

给您的Arduino一个“第二只大脑”并使之更智能。

一个真正的八位微处理器运行程序,而一个Arduino仿真ROM,RAM和简单的外围设备。

在Arduino IDE中设计虚拟外设,然后在微处理器上运行汇编代码。 无需组装复杂的电路和闪存并行ROM。

支持的微处理器:6502、6809和Z80(18581),其他的也在路上。

带有微处理器的屏蔽板不会干扰其他屏蔽板的连接:LCD,存储卡等。

除了自组装语言外,您还可以尝试在微处理器上运行一些经典代码。

没错,微处理器将以非常低的频率运行-大约95 kHz,其确切值取决于外围仿真代码的优化。

地址空间的分布在草图中以编程方式设置。 可以为Arduino Mega上的4至6 kB的8 kB RAM分配微处理器。 ROM可以分配可用256个内存中的200 kB以上。

Arduino Mega串行端口可以仿真UART。

此处的 CC-BY-SA 4.0提供了电路,电路板图纸,Gerber文件。 同时,需要附加README.md文件,因为它包含以下警告:
在上传外围仿真草图之前,请勿连接屏蔽! 否则,可能会使微处理器的输出线短路。
是的,在草图本身中,出于相同的原因,需要仔细重做一些内容。

6502设备的方案:



6809上的设备方案:



Z80上设备的方案:



您已经可以运行:

在具有6502的设备上-Apple I,Woz Monitor +带有BASIC的ROM

在具有6809的设备上- 同一开发人员的家用计算机Simon6809的模拟物,带有汇编器和反汇编器的培训监视器

在具有Z80的设备上-到目前为止,仅对串行端口进行回显测试 ,使您可以检查虚拟8251(KR580VV51A)的性能。

用于仿真外围设备的固件-根据MIT许可。

作用原理的简要说明:

到6502设备

至设备6809

到Z80上的设备-准备中。

开发人员试图销售设备,但仅在美国交付。 没有特别的购买理由,因为该计划非常简单,您可以在一个小时内在一块面包板上重复该计划。

计划在RCA1802、68008、8085(182185),8088(181088)上开发类似的电路板。 关于K1801BM1并没有说,但是您可以向作者提出这样的想法。

档案:

到6502上的设备: 组装说明丝网印刷

到6809上的设备: 组装说明丝网印刷

到Z80上的设备: 组装说明丝网印刷

考虑一下Arduino和6502设备的交互作用,Arduino会定期更改微处理器输入的电平,该微处理器旨在提供从零到1的时钟脉冲,反之亦然。 在每个周期中,它都会检查控制线和地址总线上发生的情况,并根据情况从数据总线中读取信息或将其发送到那里。 Arduino还可以控制IRQ和NMI线,从而引起中断。 该图显示了数据的类型及其传输方向:



草图中配置了Arduino端口与微处理器输出的对应关系:

/* Digital Pin Assignments */ #define DATA_OUT PORTL #define DATA_IN PINL #define ADDR_H PINC #define ADDR_L PINA #define ADDR ((unsigned int) (ADDR_H << 8 | ADDR_L)) #define uP_RESET_N 38 #define uP_RW_N 40 #define uP_RDY 39 #define uP_SO_N 41 #define uP_IRQ_N 50 #define uP_NMI_N 51 #define uP_E 52 #define uP_GPIO 53 

我们将每种度量划分为以下事件:

CLK的状态从1变为零(下降)
CLK处于零状态
CLK将状态从1更改为零(上升)
CLK处于单元状态
CLK再次将状态从1更改为零...

在国家过渡时期会发生什么?

6502在输入CLK0处接收时钟脉冲,对其进行缓冲,然后将其发送到两个输出:CLK1和CLK2。 尽管微处理器中的所有事件都与CLK1有关,但我们假定延迟并不大,并且它们与CLK0有关(CLK0是微处理器从Arduino接收时钟脉冲的线路)。 并将信号称为CLK。



1. CLK将状态从1更改为零。

2.微处理器将新地址输出到地址总线,并将读写之间的切换信号输出到R / W输出。 但是他还没有准备好进行数据交换。

3. CLK进入单元状态,这意味着数据交换已经开始。 如果这是读操作,则微处理器将数据总线输出传输到输入状态并接收数据,如果是写操作,则将其传输到输出状态并发送数据。 R / W信号将外部设备切换到写入或读取模式,与微处理器的相应状态相反。

4. CLK变为零。 现在,微处理器和输入输出设备都不会输出任何数据到数据总线。 微处理器可以将数据总线线路和R / W引脚设置为新状态。

一个简单的解释,孩子可以理解。 如果他只对微控制器进行编程,谁也永远不会想到这些“幕后的诡计”。 即使在汇编程序中。

如果需要连接外围设备,则在设备(准备时间)出现在CLK线上之前,它必须有足够的时间准备数据,但是目前,不应该更改该设备。 如果外围设备没有足够的时间在CLK为零时准备数据,或者在该设备存在时更改数据,那么您会很长一段时间想知道为什么您的代码不起作用。 由于微处理器的时钟频率比标称频率低十到十五倍,因此很容易满足这一要求。 但这是必要的。

因此,我们需要“教” Arduino以生成时钟脉冲,不断检查地址总线和R / W线上发生了什么,并相应地与数据总线进行交互。 为此,草图使用了timer1定时器中断,该中断产生了频率为95 kHz的脉冲。 Arduino的工作速度比微处理器快得多,因此,在两个时钟之间,它可以读取和准备一切。 重要的是要确保在修改草图后继续满足此条件。

这是草图的摘录,其中显示了CLK如何从零变为一,以及接下来将发生什么:

 //////////////////////////////////////////////////////////////////// // Processor Control Loop //////////////////////////////////////////////////////////////////// // This is where the action is. // it reads processor control signals and acts accordingly. // ISR(TIMER1_COMPA_vect) { // Drive CLK high CLK_E_HIGH; // Let's capture the ADDR bus uP_ADDR = ADDR; if (STATE_RW_N) ////////////////////////////////////////////////////////////////// // HIGH = READ transaction { // uP wants to read so Arduino to drive databus to uP: DATA_DIR = DIR_OUT; // Check what device uP_ADDR corresponds to: // ROM? if ( (ROM_START <= uP_ADDR) && (uP_ADDR <= ROM_END) ) DATA_OUT = pgm_read_byte_near(rom_bin + (uP_ADDR - ROM_START)); else if ( (BASIC_START <= uP_ADDR) && (uP_ADDR <= BASIC_END) ) DATA_OUT = pgm_read_byte_near(basic_bin + (uP_ADDR - BASIC_START)); else // RAM? if ( (uP_ADDR <= RAM_END) && (RAM_START <= uP_ADDR) ) DATA_OUT = RAM[uP_ADDR - RAM_START]; else // 6821? if ( KBD <=uP_ADDR && uP_ADDR <= DSPCR ) { // KBD? if (uP_ADDR == KBD) { ... // handle KBD register } else // KBDCR? if (uP_ADDR == KBDCR) { ... // handle KBDCR register } else // DSP? if (uP_ADDR == DSP) { ... // handle DSP register } else // DSPCR? if (uP_ADDR == DSPCR) { ... // handle DSPCR register } } } else ////////////////////////////////////////////////////////////////// // R/W = LOW = WRITE { // RAM? if ( (uP_ADDR <= RAM_END) && (RAM_START <= uP_ADDR) ) RAM[uP_ADDR - RAM_START] = DATA_IN; else // 6821? if ( KBD <=uP_ADDR && uP_ADDR <= DSPCR ) { // KBD? if (uP_ADDR == KBD) { ... // handle KBD register } else // KBDCR? if (uP_ADDR == KBDCR) { ... // handle KBDCR register } else // DSP? if (uP_ADDR == DSP) { ... // handle DSP register } else // DSPCR? if (uP_ADDR == DSPCR) { ... // handle DSPCR register } } } //////////////////////////////////////////////////////////////// // We are done with this cycle. // one full cycle complete clock_cycle_count ++; // start next cycle CLK_E_LOW; // If Arduino was driving the bus, no need anymore. // natural delay for DATA Hold time after CLK goes low (t_HR) DATA_DIR = DIR_IN; } 

地址空间分配可以随意完成,在未经修改的草图中,它与Apple 1相同,具有256字节的ROM,8 KB的BASIC ROM,4 KB的RAM和6821输入输出设备。

 // MEMORY LAYOUT // 4K MEMORY #define RAM_START 0x0000 #define RAM_END 0x0FFF byte RAM[RAM_END-RAM_START+1]; // ROMs (Monitor + Basic) #define ROM_START 0xFF00 #define ROM_END 0xFFFF #define BASIC_START 0xE000 #define BASIC_END 0xEFFF //////////////////////////////////////////////////////////////////// // Woz Monitor Code //////////////////////////////////////////////////////////////////// // PROGMEM const unsigned char rom_bin[] = { 0xd8, 0x58, 0xa0, 0x7f, 0x8c, 0x12, 0xd0, 0xa9, 0xa7, 0x8d, 0x11, 0xd0, ... 0x00, 0xff, 0x00, 0x00 }; // BASIC ROM starts at E000 PROGMEM const unsigned char basic_bin[] = { 0x4C, 0xB0, 0xE2, 0xAD, 0x11, 0xD0, 0x10, 0xFB, ... 0xE0, 0x80, 0xD0, 0x01, 0x88, 0x4C, 0x0C, 0xE0 }; 

RAM由字节RAM阵列[RAM_END-RAM_START + 1]进行仿真。 需要两个PROGMEM关键字,以便将仿真ROM的内容存储在微控制器的闪存中。

对6821的仿真足以使虚拟键盘和显示通过“终端”工作。 作者所追求的是Woz Monitor和BASIC的工作。

要仿真任何外围设备,您需要仔细阅读其数据表,并找出其具有的寄存器以及它们的用途。 仿真的便利在于您可以灵活地制作外围设备的软件类似物。

I / O设备位于微处理器的地址空间中;它们的访问方式与存储单元相同。 要使用“熨斗”外围设备,例如LCD显示屏,存储卡,声音输出,您需要在地址空间中分配一个位置。

参考文献:

www.6502.org
www.callapple.org/soft/ap1/emul.html
skilldrick.imtqy.com/easy6502
searle.hostei.com/grant/6502/Simple6502.html
wilsonminesco.com/6502底漆
SB组装商: www.sbprojects.net/sbasm

转到6809,其中包含:

两个八位电池A和B,可以组合为一个六位电池
两个16位堆栈索引
相对于指令计数器的寻址
自动加减1或2
两个八位无符号数字的乘法
16位算术
所有寄存器之间的数据传输和交换
写入和读取所有寄存器及其任意组合

微处理器6809E(外部)需要一个外部时钟,而6809E具有一个内部时钟。 在日立(Hitachi)中,它们分别称为6309E和6309,它们与通常的区别在于它们在操作内部以32位格式进行操作,但是可以使用经典版本切换到兼容模式。

实际上,整个RetroShield项目之所以开始是因为作者想要升级他的家用计算机Simon6809并将结果命名为Simon6809 Turbo。 但事实证明,要在其中实现所有功能的标准逻辑芯片都需要很多东西。 因此,作者首次提出了关于6809的RetroShield的想法,然后才想到:“如果与其他处理器相同会怎样?”。

该设备当然使用6809E,它需要一个外部时钟,以便它可以从外部同步其工作。 两个处理器的E和Q线命名相同,只有6809具有输出,而6809E具有输入。

Arduino与6809的交互方式与与6502相同,但它具有两个时钟输入:E和Q,以及三个中断输入:IRQ,FIRQ和NMI。



这次,Arduino端口和微处理器引脚之间的对应关系配置如下:

 /* Digital Pin Assignments */ #define DATA_OUT PORTL #define DATA_IN PINL #define ADDR_H PINC #define ADDR_L PINA #define ADDR ((unsigned int) (ADDR_H << 8 | ADDR_L)) #define uP_RESET_N 38 #define uP_E 52 #define uP_Q 53 #define uP_RW_N 40 #define uP_FIRQ_N 41 #define uP_IRQ_N 50 #define uP_NMI_N 51 #define uP_GPIO 39 

从图中可以看出,信号Q相对于E偏移了四分之一周期:

我们几乎不会关注Q,因为所有事件都与E相关联。所有事情都是这样发生的:



  1. E切换为零。 处理器在地址总线上设置一个新地址,并更改R / W线的状态。
  2. E切换为1,处理器准备进行数据交换。
  3. 只要E为1,数据总线发生什么变化都没有关系,主要的是,在E返回零时,所需的数据就存在于此。
  4. 读取数据时,I / O设备必须在线E从1变为零之前将所需的数据提供给数据总线(最小延迟由圆圈中的数字17表示)。
  5. 记录时,I / O设备必须将数据固定在某个寄存器中,其形式为E从1变为0时的状态。 处理器将更早地在总线上提供此数据-在Q转换为1时(圈中的数字20)。
  6. E转换为零后,所有重复。

上面关于6502所说的一切都涉及到需要一个外围设备(包括虚拟设备)来按时显示所有信号的问题6809。

信号E和Q的生成(如6502的情况一样),唯一的区别是存在两个信号,必须根据曲线图进行切换。 就像这样,被中断调用的子例程在所需的时刻执行数据输入或输出。

未经修改的草图中的地址空间的分配方式与国产Simon6809计算机中的分配方式相同:

 // MEMORY #define RAM_START 0x0000 #define RAM_END 0x0FFF #define ROM_START 0xE000 #define ROM_END 0xFFFF byte RAM[RAM_END-RAM_START+1]; //////////////////////////////////////////////////////////////////// // Monitor Code //////////////////////////////////////////////////////////////////// // static const unsigned char PROGMEM const unsigned char simon09_bin[] = { 0x1a, 0xff, 0x4f, 0x1f, 0x8b, 0x0f, 0x36, 0x7f, 0x01, 0xa5, 0x10, 0xce, ... 0x00, 0x09, 0x00, 0x0c, 0x00, 0x0f, 0xe0, 0x00 }; 

RAM和ROM以与6502变体相同的方式存储在阵列中,唯一的区别是只有一个带有ROM数据的阵列。

I / O设备也分配了地址空间的一部分,它们可以是虚拟的也可以是真实的。 由于Simon6809是基于老式元素基础的现代机器,因此它通过FTDI从运行“终端”的PC上交换数据。 在这里被模拟。

参考文献:

Arto页面上有关6809的更多信息
维基百科关于6809的文章
SWTPc 6809系统
有关FLEX操作系统的维基百科文章

Source: https://habr.com/ru/post/zh-CN446048/


All Articles