进位采取与门,单位上的和用异或门
进位数就是三个数进行加和,通过与门,就是两两过与门
描述每位的和项就是,只去描述那个1的情况,即三中有一个,或者三个都为1
是说下一位的进位=此位的两个加数再加上来自上位的进数
当此位的两个加数均为1时,此位必定产生进位信号,这是本位产生的,即g,是生成函数
当有一个为1,且来自上位的进位为1时,也将产生进位信号,这个进位信号可以认为是来自上位的进位信号向后续传递的,所以可以称为传播函数
行波是说从低到高,算完一位的数,就把这位的进数传递给下一位,再去计算下一位,依次传递,即行波。
超前进位是说,需要第i位之前的位数乘积,再或起来
就是每位都需要产生俩个值,一个是或门,一个是与门,然后每位的这两个值在在其他位里组合(与-或起来)除此之外每位还需要去参与计算本位,计算本位需要上位的进位
这个电路图的思路就是只传递每位的g0,p0,而不复用每位的计算结果,想的是算完后能复用那些重复出现的,比如p0c0
但其实难说效率谁高,传递原值的话,可以同时开始计算,但肯定是位数低的先计算完,因为要计算的项少,位数高的计算时间长,因为计算的项多,最终时间由最长的决定
即随着n的增加,n位超前进位加法器的复杂度也在迅速增加,n越大,或门上一级的与门就越多
如果说要复用(递归,打表思路)的话,其实还是行波的思路,就是得等到前面的都算完了这项才能开始算,虽然在前项算完基础上再增加一点规模用的时间可能并不是那么多。
这种还是建立在行波的框架上,只不过每个行波里算得更快一点,但还是要上一块算完才能算这一块
替代模块间的行波进位法的另一种方法是模块间采用第2级超前进位技术
对于每一个模块,它并不给出代表该模块最高位的进位输出信号,而给出代表整个块的产生信号和传递信号
?具体指什么?
在计算每个模块的位数时,需要上一个模块的进数
计算每个模块的进数时,也需要上个模块的进数
每个模块处理完后,产生位数结果与这个位的产生与传播信号,即只有计算完这个模块(需要来自上个模块的进位信号),才能计算出产生与传播信号
块0计算完,产生块0位数和G0,P0
G0,P0与c0计算出这个块的进位,传递给下个块
下个块开始计算
`timescale 1ns/1ns
module mul_binary(
input wire sclk,
input wire rst_n,
input wire start,
input wire [7:0] data_a,
input wire [7:0] data_b,
output reg prd_vld,//product is valid
output reg [15:0] product
);
reg add_shift;
reg shift;
reg load_data;
reg prd_vld_r;
wire M_eq_1;
wire m0;
reg [15:0] multiplicand;
reg [15:0] multiplier;
parameter S_idle=2'b01;
parameter S_cal=2'b10;
reg [1:0] state,next_state;
always @(posedge sclk or negedge rst_n)begin
if(rst_n==1'b0) state<=S_idle;
else state<=next_state;
end
always @(*)begin
add_shift=1'b0;shift=1'b0;
load_data=1'b0;prd_vld_r=1'b0;
next_state=S_idle;
case(state)
S_idle:begin
if(start==1'b1) begin
next_state=S_cal;
load_data=1'b1;
end
else next_state=S_idle;
end
S_cal:begin
if(M_eq_1==1'b1)begin
add_shift=1'b1;prd_vld_r=1'b1;
next_state=S_idle;
end
else begin
next_state=S_cal;
if(m0==1'b1) add_shift=1'b1;
else shift=1'b1;
end
end
default:next_state=S_idle;
endcase
end
always @(posedge sclk or negedge rst_n)begin
if(rst_n==1'b0) begin
multiplicand<=16'd0;
multiplier<=16'd0;
product<=16'd0;
end
else if(load_data==1'b1)begin
multiplicand<={{8{data_a[7]}},data_a};
multiplier<={{8{data_b[7]}},data_b};
product<=16'd0;
end
else if(add_shift==1'b1)begin
multiplier<=multiplier>>1;
multiplicand<=multiplicand<<1;
product<=product+multiplicand;
end
else if(shift==1'b1)begin
multiplier<=multiplier>>1;
multiplicand<=multiplicand<<1;
end
end
always @(posedge sclk or negedge rst_n)begin
if(rst_n==1'b0) prd_vld<=1'b0;
else prd_vld<=prd_vld_r;
end
assign m0=multiplier[0];
assign M_eq_1=(multiplier==1'b1) ? 1'b1:1'b0;
endmodule
组合逻辑电路的输出完全由输入值决定
触发器的输出取决千触发器的状态,而不是任意时刻的输入 值,触发器的输入将引起状态的改变
电路的输出同时依赖于电路之前的状态和当前输入值的一类常用 电路,这种电路称为时序电路
同步时序电路由组合逻辑以及一个或多个触发器实现
该电 路有一组原始输入 w, 并产生一组输出 z。触发器中存储的状态为 Q。在时钟信号的控制下,触发器通过加在其输入端的组合逻辑输入,使得电路从一个状态变化为另一个状态。
即触发器由输入端和时钟信号决定
采用边沿触发的触发器可以确保一个时钟周期中仅发生一次状态变化。它们可以由时钟信 号的上升沿或者下降沿触发。这种产生状态变化的时钟边沿称为有效时钟边沿
的输出显然是 触发器当前状态和原始输入的函数
触发器具有两路组合逻辑输入,分别为原始输入w 和触发器的当前输出Q 。因此电 路状态的改变不仅取决千触发器的当前状态,还取决于电路的原始输人。
时序电路的输出总取决千触发器的当前状态,但却不 一定直接依赖于原始输入 。
确定电路中需要多少状态,并获得从一个状态到另一个状态的所有可能变化
一个好的方法是选择 一个特殊状态作为起始状态,这个状态应该是电 路加电或 者复位后进入的状态。
在画表的时候就不用考虑时钟信号,只是说当前什么状态,以及当前这个状态在输入信号w的影响下会转变成什么信号(通过组合电路),而在时序图中就需要综合时钟信号,来确定什么时候应该发生转变
时钟沿就相当于使能端,只有有有效的时钟沿才会触发触发器,使其发生状态改变,时钟沿就相当于开关,
由于采用上升沿触发的触发器,所有信号的变化都立即发生千时钟上升沿之后
区分输出和次态,输出是时序电路整体的输出,次态是当前输入对时序电路自身造成的影响,二者都由当前的时序电路所产生
理解这个状态图的关键点是当前时钟周期中的弧线上对应的输出标记来自千当前状态 结点。
每个状态就是由参数的取值确定,状态变化就是参数改变的方式
时钟信号就是触发器触发的信号,而触发器触发后有什么影响,怎么作用,有什么作用则由触发器自身的特性决定
每个时刻,状态机都存储(保留)着两个状态,一个现态,一个次态,次态在确定输入后确定(有输入信号到达即可),即现态保持不变时,次态随着输入信号的改变而时刻改变,但次态的改变并不意味着现态要跟着改变,次态是下一个现态,至于什么时候是下一个,就看时钟信号,当时钟信号的时钟沿到来时,触发器被触发,触发器依据此时现态和输入信号而生成(或存储)的次态信号赋值给现态 。(在采用D触发器的情况下)
即触发器依据时钟信号决定什么时候更新现态,以及怎么更新
就是有多少个状态就有多少个码(状态变量)
确定次态表达式,有两个参数,一个是当前状态,一个是当前输入w
但是触发器的数目从2个增加到了4个(即用来确定状态变量取值的机器多了,触发器在时钟信号的作用下,依据当前状态和输入信号w,产生次态)
触发器接收两个信号,一个是时钟信号,一个是组合电路传来的次态信号,输出相应信号(根据相应的触发器性质),改变现态,并做出电路输出