Variable bits output

Status
Not open for further replies.

keyboardcowboy

Member level 3
Joined
Mar 4, 2010
Messages
55
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,286
Visit site
Activity points
1,715
I am trying to implement a sort of serial FIFO (couldn't think of a better name) wherein a 32bit data is pushed in, and variable bits can be taken out. I have implemented it in systemverilog in this way

Code:
reg [1023:0] wk;
bitsleft=0;

if(pushin) begin // pushin is just a variable which is set to 1 when i want to insert data
      for(ix=bitsleft; ix < bitsleft+32; ix=ix+1) 
                       wk[ix]=datain[ix-bitsleft]; // datain is the 32bit that i am pushing in, random.
      bitsleft += 32;

now when i want to extract some bits from the end

Code:
expdata=wk[14:0];
expdata &= ~(16'hffff << reqlen); //reqlen is the length of the bits to be extracted, random from 0 to 15
bitsleft -= reqlen;
wk = wk >> reqlen;

The problem is that I have to implement the same thing in verilog as well, and I am unable to come up with any ideas
 

Attachments

  • New Doc 8_1.jpg
    1.4 MB · Views: 82
Last edited:

Back again with the same subject? I've already made suggestions on your other thread.

What you have written in SV is unlikely to be synthesizable. You are using a lot of stuff that synthesis tools will likely choke on.


1. use a regular FIFO (i.e. block ram fifo/distributed ram fifo)
2. attach control logic on output that reads fifo when data is requested.
3. attach serializer to output of fifo. (shift register and counter, bit width of fifo)
4. request data when serializer will go empty on next clock (loading a new word at the same time the last bit is shifted out)
5. control amount of data serialized by the reqlen control (a counter that controls the shift register and enables counter.)
 
I really didn't understand your previous suggestion (sorry) so i thought i should try what i want in systemverilog and then ask for help trying to convert that to verilog. This posts is much more clear to understand
 

I don't believe that using SV or plain Verilog (or e.g. VHDL) makes a big difference when describing the basic operation of your bitwise FIFO. You need to describe it in a way that can be mapped to hardware.

It's helpful to have an idea of the possible internal structure, e.g. using BRAM or registers only, using a combination of a 32x32 FIFO and a 32-bit shifter or only a 1024x1 FIFO, but that's the second design step, I think. First step is a clear description of interface and internal function.

For the interface, you already specified datain, dataout, "pushin", requestlen. Request input has been omitted from your previous description and should be re-added. ads-ee already mentioned that full/empty signals are required for a practical FIFO, but we can disregard it temporarily.

To work on existing hardware, the design needs a clock. In a usual streaming interface, pushin and requestin would work as clock qualifiers, they are active for one clock cycle to push or pop one data word.

An important point is about timing. What's the maximal input/output word rate? Is it slow enough to shift data 16 or even 32 times between new words or is it so fast that we must expect a new word every clock cycle? The possibility to serialize internal operation (fully or in part) depends on this clock rate/maximum word rate ratio.
 

It depends, if they are serially clocked out of a shift register or copied bit-shifted in one cycle.

Like ads-ee I presume that you want to write synthesizable code, but you didn't mention it explicitely.
 

It depends, if they are serially clocked out of a shift register or copied bit-shifted in one cycle.

Like ads-ee I presume that you want to write synthesizable code, but you didn't mention it explicitely.

they are serially clocked out, not in one cycle, and yes i want to write synthesizable code
 

they are serially clocked out
This eases implementation. You can e.g. split the design into to a FIFO with 32 bit input width/1 bit output width and a shift register that assembles the output bits to a word of the intended variable width.
 

You can e.g. split the design into to a FIFO with 32 bit input width/1 bit output width
Current generation parts and tools only allow a 8-to-1 width reduction so x32 becomes x4. I checked this on K7 and V7 don't know about S6.

That's why I suggested a FIFO (no width conversion) plus a parallel load shift register.
 

I was considering Altera FIFO IP that allows 32:1 mixed width. But your solution is of course a valid option. It's a bit tricky because you must potentially assemble parts of two 32 bit words.

Another option would be a 1024x1 FIFO with a PISO input shifter. Presumed you have at least 32 clocks between two input words.

In any case keyboardcowboy should have some input to start with a real hardware design.

- - - Updated - - -

O.K., it should be sufficient to have a 32-bit output SR that is loaded each time when the last data bit has been shifted out.
 

It's a bit tricky because you must potentially assemble parts of two 32 bit words.
O.K., it should be sufficient to have a 32-bit output SR that is loaded each time when the last data bit has been shifted out.
Never considered it to be all that tricky, been doing it for years on many designs. Serializing the input works well if you don't have bursting data. For bursting input data with a contiuous serial output it has to be done at the output.
 

I have written some code

Code:
module bits(input clk, input rst, input pushin, input [31:0] datain, input reqin, input [3:0] reqlen,
	     output pushout, output [3:0] lenout, output [14:0] dataout);
	     
  reg [14:0] _dataout,_dataout2;	     
  reg [3:0] request[31:0];
  reg [31:0] fifo[31:0];
  reg [4:0] write,read,rwrite,rread;
  wire [4:0] write_inc = write + 1;
  reg _pushout;
  reg _lenout;
  reg shiftop;
  reg [31:0] data;
  reg [4:0] shift_counter,shift_counter2;
  reg load;
  reg [4:0] totalrequests;
  reg firstrun;
  
  assign pushout = _pushout;
  assign lenout = _lenout;
  assign empty = (write == read);
  assign full = (write_inc == read);
  assign dout = fifo[read];

  always @(posedge clk) begin
  _pushout <= #1 0;
  _lenout <=#1 0;
  if (shiftop) begin					// shifter code
    if(request[rread] != 0) begin                        // this checks if a request for 0 bits was made, is it was made then 0 is the output
      if(load) begin                                    // if the request was not zero and the load flag is set 
      data <= fifo[read];                               // load data from fifo, invert the load flag
      load <= 0;
      end else if (shift_counter != request[rread]) begin  //check if amount of shift performed by shifter is less then requested length
      data <= {0,data[31:1]};				  //shifter logic			
      _dataout <= {data[0],_dataout2};                    //shifter logic
      shift_counter <= shift_counter + 1;		  //two counters are used, one is for the required shift, and the other indicates if 32 bits have been shifted in which case another value is loaded from fifo	
      shift_counter2 <= shift_counter2 +1;
      end else begin
      rread<= rread+1;
      totalrequests<= totalrequests -1;
      end
      if (shift_counter2 == 31) begin
      read <= read + 1;
      load <= ~load;
      end
      if (totalrequests ==0) begin
      shiftop <= ~ shiftop;
      end
  end else begin
  firstrun<=#1 0;
  _lenout<= 0;
  _pushout <= 0;
  rread <= rread +1;
  end
  end
  end
  
  always @(posedge clk) begin
    if (rst) begin
      write <= #1 0;
      read <= #1 0;
      rwrite <= #1 0;
      rread <= #1 0;
      shiftop <= #1 0;
      load <= #1 0;
      firstrun <= #1 0;
      totalrequests <= #1 0;
      shift_counter <= #1 0;
      shift_counter2 <= #1 0;
      _dataout <= #1 0;
    end
    if (pushin) begin                         //If a new value is pushed in
      fifo[write] <= #1 datain;               //value "datain" goes into fifo
      write <= #1 write_inc;                  //write pointer is incremented
    end
    
    if (reqin && (!empty)) begin              //if a request for bits arrive, the requests are stored inside a seperate fifo becasue multiple requests come at the same time.
      request[rwrite] <=#1 reqlen;	      //seperate write pointer of requests fifo is incremented
      rwrite <= #1 rwrite + 1;
      
      totalrequests<= totalrequests+1;        //variable totalrequests is incremented, this contains the total requests made.
      if (firstrun == 0) begin		      //firstrun flag indicates that the shifter is being run for the first time
      load <=#1 1;			      //load flag is raised which causes the shiter to load data from fifo
      shiftop <= #1 1;
      end else begin
      load <= #1 0;
      shiftop <= #1 0;
      end
      
      
    end
    
    
    
    
  end
endmodule

It is not working. Can you provide some sample code
 

I don't have vacancy to review the code now. Two general comments:
- there's no use of timing staments in synthesizable code
- where's the test bench that shows the design is "not working"?
 

Test Bench
Code:
`timescale 1ns/10ps

module test;

reg clk,rst,pushin;
reg [31:0] datain;
reg reqin;
reg [3:0] reqlen;
wire pushout;
wire [3:0] lenout;
wire [14:0] dataout;

reg pushout0;
reg [3:0] lenout0;
reg [14:0] dataout0;
reg draining;
reg filling;
int bitsleft;

reg running=0;

reg debug=0;

default clocking tclk @(posedge(clk)) ;
  
endclocking

typedef struct {
	reg[3:0] len;
	reg[14:0] data;
} sexp;

sexp fexp[$];

sexp exp;

task death(input string s);
  begin
    $display();
    $display();
    $display(s);
    $display();
    $display();
    $error(":-( :-( :-( ended with error");
    $display();
    $display();
    $finish;
  end
endtask

class rt;

rand reg Xpushin;
rand reg [31:0] Xdatain;
rand reg Xreqin;
rand reg [3:0] Xreqlen;
rand reg [8:0] Xdrain;
rand reg [8:0] Xfill;

reg [14:0] expdata;

reg [31*32-1:0] wk;

constraint c1 {
  Xpushin dist {
    0 := 20-19*filling,
    1 := 3  
  };
}
constraint c2 {
  Xreqlen <= bitsleft;
}


function new();
  begin
    bitsleft=0;
    wk=0;
    draining=0;
    filling=0;
  end
endfunction


task apply;
integer ix;
sexp se;
  begin
    if( bitsleft > (30*32-1) ) begin
      Xpushin=0;
    end
    if(bitsleft < Xreqlen) begin
      Xreqin=0;
    end
    if(filling) begin
      if(bitsleft < 29*32) Xreqin=0; else filling=0;
    end else if(draining) begin
      if(bitsleft > 0) Xpushin=0;
      if(bitsleft == 0) draining=0;
    end else begin
      if( Xdrain == 123 ) draining=1;
      else if(Xfill == 123) filling=1;
    end
    ##1 #1;
    pushin = Xpushin;
    datain = Xdatain;
    reqin = Xreqin;
    reqlen = Xreqlen;
    if(Xpushin) begin
      for(ix=bitsleft; ix < bitsleft+32; ix=ix+1) wk[ix]=Xdatain[ix-bitsleft];
//      wk[bitsleft+31:bitsleft]=Xdatain;
      bitsleft += 32;
      if(debug) $display("Pushing %08h",Xdatain);
    end
    if(Xreqin) begin
      expdata=wk[14:0];
      expdata &= ~(16'hffff << Xreqlen);
      se.len = Xreqlen;
      se.data=expdata;
      if(debug) $display("requesting %d bits, expecting %04h",Xreqlen,expdata);
      fexp.push_back(se);
      bitsleft -= Xreqlen;
      wk = wk >> Xreqlen;
    end
  end
endtask

task alldone;
begin
  if(fexp.size() > 0) begin
    death("You did not push out the last request within 20 clocks");
    $finish;
  end
end
endtask

endclass

rt t=new();

bits b(clk,rst,pushin, datain, reqin, reqlen, pushout, lenout, dataout);

initial begin
clk=0;
forever #5.0 clk=~clk;
end

initial begin
  #1;
  if(debug) begin
    $dumpfile("bits.vcd");
    $dumpvars(9,test);
  end
end

initial begin
rst=0;
pushin=0;
datain=0;
reqin=0;
reqlen=0;
##1 #1;
rst=1;
##5 #1;
rst=0;
##1 ;
running=1;
repeat(100) begin
  t.randomize;
  t.apply;
end
##1 #1;
pushin=0;
reqin=0;
##20 #1;
t.alldone;
$display();
$display();
$display("all done with a smile");
$display();
$display();
$finish();
end

always @(posedge(clk)) begin
  if(running) begin
    pushout0=pushout;
    lenout0=lenout;
    dataout0=dataout;
    #0.02;
    if(pushout0 !== pushout) death("No hold time on pushout");
    if(lenout0 !== lenout) death("No hold time on lenout");
    if(dataout0 !== dataout) death("no hold time on dataout");
    if(pushout !== 0 && pushout !==1) death("X or Z on pushout");
    if(pushout) begin
      if(fexp.size() < 1) death("You pushed, and I am not expecting anything");
      exp = fexp.pop_front();
      if(lenout !== exp.len) begin
        $display();
        $display();
        $display("Length error --- Recv %h Exp %h",lenout,exp.len);
        death("length received in error");
      end
      if(dataout !== exp.data) begin
        $display();
        $display();
        $display("Data error --- Recv %h Exp %h",dataout,exp.data);
        death("Data received error");
      end
    end
  end
end



endmodule

I have fixed some parts, and now it works, but not completely, the problem I am facing now is that sometimes i get an extra bit and sometimes a bit less

Fixed Code

Code:
module bits(input clk, input rst, input pushin, input [31:0] datain, input reqin, input [3:0] reqlen,
	     output pushout, output [3:0] lenout, output [14:0] dataout);
 
  reg [5:0] totalrequests;
  reg [3:0] _lenout;
  reg _pushout;
  reg [31:0] fifo[31:0];
  reg [3:0] lenfifo[95:0];
  reg [4:0] write,read;
  reg [5:0] lread,lwrite;
  wire [4:0] write_inc = write + 1;
  wire [5:0] lwrite_inc = lwrite + 1;
  reg firstrun;
  reg [31:0] temp;
  reg [14:0] sout,shftout;
  reg load;
  reg [3:0] count1;
  reg [4:0] count2;
  reg enable,enable2;
  reg shiftenable;
  reg [14:0] _dataout;
  reg [14:0] souttemp;
  integer ii;
  reg[3:0] wi;
  reg once;
  
  assign dataout = _dataout;
  assign pushout = _pushout;
  assign lenout = _lenout;
  assign empty = (write == read);
  assign full = (write_inc == read);
  assign dout = fifo[read];
  

always @(posedge clk) begin
  //_pushout <= #1 0;
  //_lenout <=#1 0;

 

 if(shiftenable) begin
 if(lenfifo[lread] != 0) begin
  if(load)begin
    temp <= #1 fifo[read];
    load <= #1 0;
    enable <= #1 1;
    end else if(enable) begin
    temp <= #1 {0,temp[31:1]};
    count1 <= #1 count1 +1;
    count2 <= #1 count2 +1;
    sout <= #1 {sout,temp[0]};
    if (count1 == lenfifo[lread]) begin
    for (ii=0; ii <= 14; ii=ii+1) souttemp[ii]=sout[wi-ii];
    _dataout <= #1 souttemp;
    if(lenfifo[lread] < 14) begin
    _dataout <= #1 souttemp >> (14-lenfifo[lread]);
    end
    
    _lenout <= #1 count1;
    _pushout <=#1 1;
    //enable <= #1 0;
    totalrequests <= totalrequests -1;
    lread <= lread +1;
    count1 <= #1 0;
    sout<= #1 0;
    if (totalrequests == 0) begin 
    shiftenable <= 0;
    
    end
    end else _pushout <= #1 0;
    end 
  if (count2 == 31) begin
  load <= #1 1;
  end
  end else if(lenfifo[lread] != 0)  begin 
  lread <= #1 lread +1;
  _pushout <= #1 1;
  _lenout <= #1 0;
  _dataout <= #1 0;
  end else _pushout <= #1 0;
  end 

end 
  always @(posedge clk) begin
    if (rst) begin
      once <= #1 1;
      shftout <= #1 0;
      write <= #1 0;
      read <= #1 0;
      lwrite <= #1 0;
      lread <= #1 0;
      load <= #1 0;
      count1 <= #1 0;
      count2 <= #1 0;
      firstrun <= #1 1;
      enable2 <= #1 1;
      totalrequests <= #1 0;
      _pushout <= #1 0;
      wi <= #1 14;
    end
    if (pushin) begin
      fifo[write] <= #1 datain;
      write <= #1 write_inc;
    end
    
    

    if (reqin== 1 && empty==1) begin
    _pushout <= #1 1;
    _lenout <= #1 0;
    _dataout <= #1 0;
    end else if(firstrun) _pushout <= #1 0;
    
    if (reqin && !(empty)) begin
      //if(reqlen != 0) begin
      lenfifo[lwrite] <= #1 reqlen;
      lwrite <= #1 lwrite_inc;
      totalrequests <= #1 totalrequests +1;
      if (firstrun) begin
      load <= #1 1;
      shiftenable <= #1 1;
      firstrun <=#1 0;
      end
      //read <= read + 1;
      
      //end
    end
  end
endmodule
 

Status
Not open for further replies.
Cookies are required to use this site. You must accept them to continue using the site. Learn more…