并行数据流转换为一种特殊串行数据流模块的设计,设计两个可综合的电路模块
- 1,第一个可综合模块,M1。
- 2,描述M2模块
- 3,描述M0模块的Verilog代码
- 4,描述顶层模块
- 5,电路生成的门级网表,netlist
- 6,前仿真波形验证
参考文献1
参考文献2
并行数据流转换为一种特殊串行数据流模块的设计:
设计两个可综合的电路模块,第一个模块(M1)能把4位的并行数据转换为符合以下协议的串行数据流,数据流用scl和sda两条线传输,sclk为输入的时钟信号,data[3:0]为输入数据,ack为M1请求M0发新数据信号。第二个模块(M2)能把串行数据流内的信息接收到,并转换为相应16条信号线的高电平,即若数据为1,则第一条线路为高电平,数据为n,则第N条线路为高电平。M0为测试用信号模块。该模块接收M1发出的ack信号,并产生新的测试数据[3:0].
1,第一个可综合模块,M1。
第一个模块M1能把4位的并行数据转换为符合以下协议的串行数据流,数据流用scl和sda两条线传输,sclk 为输入的时钟信号,data[3:0]为输入数据,ack为M1请求M0发新数据信号。
通信协议: scl为不断输出的时钟信号,如果scl为高电平时,sda由高变低时刻,串行数据流开始;如果scl为高电平时,sda由低变高时刻,串行数据结束。sda信号的串行数据位必须在scl为低电平时变化,若变为高则为1,否则为0.
模块功能,按照设计要求,把输入的 4位 并行数据转换为 协议要求的串行数据流,并由scl 和sda配合输出
本模块为RTL 可综合模块,已通过综合后 门级网表 仿真
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/11/21 11:25:20
// Design Name:
// Module Name: ptosda
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
// 并行数据流转换为一种特殊串行数据流模块的设计
// 模块功能,按照设计要求,把输入的 4位 并行数据转换为 协议要求的串行数据流,
// 并由scl 和sda配合输出
// 本模块为RTL 可综合模块,已通过综合后 门级网表 仿真
module ptosda(rst, sclk, ack, scl, sda, data);
input sclk, rst;
// sclk,输入的时钟信号
input [3:0] data; // 并行口数据输入
output ack; // 请求新的转换数据
output scl; // 通信协议,scl为不断输出的时钟信号
// scl是1, sda由1变0,串行数据流开始;
// scl是0, sda由0变1,串行数据流结束;
output sda; // 定义sda为单向的串行输出
// inout sda;
reg scl, link_sda, ack, sdabuf; // 不断输出时钟信号
// 连接 sda // 设计 一个寄存器
// ask_for_new_data
// sda 缓存器 // 设计 一个寄存器
reg [3:0] databuf; // 数据 缓存器 ,用来接收 data 数据
reg [7:0] state; // 状态
out16hi m2(.scl(scl), .sda(sda), .outhigh());
assign sda = link_sda?sdabuf:1'b0; // link_sda 控制 sdabuf 输出到串行总线上
// assign sda = link_sda?sdabuf:1'bz; // link_sda 控制 sdabuf 输出到双向串行总线上
parameter ready = 8'b0000_0000, // 设计 9个 状态参数
start = 8'b0000_0001,
bit1 = 8'b0000_0010,
bit2 = 8'b0000_0100,
bit3 = 8'b0000_1000,
bit4 = 8'b0001_0000,
bit5 = 8'b0010_0000,
stop = 8'b0100_0000,
idle = 8'b1000_0000;
always@(posedge sclk or negedge rst) // 由输入的 sclk时钟信号 产生串行输出时钟scl
if(!rst)
scl <= 1;
else
scl <= ~scl;
always@(posedge ack) // 请求新数据时 存入 并行总线上 要转换的数据
databuf <= data;
// 主状态机,产生控制信号,根据databuf 中保存的数据,按照协议产生sda串行信号
// always@(posedge sclk or negedge rst)
always@(negedge sclk or negedge rst)
if(!rst) begin
link_sda <= 0; // 把 sdabuf 与 sda 串行总线断开
state <= ready;
sdabuf <= 1;
ack <= 0; // 请求新数据置0
end
else begin
case(state)
ready: if(ack) // 并行数据已经到达
begin
link_sda <= 1; // 把 sdabuf 与 sda 串行总线连接
state <= start; //
end
else // 并行数据尚未到达
begin
link_sda <= 0; // 把 sda 总线让出,若前面把 sda 定义成双向串行总线,
// 则此时 sda 可作为输入
state <= ready;
ack <= 1; // 请求新数据信号置 1
end
start: if(scl && ack) // 产生 sda 的开始信号
begin
sdabuf <= 0; // 在 sda 连接的前提下,输出开始信号
state <= bit1;
end
else
state <= start;
bit1: if(!scl) // 在 scl 为低电平时送出最高位 databuf[3]
begin
sdabuf <= databuf[3];
state <= bit2;
ack <= 0;
end
else
state <= bit1;
bit2: if(!scl) // 在 scl 为低电平时送出次高位 databuf[2]
begin
sdabuf <= databuf[2];
state <= bit3;
end
else
state <= bit2;
bit3: if(!scl) // 在 scl 为低电平时送出次低位 databuf[1]
begin
sdabuf <= databuf[1];
state <= bit4;
end
else
state <= bit3;
bit4: if(!scl) // 在 scl 为低电平时送出最低位 databuf[0]
begin
sdabuf <= databuf[0];
state <= bit5;
end
else
state <= bit4;
bit5: if(!scl) // 为产生结束信号做准备,先把 sda 变为低
begin
sdabuf <= 0;
state <= stop;
end
else
state <= bit5;
stop: if(scl) // 在scl为高时,把 sda 由低变高 产生结束信号
begin
sdabuf <= 1;
state <= idle;
end
else
state <= stop;
idle: begin
link_sda <= 0; // 把 sdabuf 与 sda 串行总线脱开
state <= ready;
// sdabuf <= 1;
end
default: begin
link_sda <= 0;
sdabuf <= 1;
state <= ready;
end
endcase
end
endmodule
2,描述M2模块
模块功能: 按照协议接收串行数据,进行处理并按照数据值在相应位输出高电平;
本模块为RTL可综合模块,已通过综合后门级网表仿真。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/11/21 11:29:07
// Design Name:
// Module Name: out16hi
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
// 描述 M2 模块的Verilog 代码
// 模块功能,按照协议接收 串行数据,进行处理 并按照数据值 在相应位 输出高电平
// 本模块为 RTL可综合模块,已通过综合后 门级网表仿真
module out16hi(scl, sda, outhigh);
input scl, sda; // 串行数据输入
output [15:0] outhigh; // 根据输入的串行数据设置高电平位
reg [5:0] mstate; // synthesis preserve*/;
// 本模块的主状态
// /* synthesis preserve*/ 为综合指令, 使综合器布局布线后仍能保留状态信号,
// 以便于观察,不同的综合器综合指令并不相同,必须参考综合器的技术资料才能掌握
//
reg [3:0] pdata, pdatabuf;
// 记录串行数据位时, 用寄存器和最终数据寄存器
reg [15:0] outhigh; // 输出 位寄存器;
reg startflag, endflag; // 数据开始和结束标志
// always@(posedge sda)
always@(negedge sda)
if(scl)
startflag <= 1; // 串行数据开始标志
else if(endflag)
startflag <= 0;
always@(posedge sda)
if(scl) begin
endflag <= 1; // 串行数据 结束标志
pdatabuf <= pdata; // 把收到的 4位数据 存入寄存器
end
else
endflag <= 0; // 数据接收还没有结束
parameter ready = 6'b00_0000,
sbit0 = 6'b00_0001,
sbit1 = 6'b00_0010,
sbit2 = 6'b00_0100,
sbit3 = 6'b00_1000,
sbit4 = 6'b01_0000;
//always@( padabuf) // 把收到的数据变为相应位的高电平
always@(pdatabuf) // 把收到的数据变为相应位的高电平
begin
case(pdatabuf)
4'b0001: outhigh = 16'b0000_0000_0000_0001;
4'b0010: outhigh = 16'b0000_0000_0000_0010;
4'b0011: outhigh = 16'b0000_0000_0000_0100;
4'b0100: outhigh = 16'b0000_0000_0000_1000;
4'b0101: outhigh = 16'b0000_0000_0001_0000;
4'b0110: outhigh = 16'b0000_0000_0010_0000;
4'b0111: outhigh = 16'b0000_0000_0100_0000;
4'b1000: outhigh = 16'b0000_0000_1000_0000;
4'b1001: outhigh = 16'b0000_0001_0000_0000;
4'b1010: outhigh = 16'b0000_0010_0000_0000;
4'b1011: outhigh = 16'b0000_0100_0000_0000;
4'b1100: outhigh = 16'b0000_1000_0000_0000;
4'b1101: outhigh = 16'b0001_0000_0000_0000;
4'b1110: outhigh = 16'b0010_0000_0000_0000;
4'b1111: outhigh = 16'b0100_0000_0000_0000;
4'b0000: outhigh = 16'b1000_0000_0000_0000;
endcase
end
always@(posedge scl) // 在检测到开始标志后, 每次 scl 正跳变 沿 时接收数据,共 4位
if(startflag)
case(mstate)
sbit0: begin
mstate <= sbit1;
pdata[3] <= sda;
$display("I am in sdabit0");
end
sbit1: begin
mstate <= sbit2;
pdata[2] <= sda;
$display("I am in sdabit1");
end
sbit2: begin
mstate <= sbit3;
pdata[1] <= sda;
$display("I am in sdabit2");
end
sbit3: begin
mstate <= sbit4;
pdata[0] <= sda;
$display("I am in sdabit3");
end
sbit4: begin
mstate <= sbit0;
$display("I am in sdastop");
end
default: mstate <= sbit0;
endcase
else
mstate <= sbit0;
endmodule
3,描述M0模块的Verilog代码
模块功能: 本模块产生测试信号对设计中的模块进行测试。
本模块只用于测试,不能通过综合转换为电路。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/11/21 14:03:48
// Design Name:
// Module Name: sigdata
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
// 描述 M0 模块的 Verilog代码如下:
// 模块功能:本模块产生测试信号对设计中的模块进行测试
// 本模块只用于测试,不能通过综合转换为电路
`timescale 1ns/1ns
`define halfperiod 50
module sigdata(rst, sclk, data, ask_for_data
);
output rst; // 复位信号
output [3:0] data; // 输出的数据信号
output sclk; // 输出的时钟信号
input ask_for_data; // 从并串转换器来的请求数据信号
reg rst, sclk;
reg [3:0] data;
initial begin
rst = 1;
#10 rst = 0;
#(`halfperiod * 2 + 3) rst = 1;
end
initial begin
sclk = 0;
data = 0;
#(`halfperiod * 1000) $stop;
end
always #(`halfperiod) sclk = ~sclk; // 产生第一个模块需要的输入时钟
// 每次请求新数据信号的整跳变沿,等一段时间后将输出数据增加1
always@(posedge ask_for_data)
#(`halfperiod/2 + 3) data = data + 1;
endmodule
4,描述顶层模块
模块功能: 对所设计的两个可综合模块
ptosda
和out16hi
进行联合测试。观察ptosda
模块能否正确地把并行数据转换成符合协议要求的串行码流;串行码流能否通过out16hi
模块的处理输出符合设计要求的信号。本模块是为教学需要专门设计的。为了使大家容易理解接口功能,作了许多简化,因此无实用价值。
模块说明: 本模块还可以用于综合或布局布线后的电路网表模块的测试。做后仿真时,把包括的文件改为布局布线后的门级电路文件,即由综合工具生成的
ptosda.vm
和out16hi.vm
文件,或布局布线工具产生的ptosda.vo
和out16hi.vo
文件。为了能使门级电路网表模块进行仿真,有时还需要包括一个布线所用的FPGA或ASIC基本元件仿真库模块。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/11/21 14:05:43
// Design Name:
// Module Name: top
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
// 描述顶层模块的 Verilog代码如下:
// top.v
// 模块功能:对所设计的两个可综合模块 ptosda 和 out16hi 进行联合测试
// 观察 ptosda 模块能否正确地把 并行数据转换成 符合协议要求的串行码流;
// 串行码流能否通过 out16hi 模块的处理输出符合设计要求的信号。
// 本模块是为教学需要专门设计的。
// 为了使大家容易理解接口功能,作了许多简化,因此无 实用价值
// 模块说明:本模块还可以用于综合或布局布线后的电路网表模块的测试。
// 做后仿真时, 把包括的文件 改为 布局布线后的 门级电路网表文件,即由综合工具生成的
// pstosda.vo 和 out16hi.vo 文件。
// 为了能使门级电路网表模块进行仿真,有时还需要包括一个布线所用的FPGA 或 ASIC
// 基本元件仿真库模块
// `timescale 1ns/1ns
`include "sigdata.v"
`include "ptosda.v"
`include "out16hi.v"
// 可用综合后产生的 门级 Verilog网表(netlist)文件 和 布局布线后产生的带延迟参数的Verilog 网表
// (netlist)文件来代替上面两个文件。 分别进行门级后仿真和布线后仿真。
// 这两种文件的扩展名不同,但都是Verilog门级模块
module top;
wire [3:0] data;
wire sclk;
wire scl;
wire sda;
wire rst;
wire [15:0] outhigh;
sigdata m0(.rst(rst), .sclk(sclk), .data(data), .ask_for_data(ack));
ptosda m1(.rst(rst), .sclk(sclk), .ack(ack), .scl(scl), .sda(sda), .data(data));
out16hi m2(.scl(scl), .sda(sda), .outhigh(outhigh));
endmodule