第二次作业博客
前言:
第三次到第六次作业的难度在一次次提升,从单一基础门电路逐步扩展到包含译码器、数据选择器、数据分配器等复杂组合逻辑组件到最后的子电路。通过这三次迭代开发,我对面向对象设计、事件驱动模拟以及数字电路的基本原理有了更深入的理解。考察了基础的逻辑(门等电子原件),继承(每个类继承Gate).
知识点覆盖
三次作业涉及的核心知识点包括:
数字逻辑基础:与、或、非、异或、同或等基本逻辑运算
组合逻辑电路:译码器(Decoder)、数据选择器(Mux)、数据分配器(Demux)的工作原理
三态逻辑:高阻态的概念及三态门的控制机制
面向对象设计:类的继承、多态、封装
输入解析:字符串处理、正则表达式替代方案
| 作业 | 核心内容 | 新增组件 | 题量 | 难度 |
| 作业一 | 基础门电路仿真 | AND、OR、NOT、XOR、XNOR | 5 种基础门 | 入门 |
| 作业二 | 三态门与译码器 | TriState(S)、Decoder(M) | 2 种新组件 | 中等 |
| 作业三 | 数据选择器与分配器 | Mux(Z)、Demux(F) | 2 种新组件 + 复杂电路 | 困难 |
此为该三此作业的题目要求,
数字电路是一种处理离散信号的电子电路。与处理连续变化信号(如声音、温度)的模拟电路不同,数字电路只识别和运算两种基本状态:高电平(通常表示为“1”) 和 低电平(通常表示为“0”)。这正好与二进制数制系统相对应,使得数字电路成为所有计算机和数字系统的物理实现基础。
请编程实现数字电路模拟程序,
1、电路元件
电路中包含与门、或门、非门、异或门、同或门五种元件。元件特征如下:
与门:
包含两个或多个输入引脚和一个输出引脚。所有输入引脚必须都是高电平,输出引脚才是高电平,只要有一个输入引脚为低电平,输出引脚输出低电平。
或门:
包含两个或多个输入引脚和一个输出引脚。所有输入引脚必须都是低电平,输出引脚才是低电平,只要有一个输入引脚为高电平,输出引脚输出高电平。
非门:
包含一个输入引脚和一个输出引脚。输出引脚的电平与输入引脚的电平相反,如输入为低电平,输出则为高电平。
异或门:包含两个输入引脚和一个输出引脚。当两个输入引脚电平不一致时输出引脚输出高电平,否则输出低电平。
同或门:包含两个输入引脚和一个输出引脚。当两个输入引脚电平一致时输出引脚输出高电平,否则输出低电平。
2、程序输入
(1)元件信息:
用A、O、N、X、Y 分别用作与门、或门、非门、异或门、同或门五种元件的元件标识符。
电路中的每个与门、或门用“标识符(输入引脚数)+编号”作为其元件名。
例如:A(8)1表示一个8输入引脚的与门,O(4)2代表一个4输入引脚的或门。
电路中的每个非门、异或门、同或门用“标识符+编号”作为其元件名。
例如:X8表示一个异或门,Y4代表一个同或门,N1代表一个非门。
约束条件:
不同元件的编号可以相同,如X4、Y4。
同一电路中同种元件的编号不可重复,可以不连续
2)引脚信息:
引脚信息由“元件名-引脚号”构成,。
例如:A(8)1-2代表与门A(8)1的2号引脚。
3)电路的输入信息:
电路的输入格式:
INPUT:英文空格+输入1+”-”+输入信号1+英文空格+输入2+....+输入n+”-”+输入信号n
例如:
“INPUT: A-0 B-1 C-0”代表整个电路包括3个输入:A、B、C 分别输入0,1,0信号。
4)连接信息
引脚的连接信息格式:
[+输出引脚+英文空格+输入引脚1+。。。。+英文空格+输入引脚+]
例如:
[A A(8)1-1 A(8)1-3 X5-2]
代表信号从引脚A发送给与门A(8)1的1、3两个引脚,以及异或门X5的2号引脚。
[Y8-0 N1-1 O(4)2-3 Y2-1]
代表信号从引脚Y8-0发送给非门N1的1号引脚、或门O(4)2的3号引脚、同或门Y2的1号引脚。
约束条件:
一个输出引脚可以连接多个输入引脚,即将输出引脚的信号传给每一个输入引脚。但一个输入引脚不能连接多个输出引脚。
输出引脚不能短接在一起。
5)输入结束信息
所有输入以end为结束标志,end之后出现的内容忽略不计
3、程序输出
按照与门、或门、非门、异或门、同或门的顺序依次输出所有元件的输出引脚电平。同类元件按编号从小到大的顺序排序。
如果某个元件的引脚没有接有效输入,元件输出无法计算,程序输出结果忽略该元件
4、测试输入默认满足以下条件:
1)每个元件的输入引脚连续编号。假设元件有n个输入引脚,则其编号取值范围为[1,n],且引脚号不重复。
2)本题涉及的五种元件都只有一个输出引脚,输出引脚号默认为0。
5、后续迭代设计
数字电路模拟程序1(本次作业):
基础逻辑门元件构成电路
数字电路模拟程序2:
1、包含多输入输出的组合电路元件如数据选择器;
2、元件引脚类型除输入、输出之外,增加控制引脚,如三态门。
数字电路模拟程序3:
增加带反馈的电路、时序电路元件,如D触发器、JK触发器。
数字电路模拟程序4:
1、增加子电路;
2、增加程序异常输入的检测。
这为这三次题目集的题目要求.
第一次PTA:
知识点覆盖:
本次作业涉及的核心知识点包括:
基本逻辑运算:与(AND)、或(OR)、非(NOT)、异或(XOR)、同或(XNOR)的布尔代数原理;
面向对象继承与多态:通过 Gate 基类和子类重写 calc() 方法实现多态;
输入解析与字符串处理:解析 [A-0 B-0 A(2)1-1] 等格式的连节语句;
核心的性质:对于类的继承和多态,以及对于电子元件的使用以及输入输出原理;

设计原理:
| AND | A | ≥2 | 1 | 全1出1,有0出0 |
| OR | O | ≥2 | 1 | 有1出1,全0出0 |
| NOT | N | 1 | 1 | 输入取反 |
| XOR | X | 2 | 1 | 输入不同出1,相同出0 |
| XNOR | Y | 2 | 1 | 输入相同出1,不同出0 |
通过一个类去被继承,使复用性更强, Gate 封装所有组件的公共属性和行为,5 个子类通过重写 calc() 方法实现各自的逻辑功能。
遇到的困难:引脚储存问题,对于题目要求的储存模式或者格式不了解,导致储存刚刚开始,后面询问AI获得思路(引脚存储策略:pins[]/vals[] 并行数组
使用两个并行数组 pins[] 和 vals[] 存储已设置的引脚号和对应值,cnt 记录实际数量。这种设计避免了为所有引脚预分配空间,同时支持稀疏引脚设置。)
踩坑心得:
Bug 1 - 严重程度:低
初始输出格式为 A(2)1-0,缺少冒号和输出值的展示。正确格式应为 A(2)1-0:1。
Bug 2:连接覆盖而非追加
Bug 2 - 严重程度:中
在解析连接时,使用 self.connections[output_pin] = input_pins 直接赋值,导致一个输出引脚只能连接一个目标。当同一个 source 连接多个 target 时,后者会覆盖前者。
Bug 3 - 最初误以为所有门的输出引脚都是从1开始编号,实际上基础门(AND/OR/NOT/XOR/XNOR)的输出引脚固定为0,输入引脚从1开始。
质量分析:


改进:
1.引脚号越界(如给 2 输入门设置引脚 3)
2.循环连接检测.
第二次PTA:
在基础逻辑门之上,本次作业引入了三态门和译码器,增加了控制信号和多输出机制,电路复杂度显著提升。
本次作业涉及以下核心知识点:
1.三态门除了输出 0 和 1 之外,还可以输出null,使输出端与电路断开,不参与信号传播
2.译码器工作原理:通过使能信号 S1/S2/S3 控制译码器是否工作,输入编码选择对应的输出端
3.控制引脚概念:控制引脚决定组件的使能状态,区别于普通数据输入引脚

(此为新增的类图图)
我的思路和设计逻辑:
通过了解输入与输出去思考控制电路对于原件的影响,以及控制电路在电路中的优先级是否高于输入或者输出电路;(Decoder 的三个控制引脚 S1、S2、S3 构成使能条件:S1=1 且 S2=0 且 S3=0。只有当三个条件同时满足时,Decoder 才执行译码操作;否则 valid=false,输出全部为 null;Decoder 的输出格式为 M(3)1:3,其中冒号后的数字是选中的输出索引(即输入编码的值),而不是引脚号。例如 M(3)1 表示 3-to-8 译码器的第 1 个实例,输出索引为 3 意味着第 3 号输出端被选中(输出 0,其余输出 1)。)等等.
TriState(S) 计算逻辑
读取控制引脚:ctrl = get(0)
如果 ctrl == 1(使能):out[0] = get(1),将输入值传递到输出
如果 ctrl == 0(禁用):out[0] = null,输出null;
代码质量:


踩坑心得:
Bug 1:TriState ready条件判断不完整
最初只检查控制引脚是否有值,没有检查输入引脚。当控制引脚为1时,如果输入引脚还没有值,直接读取会返回-1(未初始化)。[同时检查输入输出引脚即可];
Bug 2:Decoder使能信号判断错误
Decoder的控制引脚使能条件是 (1,0,0),即控制引脚0=1、控制引脚1=0、控制引脚2=0。如果判断条件写错,译码器永远不会使能或总是使能。[对于题目的了解出现错误,使能判断失误,全0才可以使能,而控制引脚必须是(1,0,0)才可以.]
改进:
AND门:全1、有0、单输入;
TriState:控制=0(高阻)、控制=1(直通);
Decoder:所有输入编码组合;
第三次PTA作业:
特殊需求:
2、程序输入
1)元件信息:
用A、O、N、X、Y 分别用作与门、或门、非门、异或门、同或门五种元件的元件标识符。
电路中的每个与门、或门用“标识符(输入引脚数)+编号”作为其元件名。
例如:A(8)1表示一个8输入引脚的与门,O(4)2代表一个4输入引脚的或门。
电路中的每个非门、异或门、同或门用“标识符+编号”作为其元件名。
例如:X8表示一个异或门,Y4代表一个同或门,N1代表一个非门。
约束条件:
不同元件的编号可以相同,如X4、Y4。
同一电路中同种元件的编号不可重复,可以不连续
2)引脚信息:
引脚信息由“元件名-引脚号”构成,。
例如:A(8)1-2代表与门A(8)1的2号引脚。
3)电路的输入信息:
电路的输入格式:
INPUT:英文空格+输入1+”-”+输入信号1+英文空格+输入2+....+输入n+”-”+输入信号n
例如:
“INPUT: A-0 B-1 C-0”代表整个电路包括3个输入:A、B、C 分别输入0,1,0信号。
4)连接信息
引脚的连接信息格式:
[输出引脚+英文空格+输入引脚1+。。。。+英文空格+输入引脚]
例如:
[A A(8)1-1 A(8)1-3 X5-2]
代表信号从引脚A发送给与门A(8)1的1、3两个引脚,以及异或门X5的2号引脚。
[Y8-0 N1-1 O(4)2-3 Y2-1]
代表信号从引脚Y8-0发送给非门N1的1号引脚、或门O(4)2的3号引脚、同或门Y2的1号引脚。
约束条件:
一个输出引脚可以连接多个输入引脚,即将输出引脚的信号传给每一个输入引脚。但一个输入引脚不能连接多个输出引脚。
输出引脚不能短接在一起。
5)#子电路信息(本题在数字电路模拟程序-1基础上新增的内容)
可以将一部分电路设定为一个子电路,子电路可以在主电路中被引用。子电路的输入按顺序包括以下几部分:
子电路起始信息:C+子电路编号+:
子电路输入信息:
INPUT:输入1+英文空格+输入2+英文空格+....+英文空格+输入n,
子电路输出信息:
OUT:输出1+英文空格+输出2+英文空格+....+英文空格+输出n,
子电路连接信息:(格式与主电路输入信息相同),子电路的元件编号与主电路中的编号可能相同。
子电路结束标志:endc
输入、输出信息的编码可以作为子电路的引脚号在主电路中引用。
子电路元件输出时带上子电路的编号,格式为:子电路编号+“-”+元件编号+“-”+引脚号+“:”+引脚输出
例如:定义一个编号2的子电路,包含A、B两个输入和一个输出O:
C2:
INPUT:A B
OUT:C
[A X1-1]
[B X1-2]
[X1-0 Y1-1]
[A Y1-2]
[Y1-0 C]
endc
主电路中的运用:
INPUT: A-1 B-1
[A C2-A]
[B C2-B]
[C2-C N1-1]
[N1-0 OUT]
end
输出信息:
C2-X1-0:0
C2-Y1-0:0
N1-0 :1
所有子电路信息都在主电路信息之前定义完成。
6)#异常输入信息(本题在数字电路模拟程序-1基础上新增的内容)
当出现各类异常输入情况时,电路应输出相应提示,异常情况包括:
1.一个连接信息中包含两个或多个输入,输出:ERROR:“连接信息”+“英文空格”+include more than one input
例如:
INPUT: A-1 B-1
[A B A2-1]
应输出:
ERROR: [A B A2-1] include more than one input
2.一个连接信息中没有输入信息,输出:ERROR:“连接信息”+“英文空格”+include none input
例如:
INPUT: A-1 B-1
[C1-1 C2-1]
应输出:
ERROR: [C1-1 C2-1] include none input
注意:C1-1 C2-1引脚是元件的输入引脚,但作为连接信息,元件的输入引脚属于连接系统的输出,所以是none input
3.一个连接信息中没有输出,输出:ERROR:“连接信息”+“英文空格”+include none output
例如:
INPUT: A-1 B-1
[A]
应输出:ERROR: [A] include none output
4.一个连接信息中输入输出写反,输出:ERROR:“连接信息”+“英文空格”+input and output sequence error
例如:
INPUT: A-1 B-1
[A2-1 A]
应输出:ERROR: [A2-1 A] input and output sequence error
5.一个输入引脚接受中来自多个不同输出的信号,输出:ERROR:“输入引脚”+“英文空格”+input signal conflict
例如:
INPUT: A-1 B-1
[A A2-1]
[B A2-1]
应输出:ERROR: A2-1 input signal conflict
注:如果一条输入出现了多种异常,按以上异常先后顺序为优先级,顺序靠前者优先级越高,最后输出优先级最高的异常输出。
当电路输入信息中多条输入都包含异常,只处理排在最前面的异常信息。
7)输入结束信息
所有输入以end为结束标志,end之后出现的内容忽略不计
3、程序输出
按照与门、或门、非门、异或门、同或门的顺序依次输出所有元件的输出引脚电平。同类元件按编号从小到大的顺序排序。
如果某个元件的引脚没有接有效输入,元件输出无法计算,程序输出结果忽略该元件
4、测试输入默认满足以下条件:
1)每个元件的输入引脚连续编号。假设元件有n个输入引脚,则其编号取值范围为[1,n],且引脚号不重复。
2)本题涉及的五种元件都只有一个输出引脚,输出引脚号默认为0。
5、后续迭代设计
数字电路模拟程序1(本次作业):
基础逻辑门元件构成电路
数字电路模拟程序2:
1、包含多输入输出的组合电路元件如数据选择器;
2、元件引脚类型除输入、输出之外,增加控制引脚,如三态门。
数字电路模拟程序3:
增加带反馈的电路、时序电路元件,如D触发器、JK触发器。
数字电路模拟程序4:
1、增加子电路;
2、增加程序异常输入的检测。
知识点覆盖
组合逻辑电路:译码器(Decoder)、数据选择器(Mux)、数据分配器(Demux)的工作原理
事件驱动模拟:信号传播、级联计算、迭代收敛
输入解析:字符串处理、正则表达式替代方案
类图:

代码质量


改进:
Bug 1:BFS队列无限循环
最初的仿真使用递归方式传播信号,当电路存在反馈回路时会导致栈溢出或无限循环。Decoder的valid=false时会导致反复重新计算。
Bug 2:输入传播键名不匹配
外部输入信号的名称格式与门电路引脚查找的格式不一致。例如外部输入叫 "A",但门电路内部查找时用的是 "A-0"(引脚0)。
Bug 3:输出引脚编号错误
对于新增加的门电路(TriState、Decoder、Mux、Demux),outName() 方法返回的引脚编号错误,导致输出信号名称与预期不符。
核心收获:
面向对象设计:通过Gate基类+子类继承的方式,9种门电路共享通用逻辑(引脚管理、就绪判断),各自只需实现特定的calc()方法。深刻体会到"封装变化,复用共性"的设计思想。
边界条件的重要性:引脚编号、控制编码方向、使能条件等"小"细节往往是bug的根源。工程实践中必须对每个边界条件进行显式处理和测试。
数字电路基础:深入理解了逻辑门真值表、三态逻辑、译码器/选择器的工作原理,以及控制信号编码(LSB/MSB)对电路行为的影响。
代码防御性编程:isOutputPin()保护ready()完整性检查等机制,都是防御性编程思想的体现。
需要进一步学习的地方:
字符串数组的储存内容的使用;
异常处理:自定义异常类,提高程序的可维护性
算法优化:拓扑排序检测电路环路、更高效的事件队列实现
总结:
这三次作业从简单到复杂,逐步构建了完整的数字电路仿真系统。虽然过程中遇到了大量bug(特别是BFS无限循环和控制编码方向问题),但正是这些坑让我对事件驱动仿真和面向对象设计有了更深刻的理解。特别是作业三的复杂电路调试让我深刻认识到边界条件和编码细节的重要性——"看输出猜逻辑"的投机取巧心态必须摒弃,要养成"严格按规格实现、逐条验证边界"的工程习惯。
浙公网安备 33010602011771号