时钟信号:
执行部件之间的数据通路调度,是由CPU内的时序发生器所产生的微操作时间信号控制,受到时钟的驱动。
时序发生器根据时钟信号的脉冲,产生微操作时间信号,这些信号用于精确地控制各个部件的动作和数据的传输。微操作时间信号可以用于各个执行部件的使能、数据选择和操作控制等。
时钟信号作为CPU系统中的基准信号,提供了统一的时间参考。时钟信号固定的频率和周期确保了CPU内部各个部件按照同步的节奏进行操作和通信。时钟信号的变化驱动着时序发生器的工作,使得微操作时间信号按照预定的时序顺序产生。
D触发器:
触发器是时序逻辑电路的基本单元,用来存储1位2进制信息,具有记忆和存储功能,其信息由双稳态电路来保存。
D触发器是一种最简单的触发器,在触发边沿到来时,将输入端的值存入其中,并且这个值与当前存储的值无关。
在两个有效的脉冲边沿之间,D的跳转不会影响触发器存储的值,但是在脉冲边沿到来之前,输入端D必须有足够的建立时间,保证信号稳定。
考虑这个场景:
两个寄存器单元R1,R2之间通过一排平行等位宽的D触发器桥连,分析该数据通路(IPO)的时钟信号的周期范围。
给出如下参数:
Tsu : 触发器建立时间 Time of setup
Th : 触发器保持时间 Time of hold
T : 电路的工作周期
Tco : 时钟输出延迟 Time of clock output
Tskew : 时钟偏斜(clock skew),又称为时钟偏移,是指时钟信号到达数字电路各部分所用时间差异。
Tcomb: 组合逻辑的延迟。
则电路的工作周期 满足如下关系:
保持时间不违例:Tco+Tcomb-Tskew > Th
建立时间不违例:T+Tskew > Tco+Tcomb+Tsu
所以该问题可以转化为DAG(有向无环图)的最长关键路径问题,可以使用拓扑排序和动态规划的方法进行分析。
有向无环图即为上述数据通路:R1 - D触发器阵列 - R2
首先定义D触发器的基本参数
typedef int ns_t;//微秒单位
struct D_trigger{
ns_t Tsu;//建立时间
ns_t Th;//保持时间
ns_t Tco;//延迟时间
ns_t Tskew { 0U };//偏移时间
};
设置逻辑门部件的时延参数映射(单位为1T/ns)
enum class GATE : unsigned char
{ IN, OUT,//假象起点和终点,统一入口和出口
D, CLK,//D:数据端引脚,CLK:时钟接口
Q, NQ,//Q输出,NQ:反相输出
AND, OR, NOT,//与或非
NAND, NOR, XOR };//反相与或、异或
std::unordered_map<GATE, ns_t> delay_hash
{//相关逻辑门部件的连通时延
{GATE::D, 0U},
{GATE::CLK, 0U},
{GATE::Q, 0U},
{GATE::NQ, 0U},
{GATE::AND, 1U},
{GATE::OR, 1U},
{GATE::NOT, 2U},
{GATE::NAND, 3U},
{GATE::NOR, 3U},
{GATE::XOR, 3U} };
通过给每个逻辑门部件编上编号,建立联通关系,形成单向图
可以看到总共13个逻辑单元,按照编号顺序存储
constexpr std::size_t GATES { 13U };//一共13个元器件
GATE gates[GATES]
{按照编号顺序存储数据通路
GATE::IN,
GATE::D,
GATE::CLK,
GATE::NOT,
GATE::OR,
GATE::NOT,
GATE::NOR,
GATE::NOR,
GATE::NOR,
GATE::NOR,
GATE::Q,
GATE::Q,
GATE::OUT,
};
建图
int indeg[GATES] {};//入度
struct graph{
struct edge{
int __forward__;
int __next__;
} edges[32U];//链式向前星存图
int hG[GATES] {};
std::size_t tot {};
graph(void) noexcept{ std::memset(hG, -1, sizeof hG); }
void insert(int from, int to) noexcept{
edges[tot]
= (edge){ __forward__ : to,
__next__ : hG[from] };
hG[from] = tot++;
++indeg[to];
}
} G;
void construct(void){
//按照数据通路示意图建图
G.insert(0, 1);
G.insert(0, 2);
G.insert(2, 3);
G.insert(2, 4);
G.insert(3, 4);
G.insert(1, 5);
G.insert(5, 7);
G.insert(4, 6);
G.insert(4, 7);
G.insert(6, 8);
G.insert(7, 9);
G.insert(8, 10);
G.insert(9, 11);
G.insert(10, 12);
G.insert(11, 12);
}
拓扑排序得到拓扑序列
std::queue<int> q;
for(auto i {0U}; i < GATES; ++i)
if(!indeg[i]) q.push(i);
while(!q.empty()){
int current = q.front();
q.pop();
for(int i {G.hG[current]}; ~i; i = G.edges[i].__next__)
if(! --indeg[G.edges[i].__forward__])
q.push(G.edges[i].__forward__);
topology[counter++] = current;
}
std::puts("topology sequence:");
for( auto i {0U}; i < GATES; ++i)
std::printf("[G%d]%c", topology[i], " \n"[i == GATES]);
动态规划得到最大时延的通路,和最小时延的通路
std::memset(maximal_delay, -1, sizeof maximal_delay);
std::memset(minimal_delay, 0x3f, sizeof minimal_delay);
maximal_delay[0] = minimal_delay[0] = 0;
for( auto i {0U}; i < GATES; ++i){
int current { topology[i] };
for(int u {G.hG[current]}; ~u; u = G.edges[u].__next__){
int next = G.edges[u].__forward__;
if(maximal_delay[current] + delay_hash[gates[current]]
> maximal_delay[next]){
maximal_delay[next]
= maximal_delay[current] + delay_hash[gates[current]];
maximal_delay_path_previous[next] = current;
}
if(minimal_delay[current] + delay_hash[gates[current]]
< minimal_delay[next]){
minimal_delay[next]
= minimal_delay[current] + delay_hash[gates[current]];
minimal_delay_path_previous[next] = current;
}
}
}
通过递归工作站倒序输出
void print_maximal_delay_path(int current){
if(!~current) return (void)std::printf("\n\n");
print_maximal_delay_path(maximal_delay_path_previous[current]);
std::printf("[G%d] --> ", current);
}
void print_minimal_delay_path(int current){
if(!~current) return (void)std::printf("\n\n");
print_minimal_delay_path(minimal_delay_path_previous[current]);
std::printf("[G%d] --> ", current);
}
程序的执行结果
完整代码
#include <unordered_map>
#include <queue>
#include <cstring>
#include <cstdio>
typedef int ns_t;//微秒单位
struct D_trigger{
ns_t Tsu;
ns_t Th;
ns_t Tco;
ns_t Tskew { 0U };
};
enum class GATE : unsigned char
{ IN, OUT,
D, CLK,
Q, NQ,
AND, OR, NOT,
NAND, NOR, XOR };
std::unordered_map<GATE, ns_t> delay_hash
{
{GATE::D, 0U},
{GATE::CLK, 0U},
{GATE::Q, 0U},
{GATE::NQ, 0U},
{GATE::AND, 1U},
{GATE::OR, 1U},
{GATE::NOT, 2U},
{GATE::NAND, 3U},
{GATE::NOR, 3U},
{GATE::XOR, 3U} };
constexpr std::size_t GATES { 13U };
GATE gates[GATES]
{
GATE::IN,
GATE::D,
GATE::CLK,
GATE::NOT,
GATE::OR,
GATE::NOT,
GATE::NOR,
GATE::NOR,
GATE::NOR,
GATE::NOR,
GATE::Q,
GATE::Q,
GATE::OUT,
};
int indeg[GATES] {};
struct graph{
struct edge{
int __forward__;
int __next__;
} edges[32U];
int hG[GATES] {};
std::size_t tot {};
graph(void) noexcept{ std::memset(hG, -1, sizeof hG); }
void insert(int from, int to) noexcept{
edges[tot]
= (edge){ __forward__ : to,
__next__ : hG[from] };
hG[from] = tot++;
++indeg[to];
}
} G;
int topology[GATES] {};
int counter {};
int maximal_delay[GATES] {};
int minimal_delay[GATES] {};
int maximal_delay_path_previous[GATES] {};
int minimal_delay_path_previous[GATES] {};
void print_maximal_delay_path(int current){
if(!~current) return (void)std::printf("\n\n");
print_maximal_delay_path(maximal_delay_path_previous[current]);
std::printf("[G%d] --> ", current);
}
void print_minimal_delay_path(int current){
if(!~current) return (void)std::printf("\n\n");
print_minimal_delay_path(minimal_delay_path_previous[current]);
std::printf("[G%d] --> ", current);
}
void construct(void){
G.insert(0, 1);
G.insert(0, 2);
G.insert(2, 3);
G.insert(2, 4);
G.insert(3, 4);
G.insert(1, 5);
G.insert(5, 7);
G.insert(4, 6);
G.insert(4, 7);
G.insert(6, 8);
G.insert(7, 9);
G.insert(8, 10);
G.insert(9, 11);
G.insert(10, 12);
G.insert(11, 12);
}
int main(void){
construct();
std::queue<int> q;
for(auto i {0U}; i < GATES; ++i)
if(!indeg[i]) q.push(i);
while(!q.empty()){
int current = q.front();
q.pop();
for(int i {G.hG[current]}; ~i; i = G.edges[i].__next__)
if(! --indeg[G.edges[i].__forward__])
q.push(G.edges[i].__forward__);
topology[counter++] = current;
}
std::puts("拓扑排序序列:\n");
for( auto i {0U}; i < GATES; ++i)
std::printf("[G%d]%c", topology[i], " \n"[i == GATES]);
std::memset(maximal_delay, -1, sizeof maximal_delay);
std::memset(minimal_delay, 0x3f, sizeof minimal_delay);
maximal_delay[0] = minimal_delay[0] = 0;
for( auto i {0U}; i < GATES; ++i){
int current { topology[i] };
for(int u {G.hG[current]}; ~u; u = G.edges[u].__next__){
int next = G.edges[u].__forward__;
if(maximal_delay[current] + delay_hash[gates[current]]
> maximal_delay[next]){
maximal_delay[next]
= maximal_delay[current] + delay_hash[gates[current]];
maximal_delay_path_previous[next] = current;
}
if(minimal_delay[current] + delay_hash[gates[current]]
< minimal_delay[next]){
minimal_delay[next]
= minimal_delay[current] + delay_hash[gates[current]];
minimal_delay_path_previous[next] = current;
}
}
}
maximal_delay_path_previous[0] = -1;
minimal_delay_path_previous[0] = -1;
std::puts("\n\n最大时延通路:");
print_maximal_delay_path(GATES - 1);
std::puts("\n\n最小时延通路:");
print_minimal_delay_path(GATES - 1);
std::printf("\n\n最大时延:\t%dT\n", maximal_delay[GATES-1]);
std::printf("\n\n最小时延:\t%dT\n", minimal_delay[GATES-1]);
return 0;
}