verilog中双向端口inout的使用的心得
关于inout管脚的使用说明

本人也是初学者,关于inout的verilog使用方法网上流传着很多版本。
在此将两个版本综合一下。
经本人测试,两种写法都能实现。
方法一:
assign ds18b20=ds18b20_reg;
这样的话,后面可以对ds18b20_reg进行赋值,可以赋值为0,z。
我没试过输出1,估计也是可以的。
这种方法意思是管脚与寄存器连接。
方法二:
assign ds18b20=(ds18b20_reg==0)?ds18b20_reg:1'bz;
这种方法实际上是定义了ds18b20_reg为使能端。
当ds18b20_reg==0为真时,三态门导通,可以作为输出;当ds18b20_reg==0为假时,三态门不导通,可以作为输入。
这种方法很形象的说明了inout管脚作为三态门的结构:使能信号、输入、输出。
这里ds18b20_reg 也可以替换成其他寄存器。
下面附上扒来的inout管脚电路图:
图一:详细图
图二:简单描述。
汇编语言中OUT和IN的用法

汇编语言中OUT和IN的用法在汇编语言中,OUT和IN是两条常用的指令,用于进行输入输出操作。
OUT指令用于向外部设备输出数据,而IN指令则用于从外部设备读取数据。
本文将详细介绍这两条指令的用法和常见应用情况。
一、OUT指令的用法OUT指令用于将数据从微处理器输出到外部设备,通常用于与键盘、显示器等设备的交互。
OUT指令的格式如下:```OUT DX, AL```其中,DX为输出端口的地址,而AL为要输出的数据。
OUT指令的使用步骤如下:1. 向DX寄存器中加载要输出数据的端口地址;2. 使用AL寄存器存放要输出的数据;3. 执行OUT指令完成输出操作。
例如,若需要向端口地址为80h的显示器输出数据55h,可以使用如下汇编代码:```MOV DX, 80hMOV AL, 55hOUT DX, AL```这样,55h将被输出到端口地址为80h的显示器上。
二、IN指令的用法与OUT指令相反,IN指令用于从外部设备读取数据到微处理器中,用于实现键盘、鼠标等设备的输入操作。
IN指令的格式如下:```IN AL, DX```其中,AL为读取到的数据,而DX为输入端口的地址。
IN指令的使用步骤如下:1. 向DX寄存器中加载要读取数据的端口地址;2. 执行IN指令,将读取到的数据存放到AL寄存器中。
例如,若需要从端口地址为60h的键盘读取数据,可以使用如下汇编代码:```MOV DX, 60hIN AL, DX```这样,从键盘读取到的数据将被存放在AL寄存器中。
三、OUT和IN的常见应用1. 输入和输出控制:通过OUT指令向显示器输出字符、控制光标位置等;通过IN指令从键盘读取字符,实现用户输入控制。
2. 与外设通信:通过OUT指令向串口、并口等外部设备输出数据,用于与其它设备进行通信;通过IN指令从这些外部设备读取数据,实现数据的接收和处理。
3. 程序调试与测试:在程序调试时,可以使用OUT指令将调试信息输出到控制台或显示器上,方便程序员进行调试;同时,可以使用IN指令从特定的端口读取调试信息,实现程序的测试与分析。
Verilog的双向IO口的实现(

Verilog的双向IO口的实现(最近有一个项目要用到FPGA,还要用硬件描述语言综合出一个双向IO口用作地址数据总线。
一直没能够实现,在实验过程中遇到了或这或那的问题,终于在今天有所突破!能够正确的读写CAN控制芯片SJA1000的测试寄存器。
在试验中也总结了一些东西,如下:1、Inout口,一般要放在最顶层的V文件中,我试验过放到下面的v文件中,没能够成功(更正一下:inout并非一定要在最顶层,也可以在底层设置。
具体可参见黑金开发板建模篇实验13 DS1302实时时钟驱动。
)。
2、在一个module中,可以将输出定义为reg型,然后直接与要驱动module的wire型输入相连,没有问题。
3、在调试程序的过程中,尽量借助于工具,如quartus内部的Signal Tap。
之前一直不会使用,现在也在慢慢学习。
用来模拟的是intel模式的总线读写其时序图如下:代码包括下面的及部分:can_top.vmodule can_top(CLK,RSTn,Row_scan,Column_scan,can_pin,can_ALE,can_WR,can_RD,can_CS,can_dir,can_rst_out);input CLK;input RSTn;output [7:0] Row_scan; output [1:0] Column_scan; inout [7:0] can_pin;output can_ALE;output can_WR;output can_RD;output can_CS;output can_dir;output can_rst_out;wire [7:0] data_in;wire rmd;wire wmd;wire [7:0] adr;wire [7:0] data_tx;wire [7:0] data_rx;wire rd_flag;wire wr_flag;trans_control U3(.CLK(CLK),.RSTn(RSTn),.data_in(data_in),.Row_scan(Row_scan),.Column_scan(Column_scan) ); wire can_rst;can_ctr U1(.CLK(CLK),.RSTn(RSTn),.rd_flag(rd_flag),.wr_flag(wr_flag),.data_rx(data_rx),.data_display(data_in), .rmd(rmd), .wmd(wmd),.adr(adr),.data_tx(data_tx),.can_rst(can_rst));can_op U2(.CLK(CLK),.RSTn(RSTn),.can_rst_in(can_rst),.rmd(rmd),.wmd(wmd),.adr(adr),.data_tx(data_tx),.can_in(can_in_temp),.en_out(en_out),.can_out(can_out),.read_cmd(read_cmd),.data_rx(data_rx),.can_ALE(can_ALE),.can_WR(can_WR),.can_RD(can_RD),.can_CS(can_CS),.can_dir(can_dir),.rd_flag(rd_flag),.wr_flag(wr_flag),.can_rst_out(can_rst_out));wire en_out;wire [7:0] can_out;// wire [7:0] can_in;reg [7:0] can_in_temp;wire read_cmd;always @ ( posedge CLK or negedge RSTn )beginif(!RSTn)can_in_temp<=8'b1000_1001;elsebeginif(read_cmd==1'b1)can_in_temp <= can_pin;endend// assign can_in = can_in_temp;assign can_pin = (en_out==1'b1)?can_out:8'bZZZZZZZZ; //双向口设置endmodulecan_ctr.vmodule can_ctr(CLK,RSTn,rd_flag,data_rx,data_display,rmd,wmd,adr,data_tx,can_rst);input CLK;input RSTn;input rd_flag;input wr_flag;input [7:0] data_rx;output [7:0] data_display;output rmd;output wmd;output [7:0] adr;output [7:0] data_tx;output can_rst;reg [7:0] data_display_temp;reg rmd_temp;reg wmd_temp;reg [7:0] adr_temp;reg [7:0] data_tx_temp;reg can_rst_temp;reg rst_flag;parameter TS = 26'd29_999_999; parameter T1S = 26'd49_999_999;always @ ( posedge CLK or negedge RSTn )if(!RSTn)begincan_rst_temp<=1'b1;rst_flag<=1'b1;endelse if (Count_Sec==26'd100 && rst_flag == 1'b1) begin can_rst_temp<=1'b0;rst_flag<=1'b0;endendalways @ ( posedge CLK or negedge RSTn )beginif(!RSTn)beginrmd_temp<=1'b0;wmd_temp<=1'b0;adr_temp<=8'b0000_0000;data_display_temp<= 8'b1000_1000;data_tx_temp<=8'b0000_0000;endelsebeginif (Count_Sec==TS)beginwmd_temp<=1'b1;adr_temp<=8'b0001_0000;data_tx_temp<=8'b0001_0010;endif (Count_Sec==T1S)rmd_temp<=1'b1;adr_temp<=8'b0001_0000; //读测试寄存器endif (wr_flag==1'b1)beginwmd_temp<=1'b0;endif (rd_flag==1'b1)beginrmd_temp<=1'b0;data_display_temp<= data_rx;endendendreg [25:0]Count_Sec;always @ ( posedge CLK or negedge RSTn ) if( !RSTn )Count_Sec <= 26'd0;else if( Count_Sec == T1S )Count_Sec <= 26'd0;elseCount_Sec <= Count_Sec + 1'b1;assign data_display=data_display_temp; assign rmd=rmd_temp;assign wmd=wmd_temp;assign adr=adr_temp;assign data_tx=data_tx_temp;assign can_rst=can_rst_temp;endmodulecan_op.vmodule can_op (CLK,RSTn,can_rst_in, rmd,wmd,adr,data_tx,can_in,en_out,can_out,read_cmd,data_rx,can_ALE,can_WR,can_RD,can_CS,can_dir,rd_flag,wr_flag,can_rst_out);input CLK;input RSTn; input can_rst_in; input rmd;input wmd; input [7:0]adr; input [7:0]data_tx;input [7:0]can_in;output en_out;output [7:0] can_out;output read_cmd;output [7:0]data_rx;output can_ALE;output can_WR;output can_RD;output can_CS;output can_dir;output rd_flag;output wr_flag;output can_rst_out;reg [7:0] can_out_temp;reg en_out_temp; //这两个变量来组成双向口输出控制reg read_cmd_temp;reg [7:0] data_rx_temp;reg can_ALE_temp;reg can_WR_temp;reg can_RD_temp;reg can_CS_temp;reg can_dir_temp;reg rd_flag_temp;reg wr_flag_temp;reg [3:0] count;always @ ( posedge CLK or negedge RSTn ) beginif ( !RSTn )beginrd_flag_temp<=1'b0;wr_flag_temp<=1'b0;can_WR_temp<=1'b1;can_RD_temp<=1'b1;can_CS_temp<=1'b1;can_dir_temp<=1'b0;data_rx_temp<=8'd221;count<= 4'd0;en_out_temp<=1'b1;can_out_temp<=8'd0;read_cmd_temp<=1'b0;endelsebeginif (rmd)begincase(count)4'd0,4'd1,4'd6: count<= count+1'b1; 4'd2: begincan_out_temp<= adr;en_out_temp<=1'b1;can_ALE_temp<= 1'b1;count<= count+1'b1;end4'd3:begincan_ALE_temp<=1'b0;count<= count+1'b1;end4'd4:begincan_CS_temp<= 1'b0;en_out_temp<=1'b0; end4'd5:begincan_RD_temp<= 1'b0; can_dir_temp=1'b1; count<= count+1'b1; end4'd7:beginread_cmd_temp<=1'b1; count<= count+1'b1; end4'd8:begincount<= count+1'b1; read_cmd_temp<=1'b0; end4'd9:begindata_rx_temp <= can_in; can_RD_temp<= 1'b1; count<= count+1'b1; can_dir_temp <= 1'b0; en_out_temp<=1'b1; end4'd10:begincan_CS_temp<= 1'b1;rd_flag_temp<=1'b1;end4'd11:begincount<=4'd0;rd_flag_temp<=1'b0;endendcaseendif (wmd)begincase(count)4'd0,4'd1: count<= count+1'b1; 4'd2: begincan_out_temp<= adr;en_out_temp<=1'b1;can_ALE_temp<= 1'b1;count<= count+1'b1;end4'd3:begincan_ALE_temp<=1'b0;count<= count+1'b1;end4'd4:begincan_CS_temp<= 1'b0;count<= count+1'b1;endbegincan_WR_temp<= 1'b0; count<= count+1'b1; end4'd6:begincan_out_temp<= data_tx; count<= count+1'b1; end 4'd7:begincount<= count+1'b1; end4'd8:begincan_WR_temp<= 1'b1; count<= count+1'b1; end4'd9:begincan_CS_temp<= 1'b1; can_ALE_temp<=1'b1; count<= count+1'b1;wr_flag_temp<=1'b1; end4'd10:begincount<= 1'b0;wr_flag_temp<=1'b0; end endcaseendendassign data_rx=data_rx_temp;assign can_ALE=can_ALE_temp;assign can_WR=can_WR_temp;assign can_RD=can_RD_temp;assign can_CS=can_CS_temp;assign can_dir=can_dir_temp;assign wr_flag=wr_flag_temp;assign rd_flag=rd_flag_temp;assign can_rst_out=can_rst_in;assign can_out=can_out_temp;assign en_out=en_out_temp;assign read_cmd=read_cmd_temp;endmoduletrans_control.v 这个与下面两个v文件是用来将接收到的数据显示到数码管上module trans_control(CLK,RSTn,data_in,Row_scan,Column_scan);input CLK;input RSTn;input [7:0] data_in;output [7:0] Row_scan;output [1:0] Column_scan;wire [7:0] data1_temp;wire [7:0] data2_temp;trans_module U1(.CLK (CLK),.RSTn (RSTn),.data_in (data_in),.out_data1 (data1_temp), .out_data2 (data2_temp) );scan_module U2(.CLK (CLK),.RSTn (RSTn),.scan_data1 (data1_temp), .scan_data2 (data2_temp), .Row_scan (Row_scan),.Column_scan (Column_scan) );endmoduletrans_module.vmodule trans_module(CLK,RSTn,data_in,out_data1,out_data2);input CLK;input RSTn;input [7:0] data_in;output [7:0] out_data1; output [7:0] out_data2;reg [7:0] out_data1_temp; reg [7:0] out_data2_temp;reg [3:0] temp1;reg [3:0] temp2;parameter _0 = 8'b1100_0000, _1 = 8'b1111_1001, _2 = 8'b1010_0100, _3 = 8'b1011_0000, _4 = 8'b1001_1001, _5 = 8'b1001_0010, _6 = 8'b1000_0010, _7 = 8'b1111_1000, _8 = 8'b1000_0000,_9 = 8'b1001_0000, _A = 8'b1000_1000, _B = 8'b1000_0011, _C = 8'b1100_0110, _D = 8'b1010_0001, _E = 8'b1000_0100, _F = 8'b1000_1110;always @ ( posedge CLK or negedge RSTn )if( !RSTn )beginout_data1_temp<= 8'b1100_0000;out_data2_temp<= 8'b1100_0000;temp1 <= 4'd0;temp2 <= 4'd0;endelsebegintemp1 <= data_in[3:0];temp2 <= data_in[7:4];case(temp1)4'h0 : out_data1_temp <= _0;4'h1 : out_data1_temp <= _1;4'h2 : out_data1_temp <= _2;4'h3 : out_data1_temp <= _3;4'h4 : out_data1_temp <= _4;4'h5 : out_data1_temp <= _5;4'h6 : out_data1_temp <= _6;4'h7 : out_data1_temp <= _7;4'h8 : out_data1_temp <= _8;4'h9 : out_data1_temp <= _9;4'hA : out_data1_temp <= _A;4'hB : out_data1_temp <= _B;4'hC : out_data1_temp <= _C;4'hD : out_data1_temp <= _D;4'hE : out_data1_temp <= _E;4'hF : out_data1_temp <= _F; endcasecase(temp2)4'h0 : out_data2_temp <= _0;4'h1 : out_data2_temp <= _1;4'h2 : out_data2_temp <= _2;4'h3 : out_data2_temp <= _3;4'h4 : out_data2_temp <= _4;4'h5 : out_data2_temp <= _5;4'h6 : out_data2_temp <= _6;4'h7 : out_data2_temp <= _7;4'h8 : out_data2_temp <= _8;4'h9 : out_data2_temp <= _9;4'hA : out_data2_temp <= _A;4'hB : out_data2_temp <= _B;4'hC : out_data2_temp <= _C;4'hD : out_data2_temp <= _D;4'hE : out_data2_temp <= _E;4'hF : out_data2_temp <= _F; endcaseendassign out_data1 = out_data1_temp; assign out_data2 = out_data2_temp;endmodulescan_module.vmodule scan_module(CLK,RSTn,scan_data1,scan_data2,Column_scan,Row_scan);input CLK;input RSTn;input [7:0] scan_data1;input [7:0] scan_data2;output [7:0] Row_scan;output [1:0] Column_scan;parameter T10MS = 19'd499_999;//50M*0.01-1=499_999 reg [18:0]Count1;always @ ( posedge CLK or negedge RSTn )if( !RSTn )Count1 <= 19'd0;else if( Count1 == T10MS )Count1 <= 19'd0;elseCount1 <= Count1 + 19'b1;reg [1:0]t;always @ ( posedge CLK or negedge RSTn )if( !RSTn )t <= 2'd0;else if( t == 2'd2 )t <= 2'd0;else if( Count1 == T10MS )t <= t + 1'b1;reg [7:0] Row_scan_temp;reg [1:0] Column_scan_temp;always @ ( posedge CLK or negedge RSTn )if( !RSTn )beginColumn_scan_temp <= 2'b01;Row_scan_temp <= 8'hd0;endelse if( Count1 == T10MS )case( t )2'd0 : begin Column_scan_temp <= 2'b01; Row_scan_temp <= scan_data1; end 2'd1 : begin Column_scan_temp <= 2'b10; Row_scan_temp <= scan_data2; end endcaseassign Column_scan = Column_scan_temp;assign Row_scan = Row_scan_temp;endmodule代码就这些,还有TCL引脚说明#------------------GLOBAL--------------------#set_global_assignment -name RESERVE_ALL_UNUSED_PINS "AS INPUT TRI-STATED" set_global_assignment -name ENABLE_INIT_DONE_OUTPUT OFF#复位引脚set_location_assignment PIN_M1 -to RSTn#时钟引脚set_location_assignment PIN_R9 -to CLK#数码管对应的引脚set_location_assignment PIN_M8 -to Row_scan[0] set_location_assignment PIN_L7 -to Row_scan[1] set_location_assignment PIN_P9 -to Row_scan[2] set_location_assignment PIN_N9 -to Row_scan[3] set_location_assignment PIN_M9 -to Row_scan[4] set_location_assignment PIN_M10 -to Row_scan[5] set_location_assignment PIN_P11 -to Row_scan[6] set_location_assignment PIN_N11 -to Row_scan[7] set_location_assignment PIN_N8 -to Column_scan[0] set_location_assignment PIN_P8 -to Column_scan[1] #CAN控制信号对应引脚set_location_assignment PIN_R1 -to can_pin[0]set_location_assignment PIN_R3 -to can_pin[1]set_location_assignment PIN_L3 -to can_pin[2]set_location_assignment PIN_K5 -to can_pin[3]set_location_assignment PIN_P3 -to can_pin[4]set_location_assignment PIN_L8 -to can_pin[5]set_location_assignment PIN_N5 -to can_pin[6]set_location_assignment PIN_K6 -to can_pin[7]set_location_assignment PIN_L6 -to can_ALEset_location_assignment PIN_T3 -to can_WRset_location_assignment PIN_L4 -to can_RDset_location_assignment PIN_N3 -to can_CSset_location_assignment PIN_T2 -to can_dirset_location_assignment PIN_P2 -to can_rst_out。
双向既做输入又做输出的FPGA管脚

双向信号既做输出又做输出- FPGA双向电路设计经验[导读] 2)双向信号既做输出又做输出上例是最简单的双向信号应用的特例.在实际的工程中,双向信号既做信号的输入,又做信号的输出,常见的数据总线就是这种操作在工程应用中,双向电路是设计者不得不面对的问题.在实际应用中,数据总线往往是双向的.如何正确处理数据总线是进行时序逻辑电路设计的基础.在程序设计过程中,关键技术在于:实体部分必须对端口属性进行申明,端口属性必须为Inout类型,在构造体需要对输出信号进行有条件的高阻控制.在双向电路的处理问题上,常用的处理方式有两种,在介绍双向电路的处理方式之前,先看看双向电路的基本格式:ENTITY Bidir_pin IS(Bidir : INOUT Std_logic;Oe, Clk, From_core : IN Std_logic;To_core : OUT Std_logic;……END Bidir_pin;ARCHITECTURE Behavior OF Bidir_pin ISBEGINBidir <= From_core WHEN Oe=‘1’ ELSE “ZZZZ”;To_core <= Bidir;___END Behavior;该程序揭示了双向电路的处理技巧,首先在实体部分Bidir属于双向信号,在端口定义时,端口属性为Inout类型,即把Bidir信号作为输入三态输出. 语句“Bidir <= From_core WHEN Oe=‘1’ ELSE “ZZZZ”;”表示Bidir信号三态输出,语句”To_core <= Bidir;”把Bidir信号作为输入信号.由此可见,双向电路在程序设计中,Didir输入当着普通的In类型,而在输出时,需要加一定的控制条件,三态输出.问题的关键在于:如何确定这个条件?1)双向信号作一个信号的输入,作另一信号的输出ENTITY Bidir ISPORT(Bidir : INOUT STD_LOGIC_VECTOR (7 DOWNTO 0);Oe, Clk : IN STD_LOGIC;From_core : IN STD_LOGIC_VECTOR (7 DOWNTO 0);To_core : OUT STD_LOGIC_VECTOR (7 DOWNTO 0));END Bidir;ARCHITECTURE Logic OF Bidir ISSIGNAL A : STD_LOGIC_VECTOR (7 DOWNTO 0);SIGNAL B : STD_LOGIC_VECTOR (7 DOWNTO 0);BEGINPROCESS (Clk)BEGINIF Clk = ''1'' AND Clk''EVENT THENA <= From_core;To_core <= B;END IF;END PROCESS;PROCESS (Oe, Bidir)BEGINIF( Oe = ''0'') THENBidir <= "ZZZZZZZZ";B <= Bidir;ELSEBidir <= A;B <= Bidir;END IF;END PROCESS;END Logic;这种设计方式叫做寄存双向信号的方法.本设计中Bidir为双向信号,From_core为数据输入端,To_core为数据输出端,Oe为三态输出使能,Clk为读写数据的时钟.在程序设计中,需要定义两个Signal A和B信号.A信号用于输入数据From_core的寄存器,B用于输出数据To_core的寄存器.采用寄存器的方法需要设计两个进程,一个进程把A, B信号在时钟的控制下负责端口的输入信号From_core和端口输出信号To_core的连接,这一步实现了寄存双向的功能.另外一个进程则负责信号 A,B和双向口之间的赋值关系.本设计只揭示了简单的双向信号操作方式,即Bidir既可以作为From_core的输出,又可以作为To_core的输入2)双向信号既做输出又做输出上例是最简单的双向信号应用的特例.在实际的工程中,双向信号既做信号的输入,又做信号的输出,常见的数据总线就是这种操作模式.Library IEEE;Use IEEE.STD_LOGIC_1164.All;Entity Dir_data IsPort(Clk : In STD_LOGIC;Rst : In STD_LOGIC;Rw : In STD_LOGIC;Address : In STD_LOGIC_VECTOR(1 Downto 0);Data : Inout STD_LOGIC_VECTOR(7 Downto 0));End Dir_data;Architecture Arc_dir Of Dir_data IsSignal Data_in : STD_LOGIC_VECTOR(7 Downto 0);Signal Data_out: STD_LOGIC_VECTOR(7 Downto 0);Signal Reg_a: STD_LOGIC_VECTOR(7 Downto 0);Signal Reg_b: STD_LOGIC_VECTOR(7 Downto 0);BeginData_in<=Data;D1:Process(Clk,Rst,Rw)BeginIf Rst=''1'' ThenReg_a<= (Others=>''0'');Reg_b<= (Others=>''0'');Elsif Clk''Event And Clk=''1'' Then If Rw=''1'' ThenIf Address="00" ThenReg_a<=Data_in;Elsif Address="01" ThenReg_b<=Data_in;Else Null;End If;Else Null;End If;Else Null;End If;End Process D1;D2:Process(Clk,Rw,Reg_a,Reg_b) BeginIf Clk''Event And Clk=''1'' ThenIf Rw=''0'' ThenIf Address="00" ThenData_out<=Reg_a;Elsif Address="01" ThenData_out<=Reg_b;Else Null;End If;Else Null;End If;Else Null;End If;End Process D2;Data<=Data_out When (Rw=''0'' And Address(1)=''0'') Else(Others=>''Z'');End Arc_dir;在程序设计中,首先需要定义Data_in, Data_out, Reg_a, Reg_b四个Signal,我们把Data_in叫做输入寄存器,它是从双向信号Data接收数据的寄存器,Data_out叫做输出寄存器,它是向双向信号Data发送信号的寄存器,Reg_a和Reg_b叫做操作寄存器,它们是在一定的时序控制下把Data_in数据送给Reg_a,Reg_b,在一定的时序控制下从Reg_a和Reg_b读出数据的.这样的处理方式必须有两个进程,因为在Architecture Arc_dir Of Dir_data Is和Begin之间定义了Data_in, Data_out, Reg_a, Reg_b四个Signal,它在同一进程内不支持既赋值,又调用,也就是说它不支持在D1进程中对信号Reg_a, Reg_b赋值,又在D1进程中又调用Reg_a, Reg_b.首先有语句”Data_in<=Data;”它表示输入寄存器无条件的接收双先信号的数据.在D1进程中,首先在Rst信号有效时,对操作寄存器Reg_a,和Reg_b进行清零操作,然后在时钟(Clk)的控制下,在写 (Rw)信号有效的情况下,对Reg_a, Reg_b寄存器在不同的地址控制下写入不同的Data_in值.在D2进程中,在时钟(Clk)的控制下,在读(Rw)信号有效的时候,把不同地址的 Reg_a, Reg_b的值送进Data_out中.最关键的是最后一句:“Data<=Data_out When (Rw=''0'' And Address(1)=''0'') Else (Others=>''Z'');”它表示双向信号的三态输出,而最最关键的是When后面的条件,如果条件限制太宽,就会错误占用双向信号总线,引起总线的误操作,如果条件限制太窄,输出寄存器的数据就不能够正确的送到数据总线上去,会引起数据的丢失.也就是说,只有正确的限制了When语句后面的条件,才能够把输出寄存器的数据正确地送到数据总线上去.仔细查看此条件,有如下的规律:When语句后的条件是操作寄存器写入输出寄存器的条件的公共条件.比如:Rw=’0’是操作寄存器的数据写入输出寄存器的读使能信号,Address(1)是地址线的公共部分.在实际工程应用中,需要设计者在分配地址总线的时候掌握一定的技巧,尽量从地址的低位到到高位,保证地址总线有更多位的公共部分,比如只对四个寄存器操作时,地址线分配为”100”,” 010”,”110”,”001”是不科学的,而”000”,”001”,”010”和”011”则是理想的.两者不同的是前者地址线没有公共部分,这样的设计无法用When语句对条件进行直接的控制,如果置之不理,由于列举不全,在逻辑综合时,电路会利用器件的乘积项和查找表的资源形成一个Latch, Latch不仅会把电路的时序变得复杂,而且电路存在潜在的危险性.虽然When语句后的条件不能够对条件进行直接的控制,但是可以使用枚举法一一把用到的地址线罗列出来,表示只有在这样的地址线的情况下才会用到数据总线,否则其他状态对数据总线送高阻,表示不占用数据总线.总而言之,双向信号是程序设计中尤其重要的基础,设计者在设计程序的时候,要尤其注意,何时会占用数据总线,何时不占用数据总线.。
verilog模块调用端口对应方式

verilog模块调用端口对应方式Verilog模块是一种重要的硬件描述语言,可以用来描述数字电路和系统。
模块的输入和输出端口是与其他模块或顶层模块进行连接的关键部分。
在Verilog中,模块的端口有三种类型:输入端口、输出端口和双向端口。
不同类型的端口必须按照不同的方式进行调用和连接。
对于输入端口,可以直接在模块实例化时使用“.”符号进行命名。
例如,如果模块的输入端口名称为“in1”和“in2”,则可以使用以下代码进行实例化:module_inst #(.in1(in1_val), .in2(in2_val))instance_name();其中“in1_val”和“in2_val”是输入信号的变量名,这些变量可以来自其他模块或顶层模块。
对于输出端口,可以使用“wire”类型进行声明,然后在模块实例化时将其连接到其他模块或顶层模块。
例如,如果模块的输出端口名称为“out1”和“out2”,则可以使用以下代码进行声明和实例化: module module_name(output wire out1, output wire out2); module_instinstance_name(.out1(out1_val), .out2(out2_val));其中“out1_val”和“out2_val”是输出信号的变量名,这些变量可以用于其他模块或顶层模块。
对于双向端口,可以使用“inout”类型进行声明,并在模块实例化时对其进行连接。
例如,如果模块的双向端口名称为“inout1”和“inout2”,则可以使用以下代码进行声明和实例化:module module_name(inout inout1, inout inout2);module_instinstance_name(.inout1(inout1_val), .inout2(inout2_val));其中“inout1_val”和“inout2_val”是双向信号的变量名,这些变量可以用于其他模块或顶层模块。
verilog input output inout 用法-概述说明以及解释

verilog input output inout 用法-概述说明以及解释1.引言1.1 概述引言是文章开头的一部分,用于介绍文章要讨论的主题。
在这篇文章中,我们将探讨Verilog中的input、output和inout的用法。
Verilog是一种硬件描述语言,被广泛应用于数字电子系统的设计和验证。
在数字电路设计中,输入(input)、输出(output)和双向的输入输出(inout)信号是非常重要的概念。
input关键字用于定义模块的输入信号,它们是外部输入到模块中的信号。
output关键字用于定义模块的输出信号,它们是从模块中输出到外部的信号。
而inout关键字则用于定义双向的输入输出信号,它们既可以从外部输入到模块中,也可以从模块中输出到外部。
在本文的后续部分,我们将详细介绍Verilog中input、output和inout的用法,包括定义变量、使用信号等方面。
通过学习这些内容,读者将能够更好地理解和应用Verilog语言,并能够利用它进行数字电路设计和验证。
接下来我们将进入正文部分,首先介绍Verilog中input的用法。
文章结构部分的内容如下:1.2 文章结构本文将对Verilog中的input、output和inout的用法进行详细介绍。
首先,将在引言部分概述Verilog的基本概念和应用场景。
然后,通过正文部分分别介绍input、output和inout的定义和使用方法。
在每个小节中,将详细说明如何定义相应的变量,并说明如何使用这些变量进行输入、输出和双向信号的传输。
在每个小节结束时,将提供实际示例以帮助读者更好地理解和应用Verilog中的input、output和inout。
在结论部分,将对各个部分进行总结,分别总结input、output和inout的用法,包括定义和使用方法等重要内容。
通过本文的阅读,读者将能够全面了解Verilog中input、output和inout的用法,并能够灵活应用于实际的工程设计中。
Verilog inout 双向口使用和仿真

Verilog inout 双向口使用和仿真芯片外部引脚很多都使用inout类型的,为的是节省管腿。
一般信号线用做总线等双向数据传输的时候就要用到INOUT类型了。
就是一个端口同时做输入和输出。
inout在具体实现上一般用三态门来实现。
三态门的第三个状态就是高阻' Z'。
当inout端口不输出时,将三态门置高阻。
这样信号就不会因为两端同时输出而出错了,更详细的内容可以搜索一下三态门tri-state的资料.1 使用inout类型数据,可以用如下写法:inout data_inout;input data_in;reg data_reg;//data_inout的映象寄存器reg link_data;assign data_inout=link_data?data_reg:1’bz;//link_data控制三态门//对于data_reg,可以通过组合逻辑或者时序逻辑根据data_in对其赋值.通过控制link_data的高低电平,从而设置data_inout是输出数据还是处于高阻态,如果处于高阻态,则此时当作输入端口使用.link_data可以通过相关电路来控制.2 编写测试模块时,对于inout类型的端口,需要定义成wire类型变量,而其它输入端口都定义成reg类型,这两者是有区别的.当上面例子中的data_inout用作输入时,需要赋值给data_inout,其余情况可以断开.此时可以用assign语句实现:assign data_inout=link?data_in_t:1’bz;其中的l ink ,data_in_t是reg类型变量,在测试模块中赋值.另外,可以设置一个输出端口观察data_inout用作输出的情况:Wire data_out;Assign data_out_t=(!link)?data_inout:1’bz;else,in RTLinout use in top module(PAD)dont use inout(tri) in sub module也就是说,在内部模块最好不要出现inout,如果确实需要,那么用两个port实现,到顶层的时候再用三态实现。
【FPGA基础】双向端口inout端口的使用指北

【FPGA基础】双向端⼝inout端⼝的使⽤指北在查阅了各种书和帖⼦之后,总结了以下inout端⼝的使⽤注意事项。
(以下资料来源: 《Xilinx FPGA开发实⽤教程第⼆版》)⾸先是⼀些要先理解的基本概念:0、什么是双向端⼝inout端⼝ 顾名思义,双向端⼝既可以作为输⼊端⼝接收数据,也可以作为输出端⼝发出数据,它对数据的操作是双向的。
双向端⼝在综合时是以三态门的形式存在的,其典型结构如图所⽰。
1、三态门 在Xilinx的《XST User Guide》中给出了三态门的verilog描述1// Tristate Description Using Concurrent Assignment23// Combinatorial Always Block Can be Used too.45module v_three_st_2 (T, I, O);67input T, I;89output O;1011assign O = (~T) ? I: 1’bZ;1213endmodule 上述描述表明,当控制信号T=1时,管⼦被置为⾼阻态,输出O为⾼阻态;当控制信号T=0时,管⼦开通,输出O=输⼊I。
(跟控制信号T是⾼有效或低有效有关)2、⾼阻和悬空 三态门中有⼀个状态是⾼阻。
⾼阻,即可以认为是没有输出,作为输出端⼝⽽⾔,对下级电路没有任何影响。
悬空是针对输⼊端⼝来说的,也就是说没有接输⼊。
这也就意味着,实际上⾼阻和悬空是⼀个状态,在HDL语⾔⾥都表⽰为Z。
也就是说,⼀个输出端⼝在⾼阻态的时候,其状态是由于其相连的其他电路决定的,可以将其看作是输⼊。
双向端⼝⽤作输出时,就和平常⼀样,但双向端⼝作输⼊引脚时需要将此引脚置为⾼阻态,这样其电平就可以由外部输⼊信号决定了(这是⾼阻态的特性)。
在上述基本概念的基础上,讨论三个⽅⾯的问题:⼀、双向端⼝的实现原理 通过上⾯的基本概念应该已经清楚双向端⼝的实现原理了,只要搞清楚上⾯管⼦的开通状态与整个双向端⼝的对外特性之间的关系就⾏了。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
verilog中双向端口inout的使用的心得见许多问这个问题的,总结一下,希望能对大家有点用处,如果有不对的地方,欢迎指出.芯片外部引脚很多都使用inout类型的,为的是节省管腿。
一般信号线用做总线等双向数据传输的时候就要用到INOUT类型了。
就是一个端口同时做输入和输出。
inout在具体实现上一般用三态门来实现。
三态门的第三个状态就是高阻'Z'。
当inout端口不输出时,将三态门置高阻。
这样信号就不会因为两端同时输出而出错了,更详细的内容可以搜索一下三态门tri-state的资料.1 使用inout类型数据,可以用如下写法:inout data_inout;input data_in;reg data_reg;//data_inout的映象寄存器reg link_data;assign data_inout=link_data?data_reg:1’bz;//link_data控制三态门//对于data_reg,可以通过组合逻辑或者时序逻辑根据data_in对其赋值.通过控制link_data 的高低电平,从而设置data_inout是输出数据还是处于高阻态,如果处于高阻态,则此时当作输入端口使用.link_data可以通过相关电路来控制.2 编写测试模块时,对于inout类型的端口,需要定义成wire类型变量,而其它输入端口都定义成reg类型,这两者是有区别的.当上面例子中的data_inout用作输入时,需要赋值给data_inout,其余情况可以断开.此时可以用assign语句实现:assign data_inout=link?data_in_t:1’bz;其中的link ,data_in_t 是reg类型变量,在测试模块中赋值.另外,可以设置一个输出端口观察data_inout用作输出的情况:Wire data_out;Assign data_out_t=(!link)?data_inout:1’bz;else,in RTLinout use in top module(PAD)dont use inout(tri) in sub module也就是说,在内部模块最好不要出现inout,如果确实需要,那么用两个port实现,到顶层的时候再用三态实现。
理由是:在非顶层模块用双向口的话,该双向口必然有它的上层跟它相连。
既然是双向口,则上层至少有一个输入口和一个输出口联到该双向口上,则发生两个内部输出单元连接到一起的情况出现,这样在综合时往往会出错。
芯片外部引脚很多都使用inout类型的,为的是节省管腿。
一般信号线用做总线等双向数据传输的时候就要用到INOUT类型了。
就是一个端口同时做输入和输出。
inout在具体实现上一般用三态门来实现。
三态门的第三个状态就是高阻'Z'。
当inout端口不输出时,将三态门置高阻。
这样信号就不会因为两端同时输出而出错了,更详细的内容可以搜索一下三态门tri-state的资料.1 使用inout类型数据,可以用如下写法:inout data_inout;input data_in;reg data_reg; //data_inout的映象寄存器reg link_data;assign data_inout=link_data?data_reg:1’bz;//link_data控制三态门//对于data_reg,可以通过组合逻辑或者时序逻辑根据data_in对其赋值.通过控制link_data 的高低电平,从而设置data_inout是输出数据还是处于高阻态,如果处于高阻态,则此时当作输入端口使用.link_data可以通过相关电路来控制.2 编写测试模块时,对于inout类型的端口,需要定义成wire类型变量,而其它输入端口都定义成reg类型,这两者是有区别的.当上面例子中的data_inout用作输入时,需要赋值给data_inout,其余情况可以断开.此时可以用assign语句实现:assign data_inout=link?data_in_t:1’bz;其中的link ,data_in_t是reg类型变量,在测试模块中赋值.另外,可以设置一个输出端口观察data_inout用作输出的情况:Assign data_out_t=(!link)?data_inout:1’bz;else,in RTLinout use in top module(PAD)dont use inout(tri) in sub module也就是说,在内部模块最好不要出现inout,如果确实需要,那么用两个port实现,到顶层的时候再用三态实现。
理由是:在非顶层模块用双向口的话,该双向口必然有它的上层跟它相连。
既然是双向口,则上层至少有一个输入口和一个输出口联到该双向口上,则发生两个内部输出单元连接到一起的情况出现,这样在综合时往往会出错。
对双向口,我们可以将其理解为2个分量:一个输入分量,一个输出分量。
另外还需要一个控制信号控制输出分量何时输出。
此时,我们就可以很容易地对双向端口建模。
例子:CODE:module dual_port (....inout_pin,....);inout inout_pin;wire inout_pin;wire input_of_inout;wire output_of_inout;wire out_en;assign input_of_inout = inout_pin;assign inout_pin = out_en ? output_of_inout : 高阻;endmodule可见,此时input_of_inout和output_of_inout就可以当作普通信号使用了。
在仿真的时候,需要注意双向口的处理。
如果是直接与另外一个模块的双向口连接,那么只要保证一个模块在输出的时候,另外一个模块没有输出(处于高阻态)就可以了。
如果是在ModelSim中作为单独的模块仿真,那么在模块输出的时候,不能使用force命令将其设为高阻态,而是使用release命令将总线释放掉很多初学者在写testbench进行仿真和验证的时候,被inout双向口难住了。
仿真器老是提示错误不能进行。
下面是我个人对inout端口写testbench仿真的一些总结,并举例进行说明。
在这里先要说明一下inout口在testbench中要定义为wire型变量。
先假设有一源代码为:module xx(data_inout , ........);........................assign data_inout=(! link)?datareg:1'bz;endmodule方法一:使用相反控制信号inout口,等于两个模块之间用inout双向口互连。
这种方法要注意assign 语句只能放在initial和always块内。
module test();wire data_inout;reg data_reg;reg link;initial begin..........endassign data_inout=link?data_reg:1'bz;endmodule方法二:使用force和release语句,但这种方法不能准确反映双向端口的信号变化,但这种方法可以反在块内。
module test();wire data_inout;reg data_reg;reg link;#xx; //延时force data_inout=1'bx; //强制作为输入端口...............#xx;release data_inout; //释放输入端口endmodule很多读者反映仿真双向端口的时候遇到困难,这里介绍一下双向端口的仿真方法。
一个典型的双向端口如图1所示。
其中inner_port与芯片内部其他逻辑相连,outer_port为芯片外部管脚,out_en用于控制双向端口的方向,out_en为1时,端口为输出方向,out_en为0时,端口为输入方向。
用Verilog语言描述如下:module bidirection_io(inner_port,out_en,outer_port);input out_en;inout[7:0] inner_port;inout[7:0] outer_port;assign outer_port=(out_en==1)?inner_port:8'hzz;assign inner_port=(out_en==0)?outer_port:8'hzz;endmodule用VHDL语言描述双向端口如下:library ieee;use IEEE.STD_LOGIC_1164.ALL;entity bidirection_io isport ( inner_port : inout std_logic_vector(7 downto 0);out_en : in std_logic;outer_port : inout std_logic_vector(7 downto 0) );end bidirection_io;architecture behavioral of bidirection_io isbeginouter_port<=inner_port when out_en='1' else (OTHERS=>'Z');inner_port<=outer_port when out_en='0' else (OTHERS=>'Z');end behavioral;仿真时需要验证双向端口能正确输出数据,以及正确读入数据,因此需要驱动out_en端口,当out_en端口为1时,testbench驱动inner_port端口,然后检查outer_port端口输出的数据是否正确;当out_en端口为0时,testbench驱动outer_port端口,然后检查inner_port端口读入的数据是否正确。
由于inner_port和outer_port端口都是双向端口(在VHDL和Verilog语言中都用inout定义),因此驱动方法与单向端口有所不同。
验证该双向端口的testbench结构如图2所示。
这是一个self-checking testbench,可以自动检查仿真结果是否正确,并在Modelsim控制台上打印出提示信息。
图中Monitor完成信号采样、结果自动比较的功能。
testbench的工作过程为1)out_en=1时,双向端口处于输出状态,testbench给inner_port_tb_reg信号赋值,然后读取outer_port_tb_wire的值,如果两者一致,双向端口工作正常。