Digital System Design For Beginners

The electronic forum deals with the topics related to analog and digital circuits and systems (i.e. ASIC, FPGA, DSPs, Microcontroller, Single/Multi Processors etc) and their programming such as HDL, C/C++, etc.
Forum rules
The electronic forum deals with the topics related to analog and digital circuits and systems (i.e. ASIC, FPGA, DSPs, Microcontroller, Single/Multi Processors, PCBs etc) and their programming such as HDL, C/C++, etc.

Digital System Design For Beginners

Unread postby UCERD.COM » Sat Nov 01, 2014 4:18 pm

Image
A hardware description language (HDL) is a specialized computer language used to program the structure, design and operation of electronic circuits, and most commonly, digital logic circuits.
VHDL and Verilog are now two industry standard hardware description languages.
The complexity of ASIC and FPGA designs has meant an increase in the number of specialist design consultants with specific tools and with their own libraries of macro and mega cells written in either VHDL or Verilog.
As a result, it is important that designers know both VHDL and Verilog and that EDA tools vendors provide tools that provide an environment allowing both
languages to be used in unison. For example, a designer might have a model of a PCI bus interface written in VHDL, but wants to use it in a design with macros written in Verilog.



The structure of the course is categorized into four sections.
Image

  1. Front-End (I/O) Interfaces
    The Front-End (I/O) Interface is used to transfer data to the system. It acts as a window to receive and transfer data.
  2. Data Types
    The data types define how the input can be handled and processes using different variables.
  3. Conditions
    Conditions are applied to the input data types to get appropriate results.
  4. Operations
The operations are applied to the variables at specific time based on input conditions.
Operations and Conditions are mentioned in this post for VHDL and Verilog languages.


Front-End (I/O): C Code : 
Code: Select all
// C Code Style
#include "stdio.h"
   void main()
   {
      char *input_port;
      char *output_port;
      int i;
      // giving address of Input Output Location Normally Address are Defined In GPIO.H Header File of the System
      input_port  = (char *)  0x10000000;
      output_port = (char *)  0x20000000;

      char data_process[16] =  {1,2,3,4,5,6,7,8};
      char output_buffer[16];
      char input_buffer[16];

      for(i=0; i<8; i++)
         {
         input_buffer[i]=input_buffer[i];
         // or
         // input_buffer[i] = *(roccc_register1+x);
         if (input_buffer[i] == i+1)
         {
         output_buffer[i] = input_buffer[i]+data_process[i];
         output_port[i]=output_buffer[i];
         printf("%d \n", output_buffer[i]);
         }
         }
   }

Front-End (I/O): Verilog Code : 
Code: Select all
module front_end_io(
input_port , //  32 bit binary output
output_port , //  32-bit input
clock_bit       //  Clock Signal
);
// The address of input and output ports are also identified in a separate file each system (i.e. FPGA) has different names for different outputs.
//-----------Output Ports---------------
output [31:0] input_port  ;
//-----------Input Ports---------------
input  enable ;
input [31:0] output_port ;
//------------Internal Variables--------

//-------------Code Start-----------------

always @ (posedge clock_bit)
 begin
output_port<=input_port;
  end
end     
endmodule

Data Types: C code : 
Code: Select all
#include "stdio.h"
void main()
{
   int data_32bit;
   char data_8bit;
   char *data_string="UCERD.COM";
   int    one_d_array[16];
   int    two_d_array[16][16];

   data_32bit=1025468; // less than 0xffffffff
   two_d_array[1][5]=1100556;

   printf("Data from 32 Bit Single Int %d \n", data_32bit);
   printf("Data from Two D Array %d \n", two_d_array[1][5]);
   printf("String Value %s \n", data_string);
}

Data Type: Verilog Code : 
Code: Select all
module front_end_io(
input_port , //  32 bit binary output
output_port , //  32-bit input
clock_bit       //  Clock Signal
);
//----------- Input Ports---------------
output [31:0] input_port  ;
//-----------Output Ports---------------
input  enable ;
input [31:0] output_port ;
//------------Internal Variables--------
reg [7:0] memory_one_d [0:255];
//   Here [7:0] is the memory width and [0:255] is the memory depth with the following parameters:
//   Width : 8 bits, little endian
//   Depth : 256, address 0 corresponds to location 0 in the array.
reg address;
//-------------Conditions and Computations Start-----------------
// A number of Conditions can be applied here based on problem solutions.
// These conditions are mentioned in this post
always @ (posedge clock_bit)
begin
memory_one_d[address] = input_port;
address <= address+1;
end
      endmodule

Conditions : 
Code: Select all
module front_end_io(
input_port , //  32 bit binary output
output_port , //  32-bit input
clock_bit       //  Clock Signal
);
//----------- Input Ports---------------
output [31:0] input_port  ;
//-----------Output Ports---------------
input  enable ;
input [31:0] output_port ;
//------------Internal Variables--------
reg [7:0] memory_one_d [0:255];
//   Here [7:0] is the memory width and [0:255] is the memory depth with the following parameters:
//   Width : 8 bits, little endian
//   Depth : 256, address 0 corresponds to location 0 in the array.
reg address;
//-------------Conditions and Computations Start-----------------
// A number of Computation operators can be applied here based on problem solutions.
// These computational operators are mentioned in this post
always @ (posedge clock_bit)
 begin
if(memory_one_d[address] == 0) begin
memory_one_d[address] = input_port;
end
address <= address+1;
case (memory_one_d[address])
32'h00000000 : memory_one_d[address] = input_port;
32'h00000001 : memory_one_d[address] = input_port;
32'h00000002 : memory_one_d[address] = input_port;
end case
end 
endmodule

Operations : 
Code: Select all
module front_end_io(
input_port , //  32 bit binary output
output_port , //  32-bit input
clock_bit       //  Clock Signal
);
//----------- Input Ports---------------
output [31:0] input_port  ;
//-----------Output Ports---------------
input  enable ;
input [31:0] output_port ;
//------------Internal Variables--------
reg [7:0] memory_one_d [0:255];
//   Here [7:0] is the memory width and [0:255] is the memory depth with the following parameters:
//   Width : 8 bits, little endian
//   Depth : 256, address 0 corresponds to location 0 in the array.
reg address;
//-------------Conditions and Computations Start-----------------
always @ (posedge clock_bit)
 begin
memory_one_d[address] = input_port;
address <= address+1;
end     
endmodule

System Examples
Timer : 
Code: Select all
//-----------------------------------------------------
// Design Name : up_counter
// Function    : Up counter
//-----------------------------------------------------
module up_counter    (
out     ,  // Output of the counter
enable  ,  // enable for counter
clk     ,  // clock Input
reset      // reset Input
);
//----------Output Ports--------------
    output [7:0] out;
//------------Input Ports--------------
     input enable, clk, reset;
//------------Internal Variables--------
    reg [7:0] out;
//-------------Code Starts Here-------
always @(posedge clk)
if (reset) begin
  out <= 8'b0 ;
end else if (enable) begin
  out <= out + 1;
end
endmodule

Dual Port Memory : 
Code: Select all
//-----------------------------------------------------
// File Name   : ram_dp_ar_aw.v
// Function    : Asynchronous read write RAM
//-----------------------------------------------------
module ram_dp_ar_aw (
address_0 , // address_0 Input
data_0    , // data_0 bi-directional
cs_0      , // Chip Select
we_0      , // Write Enable/Read Enable
oe_0      , // Output Enable
address_1 , // address_1 Input
data_1    , // data_1 bi-directional
cs_1      , // Chip Select
we_1      , // Write Enable/Read Enable
oe_1        // Output Enable
);

parameter DATA_WIDTH = 8 ;
parameter ADDR_WIDTH = 8 ;
parameter RAM_DEPTH = 1 << ADDR_WIDTH;

//--------------Input Ports-----------------------
input [ADDR_WIDTH-1:0] address_0 ;
input cs_0 ;
input we_0 ;
input oe_0 ;
input [ADDR_WIDTH-1:0] address_1 ;
input cs_1 ;
input we_1 ;
input oe_1 ;

//--------------Inout Ports-----------------------
inout [DATA_WIDTH-1:0] data_0 ;
inout [DATA_WIDTH-1:0] data_1 ;

//--------------Internal variables----------------
reg [DATA_WIDTH-1:0] data_0_out ;
reg [DATA_WIDTH-1:0] data_1_out ;
reg [DATA_WIDTH-1:0] mem [0:RAM_DEPTH-1];

//--------------Code Starts Here------------------
// Memory Write Block
// Write Operation : When we_0 = 1, cs_0 = 1
always @ (address_0 or cs_0 or we_0 or data_0
or address_1 or cs_1 or we_1 or data_1)
begin : MEM_WRITE
  if ( cs_0 && we_0 ) begin
     mem[address_0] <= data_0;
  end else if  (cs_1 && we_1) begin
     mem[address_1] <= data_1;
  end
end

// Tri-State Buffer control
// output : When we_0 = 0, oe_0 = 1, cs_0 = 1
assign data_0 = (cs_0 && oe_0 && !we_0) ? data_0_out : 8'bz;

// Memory Read Block
// Read Operation : When we_0 = 0, oe_0 = 1, cs_0 = 1
always @ (address_0 or cs_0 or we_1 or oe_0)
begin : MEM_READ_0
  if (cs_0 && !we_0 && oe_0) begin
    data_0_out <= mem[address_0];
  end else begin
    data_0_out <= 0;
  end
end

//Second Port of RAM
// Tri-State Buffer control
// output : When we_0 = 0, oe_0 = 1, cs_0 = 1
assign data_1 = (cs_1 && oe_1 && !we_1) ? data_1_out : 8'bz;
// Memory Read Block 1
// Read Operation : When we_1 = 0, oe_1 = 1, cs_1 = 1
always @ (address_1 or cs_1 or we_1 or oe_1)
begin : MEM_READ_1
  if (cs_1 && !we_1 && oe_1) begin
    data_1_out <= mem[address_1];
  end else begin
    data_1_out <= 0;
  end
end
endmodule // End of Module ram_dp_ar_aw

Round Robin arbiter : 
Code: Select all
//----------------------------------------------------
// A four level, round-robin arbiter. This was
//----------------------------------------------------
module arbiter (
  clk,   
  rst,   
  req3,   
  req2,   
  req1,   
  req0,   
  gnt3,   
  gnt2,   
  gnt1,   
  gnt0   
);
// --------------Port Declaration-----------------------
input           clk;   
input           rst;   
input           req3;   
input           req2;   
input           req1;   
input           req0;   
output          gnt3;   
output          gnt2;   
output          gnt1;   
output          gnt0;   

//--------------Internal Registers----------------------
wire    [1:0]   gnt       ;   
wire            comreq    ;
wire            beg       ;
wire   [1:0]    lgnt      ;
wire            lcomreq   ;
reg             lgnt0     ;
reg             lgnt1     ;
reg             lgnt2     ;
reg             lgnt3     ;
reg             lasmask   ;
reg             lmask0    ;
reg             lmask1    ;
reg             ledge     ;

//--------------Code Starts Here-----------------------
always @ (posedge clk)
if (rst) begin
  lgnt0 <= 0;
  lgnt1 <= 0;
  lgnt2 <= 0;
  lgnt3 <= 0;
end else begin                                     
  lgnt0 <=(~lcomreq & ~lmask1 & ~lmask0 & ~req3 & ~req2 & ~req1 & req0)
        | (~lcomreq & ~lmask1 &  lmask0 & ~req3 & ~req2 &  req0)
        | (~lcomreq &  lmask1 & ~lmask0 & ~req3 &  req0)
        | (~lcomreq &  lmask1 &  lmask0 & req0  )
        | ( lcomreq & lgnt0 );
  lgnt1 <=(~lcomreq & ~lmask1 & ~lmask0 &  req1)
        | (~lcomreq & ~lmask1 &  lmask0 & ~req3 & ~req2 &  req1 & ~req0)
        | (~lcomreq &  lmask1 & ~lmask0 & ~req3 &  req1 & ~req0)
        | (~lcomreq &  lmask1 &  lmask0 &  req1 & ~req0)
        | ( lcomreq &  lgnt1);
  lgnt2 <=(~lcomreq & ~lmask1 & ~lmask0 &  req2  & ~req1)
        | (~lcomreq & ~lmask1 &  lmask0 &  req2)
        | (~lcomreq &  lmask1 & ~lmask0 & ~req3 &  req2  & ~req1 & ~req0)
        | (~lcomreq &  lmask1 &  lmask0 &  req2 & ~req1 & ~req0)
        | ( lcomreq &  lgnt2);
  lgnt3 <=(~lcomreq & ~lmask1 & ~lmask0 & req3  & ~req2 & ~req1)
        | (~lcomreq & ~lmask1 &  lmask0 & req3  & ~req2)
        | (~lcomreq &  lmask1 & ~lmask0 & req3)
        | (~lcomreq &  lmask1 &  lmask0 & req3  & ~req2 & ~req1 & ~req0)
        | ( lcomreq & lgnt3);
end

//----------------------------------------------------
// lasmask state machine.
//----------------------------------------------------
assign beg = (req3 | req2 | req1 | req0) & ~lcomreq;
always @ (posedge clk)
begin                                     
  lasmask <= (beg & ~ledge & ~lasmask);
  ledge   <= (beg & ~ledge &  lasmask)
          |  (beg &  ledge & ~lasmask);
end

//----------------------------------------------------
// comreq logic.
//----------------------------------------------------
assign lcomreq = ( req3 & lgnt3 )
                | ( req2 & lgnt2 )
                | ( req1 & lgnt1 )
                | ( req0 & lgnt0 );

//----------------------------------------------------
// Encoder logic.
//----------------------------------------------------
assign  lgnt =  {(lgnt3 | lgnt2),(lgnt3 | lgnt1)};

//----------------------------------------------------
// lmask register.
//----------------------------------------------------
always @ (posedge clk )
if( rst ) begin
  lmask1 <= 0;
  lmask0 <= 0;
end else if(lasmask) begin
  lmask1 <= lgnt[1];
  lmask0 <= lgnt[0];
end else begin
  lmask1 <= lmask1;
  lmask0 <= lmask0;
end

assign comreq = lcomreq;
assign gnt    = lgnt;
//----------------------------------------------------
// Drive the outputs
//----------------------------------------------------
assign gnt3   = lgnt3;
assign gnt2   = lgnt2;
assign gnt1   = lgnt1;
assign gnt0   = lgnt0;
endmodule

RS232 Serial Code : 
Code: Select all
////////////////////////////////////////////////////////
// RS-232 RX and TX module
// (c) fpga4fun.com & KNJN LLC - 2003 to 2013

// The RS-232 settings are fixed
// TX: 8-bit data, 2 stop, no-parity
// RX: 8-bit data, 1 stop, no-parity (the receiver can accept more stop bits of course)

//`define SIMULATION   // in this mode, TX outputs one bit per clock cycle
                       // and RX receives one bit per clock cycle (for fast simulations)

////////////////////////////////////////////////////////
module async_transmitter(
   input clk,
   input TxD_start,
   input [7:0] TxD_data,
   output TxD,
   output TxD_busy
);

// Assert TxD_start for (at least) one clock cycle to start transmission of TxD_data
// TxD_data is latched so that it doesn't have to stay valid while it is being sent

parameter ClkFrequency = 25000000;   // 25MHz
parameter Baud = 115200;

generate
   if(ClkFrequency<Baud*8 && (ClkFrequency % Baud!=0)) ASSERTION_ERROR PARAMETER_OUT_OF_RANGE("Frequency incompatible with requested Baud rate");
endgenerate

////////////////////////////////
`ifdef SIMULATION
wire BitTick = 1'b1;  // output one bit per clock cycle
`else
wire BitTick;
BaudTickGen #(ClkFrequency, Baud) tickgen(.clk(clk), .enable(TxD_busy), .tick(BitTick));
`endif

reg [3:0] TxD_state = 0;
wire TxD_ready = (TxD_state==0);
assign TxD_busy = ~TxD_ready;

reg [7:0] TxD_shift = 0;
always @(posedge clk)
begin
   if(TxD_ready & TxD_start)
      TxD_shift <= TxD_data;
   else
   if(TxD_state[3] & BitTick)
      TxD_shift <= (TxD_shift >> 1);

   case(TxD_state)
      4'b0000: if(TxD_start) TxD_state <= 4'b0100;
      4'b0100: if(BitTick) TxD_state <= 4'b1000;  // start bit
      4'b1000: if(BitTick) TxD_state <= 4'b1001;  // bit 0
      4'b1001: if(BitTick) TxD_state <= 4'b1010;  // bit 1
      4'b1010: if(BitTick) TxD_state <= 4'b1011;  // bit 2
      4'b1011: if(BitTick) TxD_state <= 4'b1100;  // bit 3
      4'b1100: if(BitTick) TxD_state <= 4'b1101;  // bit 4
      4'b1101: if(BitTick) TxD_state <= 4'b1110;  // bit 5
      4'b1110: if(BitTick) TxD_state <= 4'b1111;  // bit 6
      4'b1111: if(BitTick) TxD_state <= 4'b0010;  // bit 7
      4'b0010: if(BitTick) TxD_state <= 4'b0011;  // stop1
      4'b0011: if(BitTick) TxD_state <= 4'b0000;  // stop2
      default: if(BitTick) TxD_state <= 4'b0000;
   endcase
end

assign TxD = (TxD_state<4) | (TxD_state[3] & TxD_shift[0]);  // put together the start, data and stop bits
endmodule


////////////////////////////////////////////////////////
module async_receiver(
   input clk,
   input RxD,
   output reg RxD_data_ready = 0,
   output reg [7:0] RxD_data = 0,  // data received, valid only (for one clock cycle) when RxD_data_ready is asserted

   // We also detect if a gap occurs in the received stream of characters
   // That can be useful if multiple characters are sent in burst
   //  so that multiple characters can be treated as a "packet"
   output RxD_idle,  // asserted when no data has been received for a while
   output reg RxD_endofpacket = 0  // asserted for one clock cycle when a packet has been detected (i.e. RxD_idle is going high)
);

parameter ClkFrequency = 25000000; // 25MHz
parameter Baud = 115200;

parameter Oversampling = 8;  // needs to be a power of 2
// we oversample the RxD line at a fixed rate to capture each RxD data bit at the "right" time
// 8 times oversampling by default, use 16 for higher quality reception

generate
   if(ClkFrequency<Baud*Oversampling) ASSERTION_ERROR PARAMETER_OUT_OF_RANGE("Frequency too low for current Baud rate and oversampling");
   if(Oversampling<8 || ((Oversampling & (Oversampling-1))!=0)) ASSERTION_ERROR PARAMETER_OUT_OF_RANGE("Invalid oversampling value");
endgenerate

////////////////////////////////
reg [3:0] RxD_state = 0;

`ifdef SIMULATION
wire RxD_bit = RxD;
wire sampleNow = 1'b1;  // receive one bit per clock cycle

`else
wire OversamplingTick;
BaudTickGen #(ClkFrequency, Baud, Oversampling) tickgen(.clk(clk), .enable(1'b1), .tick(OversamplingTick));

// synchronize RxD to our clk domain
reg [1:0] RxD_sync = 2'b11;
always @(posedge clk) if(OversamplingTick) RxD_sync <= {RxD_sync[0], RxD};

// and filter it
reg [1:0] Filter_cnt = 2'b11;
reg RxD_bit = 1'b1;

always @(posedge clk)
if(OversamplingTick)
begin
   if(RxD_sync[1]==1'b1 && Filter_cnt!=2'b11) Filter_cnt <= Filter_cnt + 1'd1;
   else
   if(RxD_sync[1]==1'b0 && Filter_cnt!=2'b00) Filter_cnt <= Filter_cnt - 1'd1;

   if(Filter_cnt==2'b11) RxD_bit <= 1'b1;
   else
   if(Filter_cnt==2'b00) RxD_bit <= 1'b0;
end

// and decide when is the good time to sample the RxD line
function integer log2(input integer v); begin log2=0; while(v>>log2) log2=log2+1; end endfunction
localparam l2o = log2(Oversampling);
reg [l2o-2:0] OversamplingCnt = 0;
always @(posedge clk) if(OversamplingTick) OversamplingCnt <= (RxD_state==0) ? 1'd0 : OversamplingCnt + 1'd1;
wire sampleNow = OversamplingTick && (OversamplingCnt==Oversampling/2-1);
`endif

// now we can accumulate the RxD bits in a shift-register
always @(posedge clk)
case(RxD_state)
   4'b0000: if(~RxD_bit) RxD_state <= `ifdef SIMULATION 4'b1000 `else 4'b0001 `endif;  // start bit found?
   4'b0001: if(sampleNow) RxD_state <= 4'b1000;  // sync start bit to sampleNow
   4'b1000: if(sampleNow) RxD_state <= 4'b1001;  // bit 0
   4'b1001: if(sampleNow) RxD_state <= 4'b1010;  // bit 1
   4'b1010: if(sampleNow) RxD_state <= 4'b1011;  // bit 2
   4'b1011: if(sampleNow) RxD_state <= 4'b1100;  // bit 3
   4'b1100: if(sampleNow) RxD_state <= 4'b1101;  // bit 4
   4'b1101: if(sampleNow) RxD_state <= 4'b1110;  // bit 5
   4'b1110: if(sampleNow) RxD_state <= 4'b1111;  // bit 6
   4'b1111: if(sampleNow) RxD_state <= 4'b0010;  // bit 7
   4'b0010: if(sampleNow) RxD_state <= 4'b0000;  // stop bit
   default: RxD_state <= 4'b0000;
endcase

always @(posedge clk)
if(sampleNow && RxD_state[3]) RxD_data <= {RxD_bit, RxD_data[7:1]};

//reg RxD_data_error = 0;
always @(posedge clk)
begin
   RxD_data_ready <= (sampleNow && RxD_state==4'b0010 && RxD_bit);  // make sure a stop bit is received
   //RxD_data_error <= (sampleNow && RxD_state==4'b0010 && ~RxD_bit);  // error if a stop bit is not received
end

reg [l2o+1:0] GapCnt = 0;
always @(posedge clk) if (RxD_state!=0) GapCnt<=0; else if(OversamplingTick & ~GapCnt[log2(Oversampling)+1]) GapCnt <= GapCnt + 1'h1;
assign RxD_idle = GapCnt[l2o+1];
always @(posedge clk) RxD_endofpacket <= OversamplingTick & ~GapCnt[l2o+1] & &GapCnt[l2o:0];
endmodule


////////////////////////////////////////////////////////
// dummy module used to be able to raise an assertion in Verilog
module ASSERTION_ERROR();
endmodule


////////////////////////////////////////////////////////
module BaudTickGen(
   input clk, enable,
   output tick  // generate a tick at the specified baud rate * oversampling
);
parameter ClkFrequency = 25000000;
parameter Baud = 115200;
parameter Oversampling = 1;

function integer log2(input integer v); begin log2=0; while(v>>log2) log2=log2+1; end endfunction
localparam AccWidth = log2(ClkFrequency/Baud)+8;  // +/- 2% max timing error over a byte
reg [AccWidth:0] Acc = 0;
localparam ShiftLimiter = log2(Baud*Oversampling >> (31-AccWidth));  // this makes sure Inc calculation doesn't overflow
localparam Inc = ((Baud*Oversampling << (AccWidth-ShiftLimiter))+(ClkFrequency>>(ShiftLimiter+1)))/(ClkFrequency>>ShiftLimiter);
always @(posedge clk) if(enable) Acc <= Acc[AccWidth-1:0] + Inc[AccWidth:0]; else Acc <= Inc[AccWidth:0];
assign tick = Acc[AccWidth];
endmodule
////////////////////////////////////////////////////////


VHDL and Verilog Operators
Verilog  : Image
VHDL Operators : Image
VHDL Verilog Operations : Image
Arithmetic : Image
Bit Wise Logical : Image
Concatenation : Image
Conditional : Image
Equality : Image
Logical : Image
Reduction : Image
Relation : Image
Shift : Image
Sign : Image
Please Promote Our Work and website through yoursocial and professional network. We would highly appreciate your help.
Find us on FaceBook,Like and Share Please
User avatar
UCERD.COM
Site Admin
Site Admin
 
Posts: 958
Joined: Wed Jun 20, 2012 3:01 pm
Location: Barcelona
Has thanked: 13 times
Been thanked: 14 times
Blog: View Blog (1)

Return to Electronics

Who is online

Users browsing this forum: No registered users and 4 guests

cron