2012年10月31日 星期三

P11-62 CRC 電路


源自於http://ghsi.de/CRC/
Online CRC Calculation
Enter your CRC polynomial as bit sequence ("100110001") here:
This gives the following CRC polynomial (press RETURN to update):

P(x) = x16+ x12+ x5+ x0
Enter your message as sequence of hex bytes here. Don't care about whitespaces since they will be ignored.
Press RETURN or the Calculate button below to see the CRC checksum here:

$ 510(hexadecimal)
% 0000010100010000(binary)
! 1296(decimal)


A typical hardware implementation (LFSR - Linear Feedback Shift Register) is shown here:

Dr.-Ing. K. Gorontzi, 2005
The input bits are shifted into the very left XOR gate. The MSB is shifted in first.
Each flipflop represents a single CRC output bit. The leftmost flipflop is the MSB of the CRC. This implementation doesn't need to augment the serial input message with zeros.
Note that in our case the flipflops are cleared to zeros at the beginning of each CRC calculation.



A simple VERILOG implementation of the above polynom is shown here. You can directly copy the source snippet to your code (distributed under LGPL):

// ==========================================================================
// CRC Generation Unit - Linear Feedback Shift Register implementation
// (c) Kay Gorontzi, GHSi.de, distributed under the terms of LGPL
// ==========================================================================
module CRC_Unit(BITVAL, BITSTRB, CLEAR, CRC);
   input        BITVAL;                            // Next input bit
   input        BITSTRB;                           // Current bit valid (Clock)
   input        CLEAR;                             // Init CRC value
   output [15:0] CRC;                               // Current output CRC value

   reg    [15:0] CRC;                               // We need output registers
   wire         inv;
   
   assign inv = BITVAL ^ CRC[15];                   // XOR required?
   
   always @(posedge BITSTRB or posedge CLEAR) begin
      if (CLEAR) begin
         CRC = 0;                                  // Init before calculation
         end
      else begin
         CRC[15] = CRC[14];
         CRC[14] = CRC[13];
         CRC[13] = CRC[12];
         CRC[12] = CRC[11] ^ inv;
         CRC[11] = CRC[10];
         CRC[10] = CRC[9];
         CRC[9] = CRC[8];
         CRC[8] = CRC[7];
         CRC[7] = CRC[6];
         CRC[6] = CRC[5];
         CRC[5] = CRC[4] ^ inv;
         CRC[4] = CRC[3];
         CRC[3] = CRC[2];
         CRC[2] = CRC[1];
         CRC[1] = CRC[0];
         CRC[0] = inv;
         end
      end
   
endmodule



源自於
http://www.asic-world.com/examples/verilog/serial_crc.html
Serial CRC


Below code is 16-bit CRC-CCITT implementation, with following features
space.gif
  • Width = 16 bits
  • Truncated polynomial = 0x1021
  • Initial value = 0xFFFF
  • Input data is NOT reflected
  • Output CRC is NOT reflected
  • No XOR is performed on the output CRC
space.gif

  1 //-----------------------------------------------------
  2 // Design Name : serial_crc_ccitt
  3 // File Name   : serial_crc.v
  4 // Function    : CCITT Serial CRC
  5 // Coder       : Deepak Kumar Tala
  6 //-----------------------------------------------------
  7 module serial_crc_ccitt (
  8 clk     ,
  9 reset   ,
 10 enable  ,
 11 init    , 
 12 data_in , 
 13 crc_out
 14 );
 15 //-----------Input Ports---------------
 16 input clk     ;
 17 input reset   ;
 18 input enable  ;
 19 input init    ;
 20 input data_in ;
 21 //-----------Output Ports---------------
 22 output [15:0] crc_out;
 23 //------------Internal Variables--------
 24 reg   [15:0] lfsr;
 25 //-------------Code Start-----------------
 26 assign crc_out = lfsr;
 27 // Logic to CRC Calculation
 28 always @ (posedge clk)
 29 if (reset) begin
 30   lfsr <= 16'hFFFF;
 31 end else if (enable) begin
 32   if (init) begin
 33     lfsr <=  16'hFFFF;
 34   end else begin
 35     lfsr[0]  <= data_in ^ lfsr[15];
 36     lfsr[1]  <= lfsr[0];
 37     lfsr[2]  <= lfsr[1];
 38     lfsr[3]  <= lfsr[2];
 39     lfsr[4]  <= lfsr[3];
 40     lfsr[5]  <= lfsr[4] ^ data_in ^ lfsr[15];
 41     lfsr[6]  <= lfsr[5];
 42     lfsr[7]  <= lfsr[6];
 43     lfsr[8]  <= lfsr[7];
 44     lfsr[9]  <= lfsr[8];
 45     lfsr[10] <= lfsr[9];
 46     lfsr[11] <= lfsr[10];
 47     lfsr[12] <= lfsr[11] ^ data_in ^ lfsr[15];
 48     lfsr[13] <= lfsr[12];
 49     lfsr[14] <= lfsr[13];
 50     lfsr[15] <= lfsr[14];
 51   end
 52 end 
 53 
 54 endmodule
You could download file serial_crc.v here

2012年10月30日 星期二

P11-20 4bit X 4bitt booth multiplierbit4 為 正負號

P11-20  4bit X 4bitt booth multiplier

bit4 為 正負號   
 (+7) * (+7) = +49    (31H)   最大正數
 ~(-7) * (+7) = -49    (CFH)  最大負數 
 CFH = -49D   2'S complement






源自於
http://www.cis.nctu.edu.tw/~info27/ch4/multiple.htm#Booth演算法
Booth演算法
處理有號數字的最簡單方法是:首先將乘數與被乘數轉換成正數然後記住原來的正負號。而一種較簡潔的有號數字相乘的解決方法是Booth's algorithm。其構想來自下面觀察:只要具有加法與減法的能力,計算乘積應該有很多方法。假設我們想要計算(2)10X(6)10或(0010)2X(0110)2
          (0010)2
  X       (0110)2
______________________
+          0000     移位(乘數是0)
+         0010      相加(乘數是1)
+        0010       相加(乘數是1)
+       0000        移位(乘數是0)
______________________
       00001100

Booth觀察到:能夠執行加法或減法的ALU,可以用一種以上的方法得到相同的結果。如
(6)10=(-2)10+(8)10或(0110)2=(-0010)2+(1000)2
當第一次遇到1時,可以用減法取代一串的1,當遇到最後一個1後面的0時,再加上被乘數,例如:
          (0010)2
  X       (0110)2
______________________
+          0000     移位(乘數是0)
+         0010      相減(乘數的第一個1)
+        0000       移位(字串1的中間)
+       0010        相加(上一步驟是最後一個1)
______________________
       00001100
Booth為了求快而發明了這種解決方法,他將一群的位元分成以1作為開始,中間,結尾:
如果我們局限在只看兩個位元,根據兩個位元的值,我們得到符合前面圖中的狀況:
現行位元現行位元之右邊位元解釋範例
10一群1的開始000011110002
11一群1的中間000011110002
01一群1的結束000011110002
00一群0的中間000011110002
Booth演算法一次看乘數的兩個位元
  • 依照目前與先前位元的不同,執行下面工作:
    • 00: 字串0的中間部份,不需要算術運算
    • 01: 字串1的結尾,所以將被乘數加到乘積的左半部
    • 10: 字串1的開端,所以從乘積的左半部減去被乘數
    • 11: 字串1的中間部份,所以不需要算術運算
  • 如同前面的演算法,將乘積暫存器右移1位元
在準備好開始之前,將虛構位元0放在最右邊位元的右邊。將乘積右移時,因為我們是處理有號數字,必須保留中間過程結果的正負符號,所以當乘積向右移時,擴展其符號。因此第一次重覆迴圈的乘積暫存器右移1位元時,將(111001110)2轉換成(111100111)2,不是(011100111)2,這種移位稱為算術右移(arithemetic right shift),有別於邏輯右移。
例如:以Booth演算法執行負數乘法 (0010)2X(1101)2=(11111010)2或2X(-3)=-6
重覆次數步驟被乘數暫存器乘積暫存器
0起始值00100000 1101 0
110=>乘積暫存器=乘積暫存器-被乘數暫存器00101110 1101 0
乘積暫存器右移00101111 0110 1
201=>乘積暫存器=乘積暫存器+被乘數暫存器00100001 0110 1
乘積暫存器右移00101111 1011 0
310=>乘積暫存器=乘積暫存器-被乘數暫存器00101110 1011 0
乘積暫存器右移00101111 0101 1
411=>不做任何事00101111 0101 1
乘積暫存器右移00101111 1010 1

module booth4x4(SW, LEDR, LEDG , CLOCK_50 ,KEY ,HEX0 ,HEX1 ,HEX2,HEX3 );

input  [17:0] SW; // toggle switches
input  [7:0] KEY;     // Push bottom
input  CLOCK_50; //Clock 27MHz , 50Mhz
output [17:0] LEDR; // red  LEDS   
  output [8:0] LEDG; // green LEDs
    
    output [6:0] HEX0,HEX1,HEX2,HEX3; //7-segment display
    
  
//set original program input , output 
  
// M,x,y);
//input [3:0] x,y;
//output [7:0] M;
reg [5:0]psum1,psum2;
reg[5:0]temp;
reg [7:0] M;
wire [3:0]x,y;
wire [7:0] segout0;   //HEX 0
    wire [7:0] segout1;   //HEX 1
assign x=SW[3:0];
assign y=SW[7:4];
assign LEDR[7:0]=SW[7:0];
//======================================
always@(x or y)
begin
case(y[1:0])
2'b00:
psum1=6'b000000;
2'b01:
psum1={x[3],x[3],x[3:0]};
2'b10:
begin
temp=~{x[3],x[3:0],1'b0}+1'b1;
if(x==4'b1000)
psum1={1'b0,x[3:0],1'b0};
else
psum1=temp;
end
2'b11:
begin
temp=~{x[3],x[3],x[3:0]}+1'b1;
if(x==4'b1000)
psum1={2'b00,x[3:0]};
else
psum1=temp;
end
default:
psum1=6'b000000;
endcase

//======================================
case(y[3:1])
3'b000:
           psum2=6'b000000;
3'b001:
           psum2={x[3],x[3],x[3:0]};
3'b010:
           psum2={x[3],x[3],x[3:0]};
3'b011:
           psum2={x[3],x[3:0],1'b0};
3'b100:
           begin
            temp=~{x[3],x[3:0],1'b0}+1'b1;
            if(x==4'b1000)
              psum2={1'b0,x[3:0],1'b0};
            else
              psum2=temp;
            end
3'b101:
           begin
            temp=~{x[3],x[3],x[3:0]}+1'b1;
            if(x==4'b1000)
              psum2={2'b00,x[3:0]};
            else
              psum2=temp;
           end
3'b110:
           begin
            temp=~{x[3],x[3],x[3:0]}+1'b1;
            if(x==4'b1000)
              psum2={2'b00,x[3:0]};
            else
              psum2=temp;
           end
3'b111:
           psum2=6'b000000;
default:
           psum2=6'b000000;
    endcase

M[1:0]=psum1[1:0];
M[7:2]={psum1[5],psum1[5],psum1[5:2]}+psum2;
end
    _7seg UUT0(.hex((M[3:0])),
               .seg(segout0));           
               
    _7seg UUT1(.hex((M[7:4])),
               .seg(segout1));
               
               
    assign HEX0=segout0[6:0];
    assign HEX1=segout1[6:0];    

endmodule



//-----------------------------------------
//Common-cathod seven segment display
//using case.....endcase statement
//Filename : sevenseg_case.v
//----------------------------------------- 
module _7seg(hex , seg);
    input  [3:0] hex;
    output [7:0] seg;
    reg    [7:0] seg;
    
        

// segment encoding
//      0
//     ---  
//  5 |   | 1
//     ---   <- 6
//  4 |   | 2
//     ---
//      3
always @(hex)
begin
case (hex)
       // Dot point is always disable
       4'b0001 : seg = 8'b11111001;   //1 = F9H
       4'b0010 : seg = 8'b10100100;   //2 = A4H
       4'b0011 : seg = 8'b10110000;   //3 = B0H
       4'b0100 : seg = 8'b10011001;   //4 = 99H
       4'b0101 : seg = 8'b10010010;   //5 = 92H
       4'b0110 : seg = 8'b10000010;   //6 = 82H
       4'b0111 : seg = 8'b11111000;   //7 = F8H
       4'b1000 : seg = 8'b10000000;   //8 = 80H
       4'b1001 : seg = 8'b10010000;   //9 = 90H
       4'b1010 : seg = 8'b10001000;   //A = 88H
       4'b1011 : seg = 8'b10000011;   //b = 83H
       4'b1100 : seg = 8'b11000110;   //C = C6H
       4'b1101 : seg = 8'b10100001;   //d = A1H
       4'b1110 : seg = 8'b10000110;   //E = 86H
       4'b1111 : seg = 8'b10001110;   //F = 8EH
       default : seg = 8'b11000000;   //0 = C0H
     endcase
   end
   
endmodule



適用於 DE2-70 P11-2 BCD Counter 0000-9999 BCD Counter

P11-2 0000-9999 BCD Counter 

module BCD9999(SW, LEDR, LEDG , CLOCK_50 ,KEY ,HEX0 ,HEX1 ,HEX2,HEX3 );

input  [17:0] SW; // toggle switches

input  [7:0] KEY;     // Push bottom
input  CLOCK_50; //Clock 27MHz , 50Mhz

output [17:0] LEDR; // red  LEDS   
  output [8:0] LEDG; // green LEDs
    
    output [6:0] HEX0,HEX1,HEX2,HEX3; //7-segment display
    
  
//set original program input , output 
  
//(clr,clk,q);
//input clr,clk;
//output [15:0]q;
wire clr,clk;
reg [15:0]q;
    wire HZ_1; //1HZ Clock

assign clr=KEY[0];
assign clk=CLOCK_50;


    wire [7:0] segout0;   //HEX 0
    wire [7:0] segout1;   //HEX 1
    wire [7:0] segout2;   //HEX 1
    wire [7:0] segout3;   //HEX 1
    


     //module _1HZ (CLK, RSTn, LED_Out);

     
     _1HZ UUT01 (.CLK(clk),
.RSTn(clr),
.LED_Out(HZ_1));

     

always @(posedge HZ_1 or negedge clr) 

begin
if(!clr) q[15:0]=0;
else if(q[15:0]==16'H9999) q[15:0]=0;
else if(q[11:0]==12'H999) q[15:0]=q[15:0]+12'H667;
else if(q[ 7:0]== 8'H99) q[15:0]=q[15:0]+8'H67;
else if(q[ 3:0]== 4'H9) q[15:0]=q[15:0]+4'H7;
else q[15:0]=q[15:0]+1; 
end


_7seg UUT0(.hex((q[3:0])),
               .seg(segout0));
               
    _7seg UUT1(.hex((q[7:4])),
               .seg(segout1));           
               
    _7seg UUT2(.hex((q[11:8])),
               .seg(segout2));
               
    _7seg UUT3(.hex((q[15:12])),
               .seg(segout3));   
               
    assign HEX0=segout0[6:0];
    assign HEX1=segout1[6:0];     
    assign HEX2=segout2[6:0];
    assign HEX3=segout3[6:0];   
                             

endmodule

//=======================================
//=======================================
//Clock input 50MHZ
//=======================================
 module _1HZ (CLK, RSTn, LED_Out);

    input CLK;
    input RSTn;
    output LED_Out;
    
    /*************************************/
    
    parameter T1S = 26'd50_000_000;  //50MHZ 
    
    /*************************************/
    
    reg [25:0]Count1;
    
    always @ ( posedge CLK or negedge RSTn )
    begin
     if( !RSTn ) 
         Count1 <= 26'd0;
     else if( Count1 == T1S )
         Count1 <= 26'd0;
     else
         Count1 <= Count1 + 1'b1;
end        
 /*************************************/
reg rLED_Out;
 always @ ( posedge CLK or negedge RSTn )
    begin
        if( !RSTn ) 
            rLED_Out <= 1'b0;
        else if( Count1 >= 26'd0 && Count1 < 26'd25_000_000 )
          //0.5sec ON , o.5sec OFF
            rLED_Out <= 1'b1;
        else 
            rLED_Out <= 1'b0;
     end  
          
     /***************************************/
     
     assign LED_Out = rLED_Out;
     
     /***************************************/
              
    
endmodule


//-----------------------------------------
//Common-cathod seven segment display
//using case.....endcase statement
//Filename : sevenseg_case.v
//----------------------------------------- 
module _7seg(hex , seg);
    input  [3:0] hex;
    output [7:0] seg;
    reg    [7:0] seg;
    
        

// segment encoding
//      0
//     ---  
//  5 |   | 1
//     ---   <- 6
//  4 |   | 2
//     ---
//      3
always @(hex)
begin
case (hex)
       // Dot point is always disable
       4'b0001 : seg = 8'b11111001;   //1 = F9H
       4'b0010 : seg = 8'b10100100;   //2 = A4H
       4'b0011 : seg = 8'b10110000;   //3 = B0H
       4'b0100 : seg = 8'b10011001;   //4 = 99H
       4'b0101 : seg = 8'b10010010;   //5 = 92H
       4'b0110 : seg = 8'b10000010;   //6 = 82H
       4'b0111 : seg = 8'b11111000;   //7 = F8H
       4'b1000 : seg = 8'b10000000;   //8 = 80H
       4'b1001 : seg = 8'b10010000;   //9 = 90H
       4'b1010 : seg = 8'b10001000;   //A = 88H
       4'b1011 : seg = 8'b10000011;   //b = 83H
       4'b1100 : seg = 8'b11000110;   //C = C6H
       4'b1101 : seg = 8'b10100001;   //d = A1H
       4'b1110 : seg = 8'b10000110;   //E = 86H
       4'b1111 : seg = 8'b10001110;   //F = 8EH
       default : seg = 8'b11000000;   //0 = C0H
     endcase
   end
   
endmodule

2012年10月29日 星期一

P7-13 以8bit Odd Parity 產生16bit Odd Parity Checker 適用於DE2-70


P7-13 以8bit Odd Parity 產生16bit Odd Parity Checker 
適用於DE2-70




//-----------------------------------------------
// 16-bit odd-parity generator using two 8-bit 
// odd-parity generators
// Filename : odd_parity_16.v
//-----------------------------------------------
module odd_parity (SW, LEDR, LEDG , CLOCK_27 ,KEY ,HEX0 ,HEX1 ,HEX2,HEX3 );

 input  [17:0] SW;   // toggle switches
 input  [7:0] KEY;       // Push bottom
 input  CLOCK_27;   //Clock 27MHz , 50Mhz

 output [17:0] LEDR;   // red  LEDS   
   output [8:0] LEDG;   // green LEDs
    
    output [6:0] HEX0,HEX1,HEX2,HEX3; //7-segment display
    
  
 //set original program input , output 

 //(Din, Pout);
 //input [15:0] Din;
 //output Pout;
  
 wire [15:0] Din;
 reg [7:0] High_byte; // Hight byte of input data
 reg [7:0] Low_byte;  // Low byte of input data
 reg High, Low;       // Parities of high and low byte
 reg Pout;         // Parity output


 assign Din=SW[15:0];
 assign LEDR[15:0]=SW[15:0];


  always @(Din)
    begin
      High_byte = Din[15:8];
    Low_byte = Din[7:0];
odd8(High_byte, High);
odd8(Low_byte, Low);
Pout = High ~^ Low; // Bitwise xnor
    end




  assign LEDG[0]=Pout; 
  
//================================== 
task odd8;
  input [7:0] I;
  output odd8;
  begin 
   odd8 = ~^ I; // reduction xnor operation
  end
endtask



endmodule



Task And Function



源自於 http://www.asic-world.com/verilog/task_func1.html

../images/main/bullet_green_ball.gifTask
Tasks are used in all programming languages, generally known as procedures or subroutines. The lines of code are enclosed in task....end task brackets. Data is passed to the task, the processing done, and the result returned. They have to be specifically called, with data ins and outs, rather than just wired in to the general netlist. Included in the main body of code, they can be called many times, reducing code repetition.
space.gif
  • tasks are defined in the module in which they are used. It is possible to define a task in a separate file and use the compile directive 'include to include the task in the file which instantiates the task.
  • tasks can include timing delays, like posedge, negedge, # delay and wait.
  • tasks can have any number of inputs and outputs.
  • The variables declared within the task are local to that task. The order of declaration within the task defines how the variables passed to the task by the caller are used.
  • tasks can take, drive and source global variables, when no local variables are used. When local variables are used, basically output is assigned only at the end of task execution.
  • tasks can call another task or function.
  • tasks can be used for modeling both combinational and sequential logic.
  • A task must be specifically called with a statement, it cannot be used within an expression as a function can.
space.gif
../images/main/bulllet_4dots_orange.gifSyntax
space.gif
  • A task begins with keyword task and ends with keyword endtask
  • Inputs and outputs are declared after the keyword task.
  • Local variables are declared after input and output declaration.
space.gif
../images/main/bulllet_4dots_orange.gifExample - Simple Task
space.gif

  1 module simple_task();
  2 
  3 task convert;
  4 input [7:0] temp_in;
  5 output [7:0] temp_out;
  6 begin
  7   temp_out = (9/5) *( temp_in + 32)
  8 end
  9 endtask
 10 
 11 endmodule
You could download file simple_task.v here
space.gif
../images/main/bulllet_4dots_orange.gifExample - Task using Global Variables
space.gif

  1 module task_global();
  2 
  3 reg [7:0] temp_out;
  4 reg [7:0] temp_in;
  5 
  6 task convert;
  7 begin
  8   temp_out = (9/5) *( temp_in + 32);
  9 end
 10 endtask
 11 
 12 endmodule
You could download file task_global.v here
space.gif
space.gif
../images/main/bulllet_4dots_orange.gifCalling a Task
Let's assume that the task in example 1 is stored in a file called mytask.v. Advantage of coding a task in a separate file, is that it can be used in multiple modules.
space.gif

  1 module  task_calling (temp_a, temp_b, temp_c, temp_d);
  2 input [7:0] temp_a, temp_c;
  3 output [7:0] temp_b, temp_d;
  4 reg [7:0] temp_b, temp_d;
  5 `include "mytask.v"
  6     
  7 always @ (temp_a)
  8 begin 
  9   convert (temp_a, temp_b);
 10 end  
 11 
 12 always @ (temp_c)
 13 begin 
 14   convert (temp_c, temp_d);
 15 end  
 16     
 17 endmodule
You could download file task_calling.v here
space.gif
../images/main/bulllet_4dots_orange.gifExample - CPU Write / Read Task
Below is the waveform used for writing into memory and reading from memory. We make the assumption that there is a need to use this interface from multiple agents. So we write the read/write as tasks.
space.gif
../images/verilog/task_cpu_wr_rd.gif
space.gif

  1 module bus_wr_rd_task();
  2 
  3 reg clk,rd,wr,ce;
  4 reg [7:0]  addr,data_wr,data_rd;
  5 reg [7:0]  read_data;
  6 
  7 initial begin
  8   clk = 0;
  9   read_data = 0;
 10   rd = 0;
 11   wr = 0;
 12   ce = 0;
 13   addr = 0;
 14   data_wr = 0;
 15   data_rd = 0;
 16   // Call the write and read tasks here
 17    #1  cpu_write(8'h11,8'hAA);
 18    #1  cpu_read(8'h11,read_data);
 19    #1  cpu_write(8'h12,8'hAB);
 20    #1  cpu_read(8'h12,read_data);
 21    #1  cpu_write(8'h13,8'h0A);
 22    #1  cpu_read(8'h13,read_data);
 23    #100  $finish;
 24 end
 25 // Clock Generator
 26 always
 27    #1  clk = ~clk;
 28 // CPU Read Task
 29 task cpu_read;
 30   input [7:0]  address;
 31   output [7:0] data;
 32   begin
 33     $display ("%g CPU Read  task with address : %h", $time, address);
 34     $display ("%g  -> Driving CE, RD and ADDRESS on to bus", $time);
 35     @ (posedge clk);
 36     addr = address;
 37     ce = 1;
 38     rd = 1;
 39     @ (negedge clk);
 40     data = data_rd;
 41     @ (posedge clk);
 42     addr = 0;
 43     ce = 0;
 44     rd = 0;
 45     $display ("%g CPU Read  data              : %h", $time, data);
 46     $display ("======================");
 47   end
 48 endtask
 49 // CU Write Task
 50 task cpu_write;
 51   input [7:0]  address;
 52   input [7:0] data;
 53   begin
 54     $display ("%g CPU Write task with address : %h Data : %h", 
 55       $time, address,data);
 56     $display ("%g  -> Driving CE, WR, WR data and ADDRESS on to bus", 
 57       $time);
 58     @ (posedge clk);
 59     addr = address;
 60     ce = 1;
 61     wr = 1;
 62     data_wr = data;
 63     @ (posedge clk);
 64     addr = 0;
 65     ce = 0;
 66     wr = 0;
 67     $display ("======================");
 68   end
 69 endtask
 70 
 71 // Memory model for checking tasks
 72 reg [7:0] mem [0:255];
 73 
 74 always @ (addr or ce or rd or wr or data_wr)
 75 if (ce) begin
 76   if (wr) begin
 77     mem[addr] = data_wr;
 78   end
 79   if (rd) begin
 80     data_rd = mem[addr];
 81   end
 82 end
 83 
 84 endmodule
You could download file bus_wr_rd_task.v here
space.gif
Simulation Output
space.gif
 1 CPU Write task with address : 11 Data : aa
 1  -> Driving CE, WR, WR data and ADDRESS on to bus
 ======================
 4 CPU Read  task with address : 11
 4  -> Driving CE, RD and ADDRESS on to bus
 7 CPU Read  data              : aa
 ======================
 8 CPU Write task with address : 12 Data : ab
 8  -> Driving CE, WR, WR data and ADDRESS on to bus
 ======================
 12 CPU Read  task with address : 12
 12  -> Driving CE, RD and ADDRESS on to bus
 15 CPU Read  data              : ab
 ======================
 16 CPU Write task with address : 13 Data : 0a
 16  -> Driving CE, WR, WR data and ADDRESS on to bus
 ======================
 20 CPU Read  task with address : 13
 20  -> Driving CE, RD and ADDRESS on to bus
 23 CPU Read  data              : 0a
 ======================
space.gif
../images/main/bullet_green_ball.gifFunction
A Verilog HDL function is the same as a task, with very little differences, like function cannot drive more than one output, can not contain delays.
  • functions are defined in the module in which they are used. It is possible to define functions in separate files and use compile directive 'include to include the function in the file which instantiates the task.
  • functions can not include timing delays, like posedge, negedge, # delay, which means that functions should be executed in "zero" time delay.
  • functions can have any number of inputs but only one output.
  • The variables declared within the function are local to that function. The order of declaration within the function defines how the variables passed to the function by the caller are used.
  • functions can take, drive, and source global variables, when no local variables are used. When local variables are used, basically output is assigned only at the end of function execution.
  • functions can be used for modeling combinational logic.
  • functions can call other functions, but can not call tasks.
space.gif
../images/main/bulllet_4dots_orange.gifSyntax
space.gif
  • A function begins with keyword function and ends with keyword endfunction
  • inputs are declared after the keyword function.
space.gif
../images/main/bulllet_4dots_orange.gifExample - Simple Function
space.gif

  1 module simple_function();
  2 
  3 function  myfunction;
  4 input a, b, c, d;
  5 begin
  6   myfunction = ((a+b) + (c-d));
  7 end
  8 endfunction
  9 
 10 endmodule
You could download file simple_function.v here
space.gif
../images/main/bulllet_4dots_orange.gifExample - Calling a Function
space.gif

  1 module  function_calling(a, b, c, d, e, f);
  2                    
  3 input a, b, c, d, e ;
  4 output f;
  5 wire f;
  6 `include "myfunction.v"
  7     
  8 assign f =  (myfunction (a,b,c,d)) ? e :0;
  9     
 10 endmodule
You could download file function_calling.v here

Wokwi ESP32 Simulator : ESP32 + NTP+MQTT+ Node-RED Dashboard

Wokwi ESP32 Simulator : ESP32 + NTP+MQTT+ Node-RED Dashboard  Wokwi ESP32程式 // Learn about the ESP32 WiFi simulation in // https://docs.wokw...