☰
微程序控制器实验:微指令编码、控制存储器与虚拟实验系统调试
2026/11/3 14:26:03 网站建设 项目流程

简介:面向计算机组成原理课程的学习者与实验教学场景,围绕「实验7 微程序控制器」整理的实验报告文档,重点解决微指令与机器指令的对应关系、控制存储器寻址以及地址转移逻辑等理解难点。正文从实验目的与要求切入,梳理4位数据锁存器74LS175、2K×8 EPROM2716、时序发生器及门电路构成的控制器电路,讲解微地址寄存器加载、判别位P1与操作码IR7~IR5共同决定后继微地址的过程,并给出24位全水平型微指令字段划分、IN/ADD/STA/JMP四条指令的微程序流程图与部分微指令二进制代码表,末附实验步骤与思考题。压缩包共1个docx文件,约485KB,单文件即完整报告,便于直接查阅与打印。已有651人学习,适合配合虚拟实验系统边搭建电路边对照原理。

1. 从一盏不亮的指示灯说起:微程序控制器实验到底在验证什么

虚拟实验系统里把图接完,电源打开,点 start,微地址指示灯停在 00 一动不动——这种场面我带过的新手几乎人人遇到一次。微程序控制器这个实验,本质上在验证一件事:一条机器指令怎么被拆成一串微指令,控制存储器又怎么按地址把它们一条条吐出来,变成全机的 19 路操作控制信号。这份实验资源把整条链路摊开了:74LS175 做微地址寄存器,3 片 EPROM2716 拼成 2K×24 位的控制存储器,24 位微指令里 19 位是操作控制字段、5 位是顺序控制字段,地址转移逻辑靠 P1 判别位和 IR7~IR5 决定下一条微地址,指令系统里只放 IN、ADD、STA、JMP 四条机器指令,刚好够把「取指—译码—执行」的微程序流程走完整。它适合两类人:正在做计算机组成原理课程实验、需要在虚拟实验系统里把这套电路跑通并写报告的人,以及想搞清楚「机器指令—微指令—控制信号」三层映射关系的人。

2. 拆开 24 位微指令:19 位操作控制加 5 位顺序控制的取舍

2.1 全水平型加直接表示法,为什么这么选

微指令的编码方式直接影响控制存储器的字长和控制的并行度。常见做法分两个维度:一是水平型与垂直型,二是直接表示法与编码译码法。这个实验选的是全水平型 + 直接表示法,24 位字长,操作控制字段 19 位,每一位直接对应一个微命令,中间不插译码器。

先讲为什么不用垂直型。垂直型把微命令按互斥关系分组,每组给一个字段编码,字段里不同的码值代表不同的微命令。好处是字长短,控制存储器省容量;代价是必须加译码器,而且同一字段内的微命令天然互斥,没法在同一拍里并行发出。这个实验的教学目标是让学生「看见」控制信号,一位一盏指示灯,哪几位被置 1、哪些部件动作,肉眼可读。垂直型一上译码器,学生看到的是编码值,还得反查译码表,认知链条就断了。

再讲为什么不用编码译码的直接表示法变体。19 位控制字段如果做部分编码,字长能压到 12 位左右,但地址转移逻辑和微指令格式都会变复杂,虚拟实验系统里的连线也会多出一层。教学实验里,器件数量和连线复杂度是硬约束——原文提到「为简化电路结构,本实验没有使用微命令寄存器」,同理,控制字段也不做压缩。

代价是明确的:24 位字长里 19 位都是控制位,控制存储器按 16 个微地址 × 24 位算,实际只用 16×3 字节。这个容量放在真实 CPU 里当然不够看,但四条机器指令、十几个微命令的规模,刚好卡在「能讲清楚又不冗余」的位置上。

编码方式字长是否需译码器微命令并行度本实验是否采用
全水平型 + 直接表示24 位否高,一位一命令是
水平型 + 字段编码约 16 位是中,同字段互斥否
垂直型8~12 位是低否

参数上还要注意一点:19 位操作控制字段并不是随便凑的,它按功能分了几组。S3~S0 四位是 ALU 的运算选择,能选 16 种运算;M、Cn 参与 ALU 的进位与模式控制;WE 是存储器写使能;LDR0、LDDR1、LDDR2 分别控制三个寄存器的打入;LDIR、LDPC、LDAR 分别控制指令寄存器、程序计数器、地址寄存器的打入;CE 和 LOAD 是片选与加载;剩下四位 ALU→BUS、PC→BUS、SW→BUS、R0→BUS 是四条总线驱动信号,决定这一拍谁把数据放上总线。这么一分组,写微指令代码的时候就不会瞎填——先想清楚这一拍要哪个部件动作,再去对应组里找位。

2.2 位序对齐:最后 5 位永远是 P1 加 μA3~μA0

这里有一个必须提前说的坑。实验材料里表 7-1 和表 7-3 的表头顺序在 Cn、CE、WE、LOAD、LDR0 这一段不完全一致,表 7-1 写的是「M WE LDR0 LDDR1 LDDR2 Cn CE LOAD」,表 7-3 写的是「M Cn CE WE LOAD LDR0 LDDR1 LDDR2」。这是从文档里复制表格时列错位造成的,不是你抄错了。

处理办法很简单:不管前面怎么错位,最后 5 位固定是 P1、μA3、μA2、μA1、μA0。理由很硬——顺序控制字段在两张表里都排在末尾,而且它只有 5 位,宽度确定。做微程序推演、算下一条地址,只看这 5 位就够,前面的 19 位只影响「这一拍哪些部件动作」,不影响「下一条微指令在哪」。

实操上,我一般让学生先拿地址 00 那行做对齐校验:末 5 位读出来是0 0 0 0 1,即 P1=0、μA3~μA0=0001,下一条地址就是 01。翻到表里 01 行,确实存在,说明字段切分对了。如果末 5 位读出来是1 x x x x而下一行地址对不上,那就是把 P1 的位置数错了。

提示:位序对齐只做一次,做完把「末 5 位」这四个字写在实验记录本第一页。后面每推一条微指令都从这 5 位起手,比反复翻表头快得多。

2.3 用一段脚本把二进制行拆成字段

手算 24 位容易眼花,我一般写十几行脚本代劳。下面这段按表 7-3 的列序切分,如果你的实验手册表头顺序不同,只改FIELDS这一处即可。

# 按表7-3列序切分一条24位微指令;表头顺序不同时只改 FIELDS FIELDS = [ ("S3", 1), ("S2", 1), ("S1", 1), ("S0", 1), # ALU 运算选择 ("M", 1), ("Cn", 1), ("CE", 1), ("WE", 1), # 运算/存储控制 ("LOAD", 1), ("LDR0", 1), ("LDDR1", 1), ("LDDR2", 1), ("LDIR", 1), ("LDPC", 1), ("LDAR", 1), ("ALU_BUS", 1), ("PC_BUS", 1), ("SW_BUS", 1), ("R0_BUS", 1), # 总线驱动 ("P1", 1), ("uA3", 1), ("uA2", 1), ("uA1", 1), ("uA0", 1), # 顺序控制 ] def decode(bits: str) -> dict: bits = bits.replace(" ", "") # 容忍手抄时空格 assert len(bits) == 24, f"位数不对: {len(bits)}" out, pos = {}, 0 for name, width in FIELDS: out[name] = bits[pos:pos + width] pos += width return out def show(row: str): d = decode(row) on = [k for k, v in d.items() if v == "1" and k not in ("P1", "uA3", "uA2", "uA1", "uA0")] ua = int(d["uA3"] + d["uA2"] + d["uA1"] + d["uA0"], 2) print("置1的控制位:", " ".join(on) or "无") print("P1 =", d["P1"], " 后续微地址 =", format(ua, "02o"), "(八进制)") # 表7-3 地址00行 0 0 0 0 0 1 1 0 1 0 0 0 0 0 0 1 1 1 1 0 0 0 0 1 show("000001101000001111000001")

这段代码做了三件事。FIELDS是按列序定义的字段清单,每项是「名字 + 位宽」,位宽全是 1,所以加不加都一样,但保留这个结构是为了以后遇到多比特字段(比如有人把 S3~S0 合并成一个 4 位字段)时不用重写逻辑。decode负责把连续的二进制串切成字典,断言 24 位是为了拦住手抄时漏一位的情况——这个坑很常见,少抄一个 0,后面所有推演全废。show把顺序控制字段单独拎出来,转成八进制输出,因为实验里微地址一贯用八进制表示,十进制对照容易错位。

跑地址 00 那行,输出是 P1 = 0、后续微地址 = 01。这和表里 01 行存在的事实互相印证,说明切分正确。接着把 01 行0000011000010110100010(注意这行只有 22 位时就是抄错了,必须补齐)粘进去,得到 02;02 行得到 03;03 行的 P1 变成 1,说明这是一条分支微指令,下一条地址不再由 μA 字段决定,而是交给地址转移逻辑按操作码算。整条线性链在脚本里滚一遍,比在纸上数快五倍,而且不会错。

3. 在虚拟实验系统里搭出这张图:器件、引脚与上电顺序

3.1 器件清单与虚拟组件的合并关系

先把清单摆清楚,不然连线时容易找不到北。

器件规格在电路中的角色虚拟系统中的形态
74LS1754 位数据锁存器微地址寄存器,存 μA3~μA0独立组件
EPROM27162K×8控制存储器,3 片拼 24 位合并为 1 个 2K×24 组件
时序发生器—产生 T1 等时序信号虚拟组件,带 Step 开关
与门、或门2 输入地址转移逻辑离散门电路
开关—设 IR7~IR5、CLR 等面板开关
指示灯—显示微地址与微命令面板指示灯

这里有个认知差要提前打掉:纸面上是「3 片 EPROM2716」,虚拟系统里合并成了一个组件,位宽 24 位,地址线 A10~A0 共 11 根。原文说得很清楚,「为了减少连线的复杂度,虚拟实验系统把 3 片 EPROM2716 集成到一片芯片上」。如果你按 3 片去数引脚,会发现组件上的引脚数对不上,然后开始怀疑自己接错——其实没错,是合并了。

合并之后还有一个细节:A10~A0 里,实验只用到 A3~A0 四根,高 7 位 A4~A10 全部接地。这意味着实际可寻址空间是 16 个微地址,每个地址 24 位,总容量 16×3 字节。为什么要这么设?因为四条机器指令的微程序加起来也就十几条微指令,16 个地址够用;地址线全部拉满反而会让连线复杂,且容易在 A4~A10 上悬空导致读出随机值。

3.2 上电前的引脚预置,顺序不能乱

这一步是最容易翻车的地方,我按实际顺序写。

第一步,把 EPROM2716 组件的 CE 和 OE 都置 0。CE 是片选,为 0 时芯片正常工作;OE 是读信号,CE=0 且 OE=0 时才是读操作。两根都接地恒置 0,等于让控制存储器一直处于可读状态。如果 CE 悬空或置 1,芯片不选中,输出是高阻态,指示灯全灭或者乱闪,看起来像「电路没接对」,实际是片选没打开。

第二步,把 A4~A10 全部置 0。这一步和上一步是配套的,地址高位接地,保证读的是 0000~1111 这 16 个低位地址。

第三步,把 74LS175 的 CLR 置 0。CLR 低电平有效,置 0 时微地址寄存器被清零,输出地址 0000,控制存储器随之输出 00H 号微指令。这是微程序的入口。

第四步,把时序发生器的 Step 置 1。Step 置 1 表示单步模式,每按一次 start 发一个 T1 脉冲,微地址往前走一步。如果 Step 置 0 进连续模式,时序信号连续发生,指示灯跳得太快,肉眼根本跟不上,做推演验证时会误以为「顺序乱了」。

第五步,打开电源。此时因为 CLR 还是 0,微地址寄存器保持清零,地址线上稳定是 00H,控制存储器输出第 00 号微指令,指示灯应该有一组固定的亮灭组合。

第六步,把 CLR 置 1。这一步千万别忘。CLR 一直保持 0,微地址寄存器就一直被摁在清零状态,你按多少次 start,地址都不动——这就是第 1 章说的「指示灯停在 00 不动」的最常见原因,不是电路接错,是清零信号没放开。

# 上电前引脚预置顺序(对应虚拟实验系统面板操作) EPROM2716.CE = 0 # 片选常开 EPROM2716.OE = 0 # 读使能常开 EPROM2716.A4_A10 = 0 # 高位地址接地,只用 A3~A0 74LS175.CLR = 0 # 先清零,锁定入口地址 00H Timing.Step = 1 # 单步模式 power_on() # 上电,观察 00H 号微指令输出 74LS175.CLR = 1 # 放开清零,否则地址永远不动

上面这段不是真代码,是把面板操作写成顺序清单,方便对照。关键是 CLR 的两次赋值:先 0 后 1,中间夹着上电。顺序反了,比如先置 1 再上电,微地址寄存器的初值不确定,可能从任意地址开始跑,后面所有推演都对不上。

3.3 连线自查表

接完线别急着上电,按下面这张表逐项过一遍,能省掉大半排错时间。

检查项正确状态错误表现
EPROM CE0悬空或 1,输出高阻,灯全灭
EPROM OE0为 1 时读不出数据
A4~A10全 0悬空时地址漂移,读出随机值
74LS175 CLR上电时 0,之后 1一直为 0,地址不动
时序 Step1为 0 时连续跑,看不清
IR7~IR5由数据开关给定悬空时操作码随机,分支乱跳
T1 接线接 74LS175 时钟端接错则地址不锁存

这张表里,IR7~IR5 那一行值得多说一句。原文写得很直白:「这几条信号线本应与指令寄存器的输出引脚相连,但在本实验中,与数据开关相连,指令操作码通过数据开关手动设置。」也就是说,这个实验里没有真正的指令寄存器参与,操作码是你手动拨开关给的。好处是可控,坏处是忘了拨——上电后开关停在某个默认值,你以为在跑 IN 指令,实际跑的是 JMP,微程序走向完全不同。做每条指令的微程序读取之前,先确认开关拨到了对应操作码:IN 是 000,ADD 是 001,STA 是 010,JMP 是 011。

4. 一个 CPU 周期里发生了什么:T1 上升沿、地址转移与分支判定

4.1 微地址的锁存与微指令的输出

微程序控制器的节奏感来自 T1。一个 CPU 周期执行一条微指令,具体动作拆成三步。

第一步,T1 上升沿到来,74LS175 把当前挂在数据输入端的微地址锁存进去,输出端 Q3~Q0 稳定送出这个地址。

第二步,这个地址送到控制存储器 EPROM2716 的 A3~A0,芯片译码后把对应单元的 24 位内容送到 Q0~Q23 输出引脚。这 24 位就是一条微指令。

第三步,24 位里低 5 位(P1、μA3~μA0)送到地址转移逻辑,高 19 位送到各功能部件。地址转移逻辑根据 P1 的值算出下一条微地址,挂在 74LS175 的数据输入端,等下一个 T1 上升沿锁存。

这三步是流水式的,但只有 T1 上升沿那一刻状态才更新。所以单步模式下每按一次 start,看到的是「上一条微指令执行完、下一条微指令地址已就位」的稳定画面。这个特性对做实验很友好——你可以停下来慢慢看每一位,不用担心错过。

CLR 的作用在这个节奏里要单独说。CLR=0 时 74LS175 被强制清零,Q3~Q0 全 0,地址是 00H。原文说「从控制存储器 00H 地址开始执行微程序」,指的就是这个强制入口。CLR 放开后,地址就交给地址转移逻辑接管,从 00H 一路往下走。

4.2 P1=0 与 P1=1:地址转移逻辑的两条路

地址转移逻辑是两级与门、或门搭的组合电路,输入是 μA3~μA0、P1、IR7~IR5,输出是下一条微地址。它的行为按 P1 分成两条路。

P1=0 时,下一条微地址直接等于 μA3~μA0。这是顺序执行路径,微指令在控制存储器里连续排列,一条接一条往下走。原文的表述是「当判别位 P1=0 时,下一条微指令的地址即为后续微地址 μA3~μA0」。

P1=1 时,下一条微地址由指令操作码 IR7~IR5 决定。原文说「一般是将操作码进行简单变换,把变换后的值作为下一条微指令的地址,此地址就是该操作码对应的微程序的入口地址」。变换的具体形式由那 6 个门电路的连线决定,不同实验平台可能略有差异,但思路一致:把 3 位操作码映射到 16 个微地址里的某几个入口。

为什么需要 P1 这个判别位?因为取指阶段的微程序是四条机器指令共用的——不管执行 IN 还是 ADD,前几个周期都要把指令取进来、把操作码送到该去的地方。这段公共流程走完,才根据操作码分道扬镳,进入各自的执行微程序。P1=1 的那条微指令就是岔路口:走完这一拍,地址不再顺序加一,而是跳到操作码对应的入口。

这里有个容易混淆的概念要澄清。P1=1 时,μA3~μA0 这四位并不是完全没用——它们通常参与变换,或者是作为「不需要分支时的默认值」。具体怎么用,取决于门电路怎么接。做实验时如果发现 P1=1 的微指令给出的地址和预期不符,先去看那 6 个门电路的输入接的是哪几根线,而不是急着改微指令代码。

4.3 前 10 条地址怎么推:规则、样例与记录表

原文的实验步骤里有一问:「若此时连续不断地发出时序信号,微程序的执行流程是怎样的?请按顺序写出前 10 条微指令的地址。」这一问看着吓人,其实规则只有两条。

规则一,读当前微指令的末 5 位。P1=0 就把 μA3~μA0 转成八进制,那就是下一条地址;P1=1 就停下来,去看 IR7~IR5 拨的是什么,按变换关系找入口。

规则二,每读一条就把地址记下来,别跳步。中间漏一条,后面全乱。

拿表 7-3 的 00 到 03 行做样例,走一遍。

当前地址末 5 位(P1 μA3 μA2 μA1 μA0)P1下一条地址依据
000 0 0 0 1001μA=0001
010 0 0 1

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询