MIPS单周期CPU_完整超清讲解版
看透 CPU 的灵魂:单周期 MIPS 数据通路动态解析
在计算机组成原理(CO)的星辰大海中,数据通路(Data Path)无疑是那颗最硬、也最亮的核。对于备战 408 考研或深耕计算机底层架构的同学来说,仅仅盯着课本上那张密密麻麻的静态图是远远不够的。
为了彻底撕开指令执行的"黑盒",我利用 Manim 引擎制作了一段精细化的单周期 MIPS CPU 动画。本文将带你拆解其中的核心逻辑。
- 为什么是单周期 MIPS?
虽然现代处理器早已进入超标量和乱序执行时代,但单周期 MIPS 是所有现代架构的基石。它的逻辑极其纯粹:一个时钟周期完成一条指令。
这意味着:
无流水线冲突:不需要考虑数据冒险或控制冒险。
逻辑直观:信号从 PC 出发,经过组合逻辑,最终回到寄存器或存储器。
考研重灾区:无论是 LW、SW 还是 BEQ,数据通路的每一次转向都是考点。
- 核心组件的"角色分配"
在动画中,我通过特定的色彩和布局对硬件进行了模块化处理:
🛠️ 基础设施层
PC (Program Counter):整个系统的"领跑者",决定了下一条指令的地址。
指令存储器 (IM):只读空间,根据 PC 提供的地址吐出 32 位的机器码。
🧠 加工与计算层
寄存器堆 (RegFile):CPU 的高速暂存区。动画中特意区分了 R1、R2(读地址)和 W(写地址)。
ALU (算术逻辑单元):心脏部位,负责执行所有的加减跟位运算。
🚥 控制通路 (Control Unit)
这是动画中最"烧脑"的部分。控制器根据指令的 Opcode 和 Funct 字段,像交警一样指挥多路选择器(Mux):
RegDst:决定写回到哪个寄存器。
ALUSrc:决定 ALU 的第二个操作数来自寄存器还是立即数。
MemtoReg:决定写回数据是来自计算结果还是内存读出的数据。
- 动画背后的技术细节
为了确保可视化达到"金标准",我在 Manim 代码中做了以下深度定制:
📏 消失的"标注意外"
在早期的版本中,标注文字常与线路重叠。在最终版里,我使用了 next_to 配合 buff 参数,确保 [ 25 : 21 ] [25:21] [25:21] 等位域标注始终紧邻线路下方,且保持逻辑间距。
🏹 统一的视觉语言
所有的箭头(Tips)都经过了比例统一。无论线路长短,箭头的张角和尺寸始终如一,避免了视觉上的"廉价感"。
⚡ 动态脉冲感
通过 Create 动画模拟信号在金黄色数据线上的流转,配合青色控制信号的激活,能够清晰地展示出 "控制信号控制数据流向" 的本质。
- 深度思考:可视化对教育的意义
作为一名教育技术学(EduTech)的研究者,我一直在思考如何利用 AI 和可视化技术降低复杂知识的认知负载。
"一张好的动图,胜过一万字枯燥的讲义。"
通过 Manim 这种编程化的动画制作,我们可以将抽象的数字电路转化为具体的逻辑流。这不仅仅是展示,更是一种知识建模的过程。
结语
计算机架构之美,在于其精密的确定性。希望这段动画能帮你扫清单周期数据通路中的最后一片迷雾。
如果你对 Manim 实现 CPU 动画的代码感兴趣,或者正在备考 408 遇到瓶颈,欢迎在评论区交流!
关键词:#MIPS #计算机组成原理 #408考研 #Manim #可视化教学 #CPU架构
python
%%manim -v WARNING -qh CPU_FULL_ANIMATIONfrom manim import *import numpy as npclass CPU_FULL_ANIMATION(Scene): def construct(self): # ===================== 第一部分:CPU元件逐个讲解动画 ===================== # 风格设定(保留您的暗黑霓虹风格,并增加教材中的蓝色控制信号) self.camera.background_color = "#0A0A0A" NEON_CYAN = "#00E5FF" NEON_YELLOW = "#FFD700" CONTROL_COLOR = "#00A2FF" # 专门用于匹配教材中蓝色的控制信号 TEXT_COLOR = WHITE HIGHLIGHT_COLOR = "#FF8800" # 鲜亮的橙黄色,让讲解文字更醒目 FILL_COLOR = "#121212" STROKE_W = 2 chinese_font = "SimSun" # 工具函数 1:创建带斜线和位宽的数据总线 def make_bus(start, end, width_str, label_dir=DOWN, slash_pos=0.5, color=NEON_YELLOW): line = Line(start, end, color=color, stroke_width=STROKE_W).add_tip(tip_length=0.15, tip_width=0.15) vg = VGroup(line) if width_str: center = line.point_from_proportion(slash_pos) # 绘制小斜线 slash = Line(center + DL * 0.1, center + UR * 0.1, color=color, stroke_width=STROKE_W) # 绘制位宽数字 lbl = Text(width_str, color=TEXT_COLOR, font_size=18).next_to(slash, label_dir, buff=0.05) vg.add(slash, lbl) return vg # 工具函数 2:创建蓝色控制信号 def make_control(end, label_str, direction=UP, color=CONTROL_COLOR): start = end + direction * 0.7 line = Line(start, end, color=color, stroke_width=STROKE_W).add_tip(tip_length=0.15, tip_width=0.15) lbl = Text(label_str, color=color, font_size=20).next_to(line, direction, buff=0.05) return VGroup(line, lbl) # 工具函数 3:创建时钟小三角(内部底边居中) def make_clk(bottom_center): return Polygon( [bottom_center[0] - 0.15, bottom_center[1], 0], [bottom_center[0] + 0.15, bottom_center[1], 0], [bottom_center[0], bottom_center[1] + 0.2, 0], color=NEON_CYAN, stroke_width=STROKE_W ) # ================= 元件创建函数 ================= def create_pc(): rect = Rectangle(width=0.8, height=1.8, color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_pc = Text("PC", color=TEXT_COLOR, font_size=24).next_to(rect, UP, buff=0.1) clk = make_clk(rect.get_bottom()) lbl_clk = Text("CLK", color=TEXT_COLOR, font_size=20).next_to(rect.get_bottom(), DOWN, buff=0.1) bus_in = make_bus(rect.get_left() + LEFT*0.8, rect.get_left(), "32") bus_out = make_bus(rect.get_right(), rect.get_right() + RIGHT*0.8, "32") return VGroup(rect, lbl_pc, clk, lbl_clk, bus_in, bus_out) def create_inst_mem(): rect = Rectangle(width=1.6, height=2.4, color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_a = Text("A", color=TEXT_COLOR, font_size=20).move_to(rect.get_left() + RIGHT*0.2 + UP*0.8) lbl_rd = Text("RD", color=TEXT_COLOR, font_size=20).move_to(rect.get_right() + LEFT*0.3 + UP*0.8) lbl_text = Text("指令\n存储器", color=TEXT_COLOR, font_size=24, font=chinese_font).move_to(rect) bus_in = make_bus(rect.get_left() + UP*0.8 + LEFT*0.8, rect.get_left() + UP*0.8, "32") bus_out = make_bus(rect.get_right() + UP*0.8, rect.get_right() + UP*0.8 + RIGHT*0.8, "32") return VGroup(rect, lbl_a, lbl_rd, lbl_text, bus_in, bus_out) def create_data_mem(): rect = Rectangle(width=1.8, height=2.6, color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_a = Text("A", color=TEXT_COLOR, font_size=20).move_to(rect.get_left() + RIGHT*0.2 + UP*0.6) lbl_wd = Text("WD", color=TEXT_COLOR, font_size=20).move_to(rect.get_left() + RIGHT*0.3 + DOWN*0.6) lbl_rd = Text("RD", color=TEXT_COLOR, font_size=20).move_to(rect.get_right() + LEFT*0.3 + UP*0.6) lbl_we = Text("WE", color=TEXT_COLOR, font_size=20).move_to(rect.get_top() + DOWN*0.2) lbl_text = Text("数据\n存储器", color=TEXT_COLOR, font_size=24, font=chinese_font).move_to(rect) clk = make_clk(rect.get_bottom()) lbl_clk = Text("CLK", color=TEXT_COLOR, font_size=20).next_to(rect.get_bottom(), DOWN, buff=0.1) ctrl_we = make_control(rect.get_top(), "MemWrite", direction=UP) bus_in_a = make_bus(rect.get_left() + UP*0.6 + LEFT*0.8, rect.get_left() + UP*0.6, "32") bus_in_wd = make_bus(rect.get_left() + DOWN*0.6 + LEFT*0.8, rect.get_left() + DOWN*0.6, "32") bus_out = make_bus(rect.get_right() + UP*0.6, rect.get_right() + UP*0.6 + RIGHT*0.8, "32") return VGroup(rect, lbl_a, lbl_wd, lbl_rd, lbl_we, lbl_text, clk, lbl_clk, ctrl_we, bus_in_a, bus_in_wd, bus_out) def create_reg_file(): rect = Rectangle(width=2.4, height=3.2, color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_r1_in = Text("R1#", color=TEXT_COLOR, font_size=18).move_to(rect.get_left() + RIGHT*0.3 + UP*1.0) lbl_r2_in = Text("R2#", color=TEXT_COLOR, font_size=18).move_to(rect.get_left() + RIGHT*0.3 + UP*0.2) lbl_w_in = Text("W#", color=TEXT_COLOR, font_size=18).move_to(rect.get_left() + RIGHT*0.3 + DOWN*0.6) lbl_wd_in = Text("WD", color=TEXT_COLOR, font_size=18).move_to(rect.get_left() + RIGHT*0.3 + DOWN*1.2) lbl_r1_out = Text("R1", color=TEXT_COLOR, font_size=18).move_to(rect.get_right() + LEFT*0.3 + UP*0.8) lbl_r2_out = Text("R2", color=TEXT_COLOR, font_size=18).move_to(rect.get_right() + LEFT*0.3 + UP*0.0) lbl_we = Text("WE", color=TEXT_COLOR, font_size=18).move_to(rect.get_top() + DOWN*0.2 + RIGHT*0.4) lbl_text = Text("寄存\n器堆", color=TEXT_COLOR, font_size=24, font=chinese_font).move_to(rect) clk = make_clk(rect.get_bottom()) lbl_clk = Text("CLK", color=TEXT_COLOR, font_size=20).next_to(rect.get_bottom(), DOWN, buff=0.1) ctrl_we = make_control(rect.get_top() + RIGHT*0.4, "RegWrite", direction=UP) bus_r1_in = make_bus(rect.get_left() + UP*1.0 + LEFT*0.8, rect.get_left() + UP*1.0, "5") bus_r2_in = make_bus(rect.get_left() + UP*0.2 + LEFT*0.8, rect.get_left() + UP*0.2, "5") bus_w_in = make_bus(rect.get_left() + DOWN*0.6 + LEFT*0.8, rect.get_left() + DOWN*0.6, "5") bus_wd_in = make_bus(rect.get_left() + DOWN*1.2 + LEFT*0.8, rect.get_left() + DOWN*1.2, "32") bus_r1_out = make_bus(rect.get_right() + UP*0.8, rect.get_right() + UP*0.8 + RIGHT*0.8, "32") bus_r2_out = make_bus(rect.get_right() + UP*0.0, rect.get_right() + UP*0.0 + RIGHT*0.8, "32") return VGroup(rect, lbl_r1_in, lbl_r2_in, lbl_w_in, lbl_wd_in, lbl_r1_out, lbl_r2_out, lbl_we, lbl_text, clk, lbl_clk, ctrl_we, bus_r1_in, bus_r2_in, bus_w_in, bus_wd_in, bus_r1_out, bus_r2_out) def create_mux(): # 标准 MUX,左平右尖(截断) mux = Polygon([-0.4, 0.8, 0], [0.4, 0.4, 0], [0.4, -0.4, 0], [-0.4, -0.8, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_0 = Text("0", color=TEXT_COLOR, font_size=18).move_to([-0.2, 0.4, 0]) lbl_1 = Text("1", color=TEXT_COLOR, font_size=18).move_to([-0.2, -0.4, 0]) lbl_mux = Text("MUX", color=TEXT_COLOR, font_size=18).rotate(-PI/2).move_to([0.1, 0, 0]) ctrl_sel = make_control([0, 0.6, 0], "sel", direction=UP) bus_in0 = make_bus([-1.2, 0.4, 0], [-0.4, 0.4, 0], "32") bus_in1 = make_bus([-1.2, -0.4, 0], [-0.4, -0.4, 0], "32") bus_out = make_bus([0.4, 0, 0], [1.2, 0, 0], "32") return VGroup(mux, lbl_0, lbl_1, lbl_mux, ctrl_sel, bus_in0, bus_in1, bus_out) def create_sign_ext(): se = Polygon([-1.2, 0.2, 0], [1.2, 0.4, 0], [1.2, -0.4, 0], [-1.2, -0.2, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_se = Text("符号扩展", color=TEXT_COLOR, font_size=24, font=chinese_font).move_to(se) bus_in = make_bus([-2.0, 0, 0], [-1.2, 0, 0], "16") bus_out = make_bus([1.2, 0, 0], [2.0, 0, 0], "32") return VGroup(se, lbl_se, bus_in, bus_out) def create_shifter(): sh = Polygon([-0.4, 0.5, 0], [0.6, 0.5, 0], [0.4, -0.5, 0], [-0.6, -0.5, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_sh = Text("<<2", color=TEXT_COLOR, font_size=24).move_to(sh) bus_in = make_bus([-1.4, 0, 0], [-0.5, 0, 0], "32") bus_out = make_bus([0.5, 0, 0], [1.4, 0, 0], "32") return VGroup(sh, lbl_sh, bus_in, bus_out) def create_adder(): # 精确绘制 ALU 的左侧凹槽 adder = Polygon([-0.6, 0.8, 0], [0.6, 0.4, 0], [0.6, -0.4, 0], [-0.6, -0.8, 0], [-0.3, 0, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_add = Text("+", color=TEXT_COLOR, font_size=36).move_to([0.1, 0, 0]) bus_in1 = make_bus([-1.4, 0.4, 0], [-0.45, 0.4, 0], "32") bus_in2 = make_bus([-1.4, -0.4, 0], [-0.45, -0.4, 0], "32") bus_out = make_bus([0.6, 0, 0], [1.4, 0, 0], "32") return VGroup(adder, lbl_add, bus_in1, bus_in2, bus_out) def create_alu(): alu = Polygon([-0.6, 0.8, 0], [0.6, 0.4, 0], [0.6, -0.4, 0], [-0.6, -0.8, 0], [-0.3, 0, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1) lbl_alu = Text("ALU", color=TEXT_COLOR, font_size=24).rotate(-PI/2).move_to([0.1, 0, 0]) ctrl_op = make_control([0, 0.6, 0], "AluOp", direction=UP) bus_in1 = make_bus([-1.4, 0.4, 0], [-0.45, 0.4, 0], "32") bus_in2 = make_bus([-1.4, -0.4, 0], [-0.45, -0.4, 0], "32") bus_out_main = make_bus([0.6, -0.2, 0], [1.4, -0.2, 0], "32") # Equal 信号单根线,无斜线标记,放上方 line_equal = Line([0.6, 0.2, 0], [1.4, 0.2, 0], color=TEXT_COLOR, stroke_width=STROKE_W).add_tip(tip_length=0.15, tip_width=0.15) lbl_eq = Text("equal", color=TEXT_COLOR, font_size=18).next_to(line_equal, UP, buff=0.05) return VGroup(alu, lbl_alu, ctrl_op, bus_in1, bus_in2, bus_out_main, line_equal, lbl_eq) # 元件列表(元件对象 + 名称 + 作用) components = [ (create_pc(), "程序计数器 PC", "作用:保存当前指令地址,自动+4以获取下一条指令地址。\n控制整个程序的执行流程。"), (create_inst_mem(), "指令存储器", "作用:按地址存储所有指令,\n根据PC的值取出对应指令输出给控制器和寄存器堆。"), (create_data_mem(), "数据存储器", "作用:存储程序运行过程中的数据,\n由MemWrite信号控制写入或读出数据。"), (create_reg_file(), "寄存器堆", "作用:提供快速的寄存器读写接口,\n存储运算中间结果和操作数。"), (create_mux(), "多路选择器 MUX", "作用:在多个输入数据中,\n根据选择信号输出其中一路数据。"), (create_sign_ext(), "符号扩展单元", "作用:将16位立即数扩展为32位,\n用于支持立即数运算和地址计算。"), (create_shifter(), "移位运算器", "作用:将数据左移2位(<<2),\n用于构造跳转或分支目标地址。"), (create_adder(), "加法器", "作用:完成两个数的加法运算,\n如PC+4和分支地址计算。"), (create_alu(), "运算器 ALU", "作用:执行加减、逻辑运算和比较操作,\n并输出equal信号支持分支判断。"), ] for i, (comp, name, desc) in enumerate(components): # 1. 元件在中心绘制 comp.move_to(ORIGIN) self.play(FadeIn(comp), run_time=1) self.wait(0.5) # 2. 元件平滑移动到左侧,右侧显示讲解 (稍微调大偏移量防止重叠) comp_target_pos = LEFT * 3.5 comp.generate_target() comp.target.move_to(comp_target_pos) name_text = Text(name, color=HIGHLIGHT_COLOR, font=chinese_font, font_size=32).move_to(RIGHT * 2.5 + UP * 1) desc_text = Text(desc, color=HIGHLIGHT_COLOR, font=chinese_font, font_size=24).move_to(RIGHT * 2.5 + DOWN * 0.5) # 使用 SmoothMoveToTarget 让动画更流畅 self.play( MoveToTarget(comp, rate_func=smooth), FadeIn(name_text, desc_text), run_time=1.5 ) self.wait(3) # 3. 元件和讲解消失,准备下一个 self.play( FadeOut(comp, name_text, desc_text), run_time=1 ) self.wait(0.5) # ===================== 第二部分:完整CPU数据通路总图动画 ===================== # 1. 风格重定义:暗黑科技感背景 self.camera.background_color = "#0A0A0A" # 颜色主题重设 NEON_CYAN = "#00E5FF" NEON_YELLOW = "#FFD700" COLOR_TEXT = WHITE FILL_COLOR = "#121212" STROKE_W = 1.8 # 中文字体设置 chinese_font = 'SimSun' # 缩放用的全局组 all_elements = VGroup() # ========================================== # 工具函数:MUX/ALU/矩形生成 # ========================================== def create_mux(width, height): mux_body = Polygon( [-width/2, height/2, 0], [width/2, height/2 - height*0.2, 0], [width/2, -height/2 + height*0.2, 0], [-width/2, -height/2, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1 ) label_0 = Text("0", color=NEON_CYAN, font_size=28) label_0.move_to([-width/2 + 0.15, height/4, 0]) label_1 = Text("1", color=NEON_CYAN, font_size=28) label_1.move_to([-width/2 + 0.15, -height/4, 0]) return VGroup(mux_body, label_0, label_1) def create_alu(width, height): alu_body = Polygon( [-width/2, height/2, 0], [width/2, height/4, 0], [width/2, -height/4, 0], [-width/2, -height/2, 0], [-width/2, -height*0.15, 0], [-width/2 + width*0.3, 0, 0], [-width/2, height*0.15, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1 ) plus_sign = Text("+", color=NEON_CYAN, font_size=48) plus_sign.move_to([0, 0, 0]) return VGroup(alu_body, plus_sign) def create_rect(width, height): return Rectangle( width=width, height=height, color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1 ) def text(s, pos, size=16, color=COLOR_TEXT, font_name='sans-serif', align=ORIGIN): return Text(s, font_size=size, color=color, font=font_name).move_to(pos, aligned_edge=align) # ========================================== # 3. 实例化核心组件 # ========================================== mux_branch = create_mux(0.6, 1.4).move_to([-8.5, 2, 0]) mux_jump = create_mux(0.6, 1.4).move_to([-7.0, 1.6, 0]) mux_branch_line = Line( start=mux_branch.get_right(), end=mux_jump[1].get_center() + LEFT * 0.08, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) pc = create_rect(0.8, 1.4).move_to([-5.0, 1.6, 0]) pc_line = Line( start=mux_jump.get_right(), end=pc.get_left(), color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) inst_mem = create_rect(1.8, 3.0).move_to([-2.5, 1, 0]) inst_mem_line = Line( start=pc.get_right(), end=inst_mem.get_left() + UP * 0.6, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) reg_file = create_rect(2.2, 3.2).move_to([2.0, 1, 0]) rd_to_r1p = Line( start=inst_mem.get_right() + UP * 0.7, end=reg_file.get_left() + UP * 0.7, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) alu = create_alu(1.4, 2.2).move_to([6.5, 1.2, 0]).scale(0.6) adder_pc4 = create_alu(1.2, 1.6).move_to([-2.5, -1.8, 0]).scale(0.7) mid = inst_mem_line.get_center() line1 = Line(mid, mid + DOWN * 2.9, color=NEON_YELLOW, stroke_width=STROKE_W) line2 = Line( line1.get_end(), adder_pc4.get_left() + UP * 0.5, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) four_input = Line( adder_pc4.get_left() + DOWN * 0.5, adder_pc4.get_left() + LEFT * 0.5 + DOWN * 0.5, color=NEON_YELLOW, stroke_width=STROKE_W ) four_label = text("4", four_input.get_start() + LEFT * 0.6, size=18, color=NEON_CYAN) mux_regdst = create_mux(0.5, 1.2).move_to([0.1, 0.3, 0]) mux_alusrc = create_mux(0.5, 1.2).move_to([4.5, 0.8, 0]).scale(0.9) sign_ext = Polygon( [-0.8, 0.4, 0], [0.8, 0.6, 0], [0.8, -0.6, 0], [-0.8, -0.4, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1 ).move_to([2.0, -3, 0]).scale(0.7) shift_branch = Polygon( [-0.4, 0.4, 0], [0.6, 0.4, 0], [0.4, -0.4, 0], [-0.6, -0.4, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1 ).move_to([4.5, -3, 0]).scale(0.7) shift_jump = Polygon( [-0.4, 0.4, 0], [0.6, 0.4, 0], [0.4, -0.4, 0], [-0.6, -0.4, 0], color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1 ).move_to([-3.5, -4.5, 0]).scale(0.7) ctrl = RoundedRectangle( corner_radius=0.4, width=1.6, height=3.2, color=NEON_CYAN, stroke_width=STROKE_W, fill_color=FILL_COLOR, fill_opacity=1 ).move_to([0, 4.5, 0]) # AND门位置微调 and_gate = VGroup( Line([-0.3, 0.4, 0], [-0.3, -0.4, 0]), Line([-0.3, 0.4, 0], [0, 0.4, 0]), Line([-0.3, -0.4, 0], [0, -0.4, 0]), ArcBetweenPoints([0, 0.4, 0], [0, -0.4, 0], angle=-PI) ).set_color(NEON_CYAN).set_stroke(width=STROKE_W).move_to([7.5, 3.8, 0]) data_mem = create_rect(1.8, 3.0).move_to([10.0, 1, 0]).scale(1.2) mux_memtoreg = create_mux(0.6, 1.4).move_to([12.5, 2, 0]).scale(1.3) adder_branch = create_alu(1.2, 1.6).move_to([6.5, -3, 0]) branch_point_orig = np.array([-0.95, 1.9, 0]) line_down = Line( branch_point_orig, branch_point_orig + DOWN * 0.8, color=NEON_YELLOW, stroke_width=STROKE_W ) line_to_r2 = Line( line_down.get_end(), reg_file.get_left() + UP * 0.1, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) line_down_continue = Line( line_down.get_end(), line_down.get_end() + DOWN * 0.6, color=NEON_YELLOW, stroke_width=STROKE_W ) line_down_final = Line( line_down_continue.get_end(), line_down_continue.get_end() + DOWN * 0.45, color=NEON_YELLOW, stroke_width=STROKE_W ) line_to_mux1 = Line( line_down_final.get_end(), mux_regdst.get_left() + DOWN * 0.25, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) line_horizontal = Line( line_down.get_end(), line_down.get_end() + RIGHT * 0.3, color=NEON_YELLOW, stroke_width=STROKE_W ) line_vertical = Line( line_horizontal.get_end(), line_horizontal.get_end() + DOWN * 0.5, color=NEON_YELLOW, stroke_width=STROKE_W ) line_to_mux0 = Line( line_vertical.get_end(), mux_regdst.get_left() + UP * 0.3, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) mux_to_w = Line( mux_regdst.get_right(), reg_file.get_left() + DOWN * 0.7, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) line_to_sign_ext_vertical = Line( line_down_final.get_end(), line_down_final.get_end() + DOWN * 3.1, color=NEON_YELLOW, stroke_width=STROKE_W ) line_to_sign_ext = Line( line_to_sign_ext_vertical.get_end(), sign_ext.get_left(), color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) line_to_shift_vertical = Line( line_to_sign_ext_vertical.get_end(), line_to_sign_ext_vertical.get_end() + DOWN * 1.5, color=NEON_YELLOW, stroke_width=STROKE_W ) line_to_shift_jump = Line( line_to_shift_vertical.get_end(), shift_jump.get_right(), color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) line_jump1 = Line( shift_jump.get_left(), shift_jump.get_left() + LEFT * 3.6, color=NEON_YELLOW, stroke_width=STROKE_W ) line_jump2 = Line( line_jump1.get_end(), line_jump1.get_end() + UP * 5.8, color=NEON_YELLOW, stroke_width=STROKE_W ) line_jump3 = Line( line_jump2.get_end(), mux_jump.get_left() + DOWN * 0.3, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) r1_to_alu = Line( reg_file.get_right() + UP * 0.7, alu.get_left() + UP * 0.5, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) srcA_text = text("SrcA", r1_to_alu.get_center() + RIGHT * 0.9 + UP * 0.25, size=18, color=NEON_CYAN ) # 寄存器堆 R2 端口 → ALUSrc 多路选择器 0号端口 线路(规范直角走线) r2_to_mux_h = Line( reg_file.get_right(), mux_alusrc.get_left(), color=NEON_YELLOW, stroke_width=STROKE_W ) # 寄存器堆 R2 端口 水平向右直达 MUX0 端口,无垂直拐弯 r2_to_mux_h = Line( reg_file.get_right(), mux_alusrc.get_left() + UP * 0.25, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) r2_branch_point = r2_to_mux_h.get_center() r2_branch_down = Line( r2_branch_point, r2_branch_point + DOWN * 1.0, color=NEON_YELLOW, stroke_width=STROKE_W ) r2_to_wd = Line( r2_branch_down.get_end(), data_mem.get_left() + DOWN * 1, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) sign_ext_to_shift = Line( sign_ext.get_right(), shift_branch.get_left(), color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) branch_point_ext = sign_ext_to_shift.get_center() line_branch_up = Line( branch_point_ext, branch_point_ext + UP * 3.5, color=NEON_YELLOW, stroke_width=STROKE_W ) line_branch_to_mux = Line( line_branch_up.get_end(), mux_alusrc.get_left() + DOWN * 0.3, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) # ====================== 仅修改这里 2/2 ====================== mux_to_alu = Line( mux_alusrc.get_right(), alu.get_left()+DOWN*0.4, # 纯水平直线,无偏移 color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) # =========================================================== alu_to_dataA = Line( alu.get_right(), data_mem.get_left() + UP * 0.25, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) alu_result_text = text("ALUResult", alu_to_dataA.get_center() + RIGHT*-0.4 + UP*0.25, size=18, color=NEON_CYAN ) branch_alu = alu_to_dataA.get_center() + RIGHT * 0.5 line_branch_up2 = Line( branch_alu, branch_alu + UP * 2.0, color=NEON_YELLOW, stroke_width=STROKE_W ) line_branch_right = Line( line_branch_up2.get_end(), line_branch_up2.get_end() + RIGHT * 3.0, color=NEON_YELLOW, stroke_width=STROKE_W ) line_branch_down = Line( line_branch_right.get_end(), line_branch_right.get_end() + DOWN * 1, color=NEON_YELLOW, stroke_width=STROKE_W ) line_branch_to_mux2 = Line( line_branch_down.get_end(), mux_memtoreg.get_left() + UP * 0.3, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) data_rd_out = Line( data_mem.get_right(), data_mem.get_right() + RIGHT * 0.5, color=NEON_YELLOW, stroke_width=STROKE_W ) rd_line_up = Line( data_rd_out.get_end(), data_rd_out.get_end() + UP * 0.7, color=NEON_YELLOW, stroke_width=STROKE_W ) rd_to_mux1 = Line( rd_line_up.get_end(), mux_memtoreg.get_left() + DOWN * 0.3, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) mux_wb_line1 = Line( mux_memtoreg.get_right(), mux_memtoreg.get_right() + RIGHT * 1.8, color=NEON_YELLOW, stroke_width=STROKE_W ) mux_wb_line2 = Line( mux_wb_line1.get_end(), mux_wb_line1.get_end() + DOWN * 7.2, color=NEON_YELLOW, stroke_width=STROKE_W ) mux_wb_line3 = Line( mux_wb_line2.get_end(), mux_wb_line2.get_end() + LEFT * 14.5, color=NEON_YELLOW, stroke_width=STROKE_W ) mux_wb_line4 = Line( mux_wb_line3.get_end(), mux_wb_line3.get_end() + UP * 4.8, color=NEON_YELLOW, stroke_width=STROKE_W ) mux_wb_line5 = Line( mux_wb_line4.get_end(), mux_wb_line4.get_end() + RIGHT * 0.7, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) shift_to_adder = Line( shift_branch.get_right(), adder_branch.get_left(), color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) adder_branch_line1 = Line( start=adder_branch.get_left() + DOWN*0.6, end=adder_branch.get_left() + DOWN*0.6 + LEFT*15, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16, at_start=True) adder_branch_line2 = Line( start=adder_branch_line1.get_end(), end=adder_branch_line1.get_end() + UP*5.9, color=NEON_YELLOW, stroke_width=STROKE_W ) adder_branch_line3 = Line( start=adder_branch_line2.get_end(), end=mux_branch.get_left() + UP*0.3, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) adder_wb_line1 = Line( adder_branch.get_right(), adder_branch.get_right() + RIGHT * 1.8, color=NEON_YELLOW, stroke_width=STROKE_W ) adder_wb_line2 = Line( adder_wb_line1.get_end(), adder_wb_line1.get_end() + DOWN * 1, color=NEON_YELLOW, stroke_width=STROKE_W ) adder_wb_line3 = Line( adder_wb_line2.get_end(), adder_wb_line2.get_end() + LEFT * 19.5, color=NEON_YELLOW, stroke_width=STROKE_W ) adder_wb_line4 = Line( adder_wb_line3.get_end(), adder_wb_line3.get_end() + UP * 5.7, color=NEON_YELLOW, stroke_width=STROKE_W ) adder_wb_line5 = Line( adder_wb_line4.get_end(), mux_branch.get_left() + DOWN * 0.3, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) adder_pc4_line1 = Line( start=adder_pc4.get_right(), end=adder_pc4.get_right() + RIGHT * 0.2, color=NEON_YELLOW, stroke_width=STROKE_W ) adder_pc4_line2 = Line( start=adder_pc4_line1.get_end(), end=adder_pc4_line1.get_end() + DOWN * 1.75, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) pc4_label = text("PC+4", adder_pc4_line1.get_center() + DOWN * 0.25+RIGHT*0.5, size=18, color=NEON_CYAN ) # ✅ 从【向下箭头的末端】继续接:向左 → 向上 → 向左 adder_pc4_line3 = Line( start=adder_pc4_line2.get_end(), # 从向下箭头结束点开始! end=adder_pc4_line2.get_end() + LEFT * 5.0, color=NEON_YELLOW, stroke_width=STROKE_W ) adder_pc4_line4 = Line( start=adder_pc4_line3.get_end(), end=adder_pc4_line3.get_end() + UP * 1.0, color=NEON_YELLOW, stroke_width=STROKE_W ) adder_pc4_line5 = Line( start=adder_pc4_line4.get_end(), end=adder_pc4_line4.get_end() + LEFT * 0.6, color=NEON_YELLOW, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) components = VGroup( mux_branch, mux_jump, mux_regdst, mux_alusrc, mux_memtoreg, pc, inst_mem, reg_file, alu, data_mem, ctrl, and_gate, adder_pc4, adder_branch, sign_ext, shift_branch, shift_jump, mux_branch_line, pc_line, inst_mem_line, line1, line2, four_input, four_label, rd_to_r1p, line_down, line_to_r2, line_down_continue, line_down_final, line_to_mux0, line_vertical, line_horizontal, line_to_mux1, mux_to_w, line_to_sign_ext_vertical, line_to_sign_ext, line_to_shift_vertical, line_to_shift_jump, line_jump1, line_jump2, line_jump3, r1_to_alu, srcA_text, r2_to_mux_h, r2_branch_down, r2_to_wd, sign_ext_to_shift, line_branch_up, line_branch_to_mux, mux_to_alu, alu_to_dataA, alu_result_text, line_branch_up2, line_branch_right, line_branch_down, line_branch_to_mux2, data_rd_out, rd_line_up, rd_to_mux1, mux_wb_line1, mux_wb_line2, mux_wb_line3, mux_wb_line4, mux_wb_line5, shift_to_adder, adder_pc4_line4,adder_pc4_line5, adder_branch_line1, adder_branch_line2, adder_branch_line3, adder_wb_line1, adder_wb_line2, adder_wb_line3, adder_wb_line4, adder_wb_line5, adder_pc4_line1, adder_pc4_line2, pc4_label ) all_elements.add(components) labels = VGroup() # 基础模块标注 labels.add(text("PC", [-5.0, 1.6, 0], size=22, font_name=chinese_font, color=WHITE)) labels.add(text("指令\n存储器", [-2.5, 0.8, 0], size=20, font_name=chinese_font, color=WHITE)) labels.add(text("A", [-3.25, 1.7, 0], size=22, color=NEON_CYAN)) labels.add(text("RD", [-1.75, 1.7, 0], size=22, color=NEON_CYAN)) labels.add(text("数据\n存储器", [10.0, 1.0, 0], size=20, font_name=chinese_font, color=WHITE)) labels.add(text("符号扩展", [2.0, -3.0, 0], size=20, font_name=chinese_font, color=WHITE)) labels.add(text("BranchTaken", [-7.8, 6.3, 0], size=14, color=NEON_CYAN)) labels.add(text("图 6.25 单周期 MIPS 处理器的数据通路高层视图", [2.0, -7.0, 0], size=24, color=NEON_CYAN, font_name=chinese_font)) # 寄存器堆端口 labels.add(text("R1#", [1.2, 1.7, 0], size=18, color=NEON_CYAN)) labels.add(text("R2#", [1.2, 1.0, 0], size=18, color=NEON_CYAN)) labels.add(text("W#", [1.2, 0.3, 0], size=18, color=NEON_CYAN)) labels.add(text("WD", [1.2, -0.4, 0], size=18, color=NEON_CYAN)) labels.add(text("WE", [2.0, 2.3, 0], size=18, color=NEON_CYAN)) labels.add(text("R1", [3.0, 1.7, 0], size=18, color=NEON_CYAN)) labels.add(text("R2", [3.0, 1.0, 0], size=18, color=NEON_CYAN)) labels.add(text("寄存器堆", [2.0, 0.0, 0], size=20, color=WHITE)) # 指令字段 labels.add(text("Instr", [-1.25, 1.9, 0], size=16, color=WHITE)) labels.add(text("25:21", [-0.65, 1.85, 0], size=14, color=NEON_CYAN)) labels.add(text("15:11", [-0.65, 0.25, 0], size=14, color=NEON_CYAN)) labels.add(text("15:0", [-0.65, -2.85, 0], size=14, color=NEON_CYAN)) labels.add(text("rs", [0.6, 1.85, 0], size=14, color=NEON_CYAN)) labels.add(text("20:16", [-0.65, 1.2, 0], size=14, color=NEON_CYAN)) labels.add(text("rt", [0.6, 1.2, 0], size=14, color=NEON_CYAN)) # 存储器端口 labels.add(text("A", data_mem.get_left() + RIGHT*0.2 + UP*0.3, size=16, color=NEON_CYAN)) labels.add(text("WD", data_mem.get_left() + RIGHT*0.2 + DOWN*1, size=16, color=NEON_CYAN)) labels.add(text("RD", data_mem.get_right() + LEFT*0.3+UP*0.3, size=16, color=NEON_CYAN)) labels.add(text("WE", data_mem.get_top() + DOWN*0.3, size=16, color=NEON_CYAN)) # 移位操作 labels.add(text("<<2", shift_branch.get_center(), size=16, color=NEON_CYAN)) labels.add(text("<<2", shift_jump.get_center(), size=16, color=NEON_CYAN)) # 控制器 labels.add(text("控制器", [0, 5.6, 0], size=20, font_name=chinese_font, color=WHITE)) labels.add(text("Op", [0, 4.6, 0], size=20, color=WHITE)) labels.add(text("Funct", [0, 3.8, 0], size=20, color=WHITE)) # 控制信号 labels.add(text("MemtoReg", [1.3, 5.8, 0], size=15, color=NEON_CYAN)) labels.add(text("MemWrite", [1.3, 5.4, 0], size=15, color=NEON_CYAN)) labels.add(text("Branch", [1.3, 4.8, 0], size=15, color=NEON_CYAN)) labels.add(text("AluOp", [1.3, 4.4, 0], size=15, color=NEON_CYAN)) labels.add(text("ALUSrc", [1.3, 4.0, 0], size=15, color=NEON_CYAN)) labels.add(text("RegWrite", [1.3, 3.6, 0], size=15, color=NEON_CYAN)) labels.add(text("RegDst", [0.2, 2.7, 0], size=16, color=NEON_CYAN)) labels.add(text("Jump", [-1.1, 5.2, 0], size=16, color=NEON_CYAN)) # 线路标注(紧贴线路、不冲撞) labels.add(text("SrcB", mux_to_alu.get_center() + UP*0.2, size=16, color=NEON_CYAN)) labels.add(text("PC+4", adder_pc4_line1.get_center() + DOWN*0.25+RIGHT*0.5, size=16, color=NEON_CYAN)) labels.add(text("SignImm", sign_ext.get_right() + RIGHT*0.5+DOWN*0.2, size=16, color=NEON_CYAN)) labels.add(text("PCBranch", adder_branch.get_right() + RIGHT*0.5+UP*0.2, size=16, color=NEON_CYAN)) labels.add(text("ReadData", rd_line_up.get_center()+DOWN*0.45, size=16, color=NEON_CYAN)) labels.add(text("WriteBackData", rd_line_up.get_center()+DOWN*6.4, size=16, color=NEON_CYAN)) labels.add(text("equal", and_gate.get_center() + DOWN*0.6, size=14, color=NEON_CYAN)) labels.add(text("31:26", [-0.6, 4.75, 0], size=14, color=NEON_CYAN)) labels.add(text("5:0", [-0.6, 3.95, 0], size=14, color=NEON_CYAN)) # 继续补充细节标注 labels.add( text( "PC+4", mux_branch.get_left() + UP*0.5 + LEFT*0.5, size=16, color=NEON_CYAN ) ) labels.add( text( "JumpAddress", [-7.3, -1.0, 0], size=16, color=NEON_CYAN ).rotate(90 * DEGREES) # 垂直显示,和原图一致 ) # 1. PC+4(加法器输出) labels.add(text("PC+4", [-4.5, -3.3, 0], size=16, color=NEON_CYAN)) # 2. 31:28(PC+4高位) labels.add(text("31:28", [-6.5, -3.3, 0], size=14, color=NEON_CYAN)) # 3. BranchAddress(分支地址总线) labels.add(text("BranchAddress", [-4.5, -3.8, 0], size=16, color=NEON_CYAN)) # 4. 27:0(跳转地址高位) labels.add(text("27:0", [-7.0, -4.3, 0], size=14, color=NEON_CYAN)) # 5. 25:0(立即数低位) labels.add(text("25:0", shift_jump.get_right() + RIGHT*0.5 + UP*0.2, size=14, color=NEON_CYAN)) labels.add( text( "CLK", pc.get_bottom() + DOWN * 0.25, size=16, color=NEON_CYAN ) ) labels.add( text( "CLK", reg_file.get_bottom() + DOWN * 0.25, size=16, color=NEON_CYAN ) ) labels.add( text( "PC+4", shift_branch.get_bottom() + DOWN * 0.25, size=16, color=NEON_CYAN ) ) all_elements.add(labels) # ========================================== # 蓝色控制线路(按教材原图修正) # ========================================== ctrl_lines = VGroup() # 1. Jump 线路 -> PC 多路选择器 jump_l1 = Line([-0.8, 5.0, 0], [-1.6, 5.0, 0], color=NEON_CYAN, stroke_width=STROKE_W) jump_l2 = Line([-1.6, 5.0, 0], [-1.6, 6.2, 0], color=NEON_CYAN, stroke_width=STROKE_W) jump_l3 = Line([-1.6, 6.2, 0], [-7.0, 6.2, 0], color=NEON_CYAN, stroke_width=STROKE_W) jump_l4 = Line([-7.0, 6.2, 0], [-7.0, mux_jump.get_top()[1], 0], color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 2. RegDst 线路 -> 寄存器地址多路选择器 regdst_l1 = Line([0.5, 2.9, 0], [0.5, 2.3, 0], color=NEON_CYAN, stroke_width=STROKE_W) regdst_l2 = Line([0.5, 2.3, 0], [mux_regdst.get_x(), 2.3, 0], color=NEON_CYAN, stroke_width=STROKE_W) regdst_l3 = Line([mux_regdst.get_x(), 2.3, 0], mux_regdst.get_top(), color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 3. Branch 线路 -> AND门 (修正版:右 -> 下 -> 右) br_l1 = Line([0.8, 4.6, 0], [6.9, 4.6, 0], color=NEON_CYAN, stroke_width=STROKE_W) br_l2 = Line([6.9, 4.6, 0], [6.9, 4.1, 0], color=NEON_CYAN, stroke_width=STROKE_W) br_l3 = Line([6.9, 4.1, 0], [7.2, 4.1, 0], color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 4. MemtoReg 线路 -> 写回多路选择器 mtr_l1 = Line([0.8, 5.7, 0], [12.5, 5.7, 0], color=NEON_CYAN, stroke_width=STROKE_W) mtr_l2 = Line([12.5, 5.7, 0], mux_memtoreg.get_top(), color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 5. MemWrite 线路 -> 数据存储器 mw_l1 = Line([0.8, 5.3, 0], [10.0, 5.3, 0], color=NEON_CYAN, stroke_width=STROKE_W) mw_l2 = Line([10.0, 5.3, 0], data_mem.get_top(), color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 6. ALUOp 线路 -> ALU aluop_l1 = Line([0.8, 4.2, 0], [6.5, 4.2, 0], color=NEON_CYAN, stroke_width=STROKE_W) aluop_l2 = Line([6.5, 4.2, 0], alu.get_top(), color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 7. ALUSrc 线路 -> ALU前多路选择器 alusrc_l1 = Line([0.8, 3.8, 0], [4.5, 3.8, 0], color=NEON_CYAN, stroke_width=STROKE_W) alusrc_l2 = Line([4.5, 3.8, 0], mux_alusrc.get_top(), color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 8. RegWrite 线路 -> 寄存器堆 rw_l1 = Line([0.8, 3.4, 0], [2.0, 3.4, 0], color=NEON_CYAN, stroke_width=STROKE_W) rw_l2 = Line([2.0, 3.4, 0], reg_file.get_top(), color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 9. Instruction 接入 Controller inst_branch_x = -1.0 inst_ctrl_main = Line([inst_branch_x, 1.7, 0], [inst_branch_x, 4.6, 0], color=NEON_CYAN, stroke_width=STROKE_W) inst_ctrl_op = Line([inst_branch_x, 4.6, 0], [-0.8, 4.6, 0], color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) inst_ctrl_funct = Line([inst_branch_x, 3.8, 0], [-0.8, 3.8, 0], color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) # 10. ALU equal -> AND门 下侧输入(ALU右上顶点直接引出版) eq_l1 = Line( alu.get_corner(UR)+DOWN*0.3, # 起点:ALU的右上角顶点,和ALU无缝接上 [alu.get_x() + 0.35, 3.5, 0], # 先垂直下到与门下侧Y坐标 color=NEON_CYAN, stroke_width=STROKE_W ) eq_l2 = Line( [alu.get_x() + 0.35, 3.5, 0], [7.2, 3.5, 0], # 再水平向右,直接接到与门下侧输入 color=NEON_CYAN, stroke_width=STROKE_W ).add_tip(tip_length=0.09, tip_width=0.16) # 11. AND门输出 BranchTaken -> 分支MUX bt_l1 = Line([7.9, 3.8, 0], [8.2, 3.8, 0], color=NEON_CYAN, stroke_width=STROKE_W) bt_l2 = Line([8.2, 3.8, 0], [8.2, 6.6, 0], color=NEON_CYAN, stroke_width=STROKE_W) bt_l3 = Line([8.2, 6.6, 0], [-8.5, 6.6, 0], color=NEON_CYAN, stroke_width=STROKE_W) bt_l4 = Line([-8.5, 6.6, 0], [-8.5, mux_branch.get_top()[1], 0], color=NEON_CYAN, stroke_width=STROKE_W).add_tip(tip_length=0.09, tip_width=0.16) b_labels = VGroup() b_labels.add(text("31:26", [-0.6, 4.75, 0], size=14, color=NEON_CYAN)) b_labels.add(text("5:0", [-0.6, 3.95, 0], size=14, color=NEON_CYAN)) # ========== 已更新:添加了 br_l3 ========== ctrl_lines.add(jump_l1, jump_l2, jump_l3, jump_l4, regdst_l1, regdst_l2, regdst_l3, br_l1, br_l2, br_l3, mtr_l1, mtr_l2, mw_l1, mw_l2, aluop_l1, aluop_l2, alusrc_l1, alusrc_l2, rw_l1, rw_l2, inst_ctrl_main, inst_ctrl_op, inst_ctrl_funct, eq_l1, eq_l2, bt_l1, bt_l2, bt_l3, bt_l4, b_labels) all_elements.add(ctrl_lines) # 整体微调 all_elements.scale(0.56).move_to(ORIGIN) # ====================== 总图动画绘制 ====================== # 1. 基础硬件和主要黄色数据流淡入 self.play(FadeIn(components, lag_ratio=0.05), run_time=3.5) # 2. 蓝色的控制信号线像电路连通一样"画"出来 self.play(Create(ctrl_lines, lag_ratio=0.1), run_time=2.5) # 3. 所有的文本标签浮现 self.play(Write(labels, lag_ratio=0.1), run_time=2) # 4. 停顿展示完整电路图 self.wait(3)