您当前的位置:首页 >> 聚焦 >  >> 
减法器的设计与实现并用译码器显示16、10进制_天天速看料
来源: 博客园      时间:2023-05-25 15:41:57

大家新年好,我是呼噜噜,在上一篇简易加法器里我们了解了半加器和全加器的设计与实现,今天我们来看下CPU中减法器是如何实现的。文章比较长,大家可以收藏反复观看

计算机为什么利用反码来实现减法?

我们来看一个最常见的例子,2-1 =1这是减法,但它等同于2+ (-1) =1这其实是加法。从运算逻辑上来说,减法可以通过加法来实现,这是可行的。从硬件电路层面说,我们很容易让电子实现汇总的效果,但是将电子群拆分出多个更小的集群,是不容易的。还有一个好处是利用加法器能实现减法的效果的话,就不需要再为减法器专门设计电路了,降低了电路的复杂度。

由于计算机采用的是二进制,和我们天生熟悉的十进制还是有区别的,那么二进制能否实现用加法来实现减法效果?


(资料图)

很幸运地是,当初那群计算机那群工程师大拿将二进制玩的是炉火纯青,通过原码->反码->补码,一步步实现了二进制通过加法来实现减法效果。其中原理大家感兴趣地,可以看看笔者之前的一篇文章 计算机中数值和字符串怎么用二进制表示?

补码真的是一个天生完美的奇妙存在,基于补码的机制,减法可以转化为加法,也就意味着计算机可以通过加法器实现减法。

看完笔者的那篇文章,我们知道了补码产生的手动:正数原码不变,负数的符号位不变, 其余各位取反, 最后一位+1

减法器的实现

要实现原码到补码的转换,需要一个取反器,我们先来写出减法逻辑的真值表:

通过真值表,我们可以很容易发现这其实就是一个异或门(相同为0,不同为1)

我们来实现一个8位的取反器,由于是8位的,所以输入选这8位输入,还得连一个8位的分线器,输出类似。异或门得有8个,每个都需和控制是否取反的输入相连。

我们将之前的全加器和减法器结合起来,需要注意的是补码需要取反再+1,取反可以将输入和取反器相连,+1可以将全加器最低位的进位控制取反的输入相连即可,极简单又巧妙

我们来启动模拟,看下效果:

上图计算结果,相当于:

1+1 =21-1 =0

但是上面有个问题是,1-1=0时,虽然灯泡是0,但是旁边的溢出标志显示溢出了,我们还需改造一下。我们这里简单地,就直接让减法不溢出即可(这种处理方式还是比较粗暴的,但是实现起来比较简单)我们来写出溢出输入IY,是否取反输入IF(如果取反,就代表是减法操作),溢出输出O的真值表关系

IYIFO
000
101
010
010

我们可以推出公式:O=非IF * IY,所以需要非门和与门

这样就减法时,就不会溢出了。但其实这个加法器只能做正数的减法(也就是输入A得大于等于输入B),如果最后结果为负数的,还是有bug的。我们后面有机会再优化

7段数码管16进制显示

由于用灯泡表示二进制,每次得出的结果,还要我们去换算成10进制,非常不直观,我们接下来利用数码管,来将二进制数"翻译"成10进制数。

我们这边利用的是7段数码管来实现的,数码管其实就是多个LED灯,不同的位控制不同的LED。从第0位到第7位,通过控制不同的LED来组合出数字。第7位比较特殊,数码管显示的是点

我们用上面的电路,一一将0~F16个数显示出来,各个开关的情况记录成下面的表:

数值开关(2进制)HEX(16进制)
00011 11110x3F
10011 00000x06
20101 10110x5B
30100 11110x4F
40110 01100x66
50110 11010x6D
60111 11010x7D
70000 01110x07
80111 11110x7F
90110 11110x6F
A0111 01110x77
b0111 11000x7C
C0011 10010x39
D0101 11000x5E
E0111 10010x79
F0111 00010x71

这其实就是7段数码管的共阴极对照表,还有共阳极对照表这里我们就不展示了。

如果直接用组合电路来封装8位输入,7段数码管的16进制显示,的确是可以的,但如果是16位,32位,64位输入,电路会异常的复杂,我们这边用储存器ROM来实现这个功能

ROM只读存储器,是以非破坏性读出方式工作,它非易失性存储器,当电源被移除时,其数据内容不会被擦除,它还有个特点就是只能读出而不能写入信息,其所存的数据,一般是装入整机前事先写好的,整机工作过程中只能读出。

需要注意的是: 虽然ROM和硬盘有一些共性,但不能简单地说ROM就是硬盘

常常与ROM相比的还有一个RAM(随机存取存储器),也就是我们常说的主存,是与CPU直接交换数据的内部存储器,它的特点:随机存取、数据易失、对静电敏感、访问速度快、需要刷新。RAM在断电以后保存在上面的数据会自动消失

我们使用ROM和7段数码管来显示16进制的数0~F,选用地址位宽为4,数据位宽为8,只需把对应的数据提前写入对应的地址中即可。

这里需要注意一下,为什么我们选用地址位宽为4,数据位宽为8的ROM

首先我们需要明白(1111 1111)2 = (f f)16, 7段数码管可以表示0~F 16进制数,我们可以用2个7段数码管并联将8位二进制数译码成16进制数。我们就先考虑1个7段数码管和ROM的关系,单个"f"也就是第16个数,也就是说4位二进制,即4位输入,最大值为16

地址位宽为4, 可以保证寻址2^4=16,分别对应十六进制下的0~F数据位宽为8,相当于2个7段数码管,一个7段数码管需要4位输入,2个就是8位输入

我们想显示16进制数,0~F,我们需要4位二进制输入,其最大值1111,就是16(F),结合上面的共阴极对照表,我们就能总结下面的表:

A3A2A1A0NumberHEX(16进制)
000000x3F
000110x06
001020x5B
001130x4F
010040x66
010150x6D
011060x7D
011170x07
100080x7F
100190x6F
1010A0x77
1011b0x7C
1100C0x39
1101d0x5E
1110E0x79
1111F0x71

根据对应关系,我们把电路和存储器相应地址数据预先填进去

我们启动模拟看下效果:

测试完成后,将4个开关换成4位输入。接着我们将2个4位16进制译码器并联,就成了8位16进制译码器,并封装一下:

并将它与上文的全加器与减法器结合起来:

nice!

7段数码管10进制显示

通过上一小节,我们成功把8位二进制数,"翻译"成16进制数,但距离我们更熟悉的十进制还是有点距离的,我们本小节继续改进7段数码管,实现10进制的译码

由于(1111 1111)2 = (255)10, 最大值为255

ROM需要8位地址位宽,2^8 = 256,确保能够将256个数(0 ~255)全部找到;255是3位数,我们至少需要3个数码管(也就是我们上一小节封装的4位16进制译码管),1个数码管需要4位输入,所以ROM数码管的数据位宽为12

更多精彩文章在公众号「小牛呼噜噜」

电路实现:我们可以使用8个开关,来表示8位输入;选用8位地址位宽且数据位宽为12的ROM,通过8位3针脚的分线器和3个4位16进制译码管相连即可。

由于ROM的查找表有255个数,不能像之前一样一个个手动填写,我们可以利用Python来实现(电脑中需要有Python3的环境)。

将其另存到桌面上为test.bin文件,用vscode打开该文件(需要安装 hex editor插件来显示二进制),以小端显示:

test.py:

with open("test.bin", "wb") as f:    for i in range(256):        var = str(i)        var = int(var, base=16) //先转成16进制        byte = var.to_bytes(2, byteorder="little")// 再转化成二进制,以显示小端        print(byte)        f.write(byte)

将其放到test.bin 同级目录后,直接运行命令python test,py后,test.bin就变成了:

这种55 02 其实是25531 02231, 像这种55 02就是小端表示法。

将test.bin 重新加载到ROM中

我们来启动模拟看看:

我们将输入替换开关,然后封装成8位10进制译码器电路,接上之前的减法器的电路:

21选择器 增强 10进制显示

我们现在有个需求,001,前面的0不想要,就想要1,我们借助21选择器来实现 高位为零时,数码管不亮

我们先来看一下1位21选择器,首先有2个输入,分别为A和B,以及一个有效位EN,一个输出S。我们的目的是实现:有效输出A,无效输出B。根据目的我们可以写出真值表:

ENABS
0000
0011
0100
0111
1000
1010
1101
1111

我们可以得出公式 S = EN与A + 非EN与B,进而可以画出电路图

封装后,模拟一下:

我们继续画出8位21选择器,只需将8个1位21选择器组合在一起:

将其封装一下,接着模拟测试:

7段数码管10进制显示增强的电路,我们再重新设计一下:

更多精彩文章在公众号「小牛呼噜噜」

最后把其封装一下,放到减法器和加法器的电路中,演示一下:

完美,这样就实现了我们的目的。

尾语

本文我们将上一小篇文章中的简易加法器进行来改进,通过补码,让加法器也是运算减法。接着为了让我们观察结果更加方便,我们使用了7段数码管实现了 16进制、10进制显示,最终优化了10进制显示,使其只显示有效位的数值。

本系列到目前为止主要是组合逻辑电路的相关知识,后续我们会探究时序逻辑电路的奥秘,来看看开关究竟是如何实现CPU除计算功能外另一个重要的功能"记忆功能"。

参考资料:

一个8位二进制CPU的设计和实现,踌躇月光《编码:隐匿在计算机软硬件背后的语言》《穿越计算机的迷雾》深入浅出计算机组成原理,徐文浩运行内存,百度百科

全文完,感谢您的阅读,如果我的文章对你有所帮助的话,还请点个免费的,你的支持会激励我输出更高质量的文章,感谢!

原文镜像:https://mp.weixin.qq.com/s/QXWm-s-v3VuYV7s4-uE7yA

计算机内功、源码解析、科技故事、项目实战、面试八股等更多硬核文章,首发于公众号「小牛呼噜噜」,我们下期再见!

标签:

X 关闭

X 关闭