📄 一句话概括
每条指令都标着要花几个时钟拍(T 状态)——把拍数加起来除以时钟频率,程序要跑多久就有数了。
📝 本节和前面几节的关系
程序装填好了,最后算一笔账:它要跑多久?——这是第三章的收尾,也是性能思维的第一课。
一、T 状态:指令的价目表
每条指令执行要花若干个时钟周期(Z80 术语叫 T 状态):LD A,n 花 7 拍、OUT (n),A 花 11 拍、HALT 花 4 拍。 为什么有零有整?取指令要 4 拍,剩下的花在【再取一个操作数】【跟外设握手】这些动作上。 于是【程序跑多快】这道题变成了一道加法题:把每条指令的拍数加起来,除以时钟频率。
二、算一遍小程序的账
三条指令合计 7 + 11 + 4 = 22 拍;时钟 4 MHz(每秒 400 万拍); 执行时间 = 22 ÷ 4,000,000 ≈ 5.5 微秒——眨一次眼的时间里,这段程序能跑成千上万遍。 真实程序有几万条指令还带循环,账要累加着算——循环体的拍数别忘了乘循环次数。
三、性能思维的起点
这套【数指令、加拍数、乘循环】的方法,是一切性能优化的第一把尺子:先算账,再动手。 【⚠️ 2026 现状】现代 CPU 玩超标量、乱序执行、多级缓存,拍数相加的简单账早已不够用——但先算账这个习惯,仍是每个工程师的基本功。
四、动手 Demo:执行时间估算器
把三条指令的拍数加起来,按 4 MHz 换算成微秒——再算一遍带循环的账。
# 拍数账 -> 执行时间
cycles = [("LD A, 128", 7), ("OUT (2), A", 11), ("HALT", 4)]
total = sum(c for _, c in cycles)
hz = 4_000_000
print("合计拍数 =", total)
print("执行时间 = %.2f 微秒" % (total / hz * 1e6))
loop = 1000
print("若这段在循环里跑 1000 次: %.2f 毫秒" % (total * loop / hz * 1000))
实跑输出:
--------------------------------------------------------------------
估算程序执行时间——拍数账
--------------------------------------------------------------------
不同指令花的时钟拍数(T 状态)不一样。按 Z80 手册的典型值记账:
指令 T 状态数 白话
-------------------------------------------------------------
LD A, 128 7 取指令 4 拍 + 取操作数 3 拍
OUT (2), A 11 取指 4 + 取端口号 3 + 对外握手 4
HALT 4 取一条指令就完事
合计拍数 = 7 + 11 + 4 = 22 拍
时钟 4 MHz = 每秒 4000000 拍
执行时间 = 22 / 4000000 秒 = 5.50 微秒
结论:这段程序 22 拍、约 5.5 微秒跑完——快是因为指令少。
真实程序几万条指令、还有循环,账要累加着算。
这也是优化程序的第一把尺子:先数指令,再数循环次数。
循环账要点:把循环体拍数乘次数——循环是【时间放大器】。 反过来用:想在 1 秒内跑完 N 次循环,先算拍数上限——这就是嵌入式开发的日常估算。
30 秒实验
- 把 OUT 指令换成两条 LD(各 7 拍),重算总时间——少了一次对外握手,快了多少?
- 查一查本机 CPU 的主频,按同样公式算一遍现代机器的【每秒拍数】。
常见误区
- 以为所有指令一样快——每条指令拍数不同(Z80 从 4 拍到 23 拍都有)。
- 以为时钟频率就是【每秒指令数】——要除以每条指令的拍数才是执行速度。
自测三问(点开对答案)
1. 什么是 T 状态? —— Z80 中一个时钟周期——每条指令要花若干个 T 状态完成。 2. 三条指令 22 拍、4 MHz,执行时间是多少? —— 约 5.5 微秒(22 除以 400 万秒)。 3. 为什么说【先算账】仍是现代工程师的基本功? —— 现代 CPU 的拍数账早已复杂化,但先算量级、再动手优化这个习惯不变。- ☐ 下一章(第四章 程序像河水一样流动着)
相关笔记
- ☕ Java基础 · 索引 — 性能意识在写第一个程序时就能建立
- 输入测试程序并进行调试 — 上一章亲手装填的那 5 个字节
- 💻 计算机是怎样跑起来的 · 索引