古老CPU启示录-MC14500 1位CPU(ICU)
简介
在20世纪80年代4位、8位CPU逐渐成为主流,但是当时的CPU发展还处于探索阶段,所以各种“奇葩”的CPU都有出现,今天给大家带来1-bit CPU MC14500和GI SBA。两者差不多以MC14500为例看下这款“奇葩”CPU。
MC14500是一种工业控制单元(ICU),也被认为是1位处理器。它由摩托罗拉(Motorola)生产,但几年前已停止生产。如今,MC14500已经被价格合理的FPGA取代了,包括其所有外设和程序存储器。至今仍存在使用MC14500设计的不同原因:
1、为旧的MC14500计算机创建备件;
2、重复使用MC14500软件;
3、FPGA开发(VHDL代码=>电子专家)与应用程序(应用工程师)之间的分离;
4、低成本PLC替代品;
5、在现代FPGA上运行具有历史意义的东西很有趣;
6、使用FPGA的学习项目。
框图
数据手册:http://www.brouhaha.com/~eric...
特点:
(1)16条指令;
(2)编程容易;
(3)容易掌握,不需要特殊的技术人员;
(4)由于使用外部存储器,系统变得容易;
(5)能满足用户的特定需求,具有丰富的灵活性;
(6)能满足用户的特定需求,具有丰富的灵活性;
(7)能够扩展以适应所有系统的规模和复杂程度;
(8)能够进行程序设计;
(9)B系列C-MOS符合JEDE规格;
(10)噪音容限大;
(11)不工作时漏电流小;
(12)工作电压3~18V;
(13)时钟频率范围广,一般工作频率1MHz(VDD=5V,一个时钟执行一条指令);
(14)信号输入和TTL互换;
(15)将判断作为中心工作,超过微处理器的性能;
(16)应用范围广,由继电器回路开始的逻辑判断处理到中速度的串行数据处理,还能减轻超负荷的微处理器系统的工作。
MC14500允许使用IO地址读取输入位。该位可以使用4位指令和内部1位结果寄存器RR进行处理。结果可以写入IO地址的输出位。
输入和输出数据位可以是物理输入和输出,其中可以连接电线,但它们可以连接到其他设备作为RAM或定时器。
IO的寻址完全在MC14500外部完成。MC14500的所选指令的4位和外部IO多路复用器的IO地址行导致程序存储器的数据宽度。MC14500使用术语“内存字”来表示从程序内存中输出的数据。本文档使用术语“command”作为“memory word”的同义词。因此,命令由两部分组成:指令和IO地址。
由于IO地址在MC14500的外部,因此不同实现之间的命令可能不同。此外,命令中4个指令位的位置也取决于设计。指令位可能占用命令中的高位或低位。
MC14500不包含从程序存储器中寻址要处理的命令的程序计数器。因此,MC14500设计的程序计数器位数可能不同。
程序内存或命令的宽度是指令的4位加上IOaddress行数。小型MC14500设计将使用8位宽的程序存储器,能够选择多达16个IO地址。由于这并不多,许多MC14500设计使用12位宽的程序存储器,可以选择多达256个IO地址。12位宽的程序存储器使用过去存在的4位宽的ROM设备。其他MC14500设计使用8位宽的程序存储器,但是每个MC14500命令有两个字节被读取,因此形成了一个16位宽的命令,能够寻址多达4096个IO地址线,用于物理IO、单位宽RAM和定时器硬件。在MC14500设计中,从程序存储器中读取两次会产生另一种变化,从程序中读取的第一个字节可能在一种设计中是低字节,但在另一种设计中是命令的高字节。指令集如下:
利用MC14500搭建的外围系统:
MC14500模拟器
MC14500模拟器使用web技术和javascript来独立于平台,并且在将来也可以使用。这种实现的一个缺点是javascript模拟器不能访问用户的文件系统或硬件。
模拟器在支持svg的浏览器上运行。模拟器使用的硬件架构如下图所示。
地址:https://www.linurs.org/mc1450...
按下“步进”按钮意味着下降的时钟边缘,因此MC14500加载指令和输入数据。
释放“步进”按钮意味着上升的时钟边缘,因此MC14500写入数据。程序计数器增加。在程序存储器访问时间之后,下一条指令和IO地址出现在MC14500和输出、输入或RAM上。
详细的介绍就不过多赘述,网上还有利用Python进行汇编程序和反汇编程序的介绍。
FPGA实现
利用MC14500搭建的CPU
从上面的介绍可以看出MC14500和FPGA有很多相似的地方,接下来就用FPGA实现一下这款单比特CPU。
module mc14500b(
input clk,
input rst,
input [3:0] i_inst,
input i_data,
output reg write = 0,
output reg jmp = 0 ,
output reg rtn = 0,
output reg flag0 = 0,
output reg flagf = 0,
output reg o_rr = 0,
output reg o_data = 0
);
reg ien = 0, oen = 0;
reg skip = 0;
always @(negedge clk or posedge rst) begin
// Reset any flags from last clock.
jmp <= 0;
rtn <= 0;
flag0 <= 0;
flagf <= 0;
write <= 0; // FIX this it's not right technically.
if (rst) begin
// reset behavior. reset internal flags and ignore clock.
ien <= 0;
oen <= 0;
o_rr <= 0;
skip <= 0;
end else begin
if (~skip) begin // skip
case(i_inst)
4'b0000 : flag0 <= 1; // NOPO
4'b0001 : o_rr <= ien & i_data; // LD
4'b0010 : o_rr <= ien & ~i_data; // LDC
4'b0011 : o_rr <= ien & (i_data & o_rr); // AND
4'b0100 : o_rr <= ien & (~i_data & o_rr); // NAND
4'b0101 : o_rr <= ien & (i_data | o_rr); // OR
4'b0110 : o_rr <= ien & (~i_data | o_rr); // NOR
4'b0111 : o_rr <= ien & (o_rr == i_data); // XNOR
4'b1000 : begin // STO
// DATA -> RR, WRITE -> 1 for a clock (if oen is allowed).
o_data <= oen & o_rr;
write <= oen;
end
4'b1001 : begin // STOC
// DATA -> ~RR, WRITE -> 1 for a clock.
o_data <= ~o_rr;
write <= oen;
end
4'b1010 : ien <= i_data;
4'b1011 : oen <= i_data;
4'b1100 : jmp <= 1;
4'b1101 : begin // RTN
rtn <= 1;
skip <= 1;
end
4'b1110 : skip <= ~o_rr;
4'b1111 : flagf <= 1;
endcase
end
else begin // reset skip flag after clocking with skip once.
skip <= 0;
end
end
end // neg edge
// always @(posedge clk) begin
// write <= 0;
// end
endmodule
“CPU是复杂的状态机”,仿真之类的详见:
https://github.com/suisuisi/o...
整体比较简单就不解释了。
原出处:FPGA 的逻辑
作者:碎碎思
相关文章推荐
更多FPGA技术干货请关注FPGA 的逻辑技术专栏。