-2

I am a beginner when it comes to verilog or any HDL. While working on a project I found a post where someone uses concatenation in both sides of the non-blocking assignment.

Like so:

{tf0, th0,tl0} <= {1'b0, th0, tl0}+ 1'b1;

I don't really understand how this works.

This is part of an implementation of a timer module in a Intel 8051 micro-controller implementation . This is the whole relevant code part for this problem:


module oc8051_tc (clk, rst, 
            data_in,
            wr_addr,
        wr, wr_bit,
        ie0, ie1,
        tr0, tr1,
        t0, t1,
            tf0, tf1,
        pres_ow,
//registers
        tmod, tl0, th0, tl1, th1);

input [7:0]  wr_addr,
             data_in;
input        clk,
             rst,
         wr,
         wr_bit,
         ie0,
         ie1,
         tr0,
         tr1,
         t0,
         t1,
         pres_ow;
output [7:0] tmod,
             tl0,
         th0,
         tl1,
         th1;
output       tf0,
             tf1;


reg [7:0] tmod, tl0, th0, tl1, th1;
reg tf0, tf1_0, tf1_1, t0_buff, t1_buff;

wire tc0_add, tc1_add;

assign tc0_add = (tr0 & (!tmod[3] | !ie0) & ((!tmod[2] & pres_ow) | (tmod[2] & !t0 & t0_buff)));
assign tc1_add = (tr1 & (!tmod[7] | !ie1) & ((!tmod[6] & pres_ow) | (tmod[6] & !t1 & t1_buff)));
assign tf1= tf1_0 | tf1_1;

//
// read or write from one of the addresses in tmod
//
always @(posedge clk or posedge rst)
begin
 if (rst) begin
   tmod <=#1 `OC8051_RST_TMOD;
 end else if ((wr) & !(wr_bit) & (wr_addr==`OC8051_SFR_TMOD))
    tmod <= #1 data_in;
end

//
// TIMER COUNTER 0
//
always @(posedge clk or posedge rst)
begin
 if (rst) begin
   tl0 <=#1 `OC8051_RST_TL0;
   th0 <=#1 `OC8051_RST_TH0;
   tf0 <= #1 1'b0;
   tf1_0 <= #1 1'b0;
 end else if ((wr) & !(wr_bit) & (wr_addr==`OC8051_SFR_TL0)) begin
   tl0 <= #1 data_in;
   tf0 <= #1 1'b0;
   tf1_0 <= #1 1'b0;
 end else if ((wr) & !(wr_bit) & (wr_addr==`OC8051_SFR_TH0)) begin
   th0 <= #1 data_in;
   tf0 <= #1 1'b0;
   tf1_0 <= #1 1'b0;
 end else begin
     case (tmod[1:0]) /* synopsys full_case parallel_case */
      `OC8051_MODE0: begin                       // mode 0
        tf1_0 <= #1 1'b0;
        if (tc0_add)
          {tf0, th0,tl0[4:0]} <= #1 {1'b0, th0, tl0[4:0]}+ 1'b1;
      end
      `OC8051_MODE1: begin                       // mode 1
        tf1_0 <= #1 1'b0;
        if (tc0_add)
          {tf0, th0,tl0} <= #1 {1'b0, th0, tl0}+ 1'b1;
      end

      `OC8051_MODE2: begin                       // mode 2
        tf1_0 <= #1 1'b0;
        if (tc0_add) begin
      if (tl0 == 8'b1111_1111) begin
            tf0 <=#1 1'b1;
            tl0 <=#1 th0;
           end
          else begin
            tl0 <=#1 tl0 + 8'h1;
            tf0 <= #1 1'b0;
          end
    end
      end
      `OC8051_MODE3: begin                       // mode 3

     if (tc0_add)
       {tf0, tl0} <= #1 {1'b0, tl0} +1'b1;

         if (tr1 & pres_ow)
       {tf1_0, th0} <= #1 {1'b0, th0} +1'b1;

      end
/*      default:begin
        tf0 <= #1 1'b0;
        tf1_0 <= #1 1'b0;
      end*/
    endcase
 end
end

toolic
  • 57,801
  • 17
  • 75
  • 117
Gundi
  • 1

1 Answers1

-1

A concatenation on the RHS of the assignment is a packing operation. It is going to take its 3 operands and pack them into a 17-bit value. The first operand (1'b0) becomes the most significant bit(MSB) and the last operand (tl0) becomes the least significant bits(LSBs). That value then gets incremented by one, and the result gets scheduled for assignment to the LHS.

A concatenation on the LHS of the assignment is an unpacking operation. The first operand (tf0) gets the MSB of the result and the last operand (tl0) gets the LSBs.

Note that a packing concatenation may contain read-only literals and constants, but an unpacking concatenation must be all writable variables.

dave_59
  • 39,096
  • 3
  • 24
  • 63