Parallel in Serial out 
Author Message
 Parallel in Serial out

Hi All,

I am hoping someone can help me out. I need to implement a memory element
the accepts a 72 bit input (9 bytes) and outputs 1 byte at a time each time
an input enable goes high. I would like a Verilog behavioural model and it
has to be synthesizeable. I had a design that simulated right but when I
synthesized it there we errors because more then one always block is
assigning a given variable.

This is what I had before:

module mem9_1 ( iCLK,
  iRST,
  iWR,
  iRD,
  iDIN,
  oDOUT,
  oDONE,
  oEMPTY );

input  iCLK;
input  iRST;
input  iWR;
input  iRD;
input [71:0] iDIN;

output [7:0] oDOUT;
output  oDONE;
output  oEMPTY;

wire  iCLK;
wire  iRST;
wire  iWR;
wire  iRD;

wire [7:0] mem8 = iDIN[71:64];
wire [7:0] mem7 = iDIN[63:56];
wire [7:0] mem6 = iDIN[55:48];
wire [7:0] mem5 = iDIN[47:40];
wire [7:0] mem4 = iDIN[39:32];
wire [7:0] mem3 = iDIN[31:24];
wire [7:0] mem2 = iDIN[23:16];
wire [7:0] mem1 = iDIN[15:8];
wire [7:0] mem0 = iDIN[7:0];

reg [7:0] memory [8:0];
reg [7:0] oDOUT;
reg  oDONE;
reg  oEMPTY;
reg [3:0] pointer;


begin
    if (!iRST)
    begin
         if (iRD)
         begin
            oDONE = 1'b1;
          end

      else
      begin
           oDONE = 1'b0;
      end
end

else
begin
      oDONE = 1'b0;
      pointer = 4'h0;
      oDOUT = 8'h00;
      oEMPTY = 1'b1;

      memory[8] = 8'h00;
      memory[7] = 8'h00;
      memory[6] = 8'h00;
      memory[5] = 8'h00;
      memory[4] = 8'h00;
      memory[3] = 8'h00;
      memory[2] = 8'h00;
      memory[1] = 8'h00;
      memory[0] = 8'h00;
     end
end


begin : write_block
     memory[8] = mem8;
     memory[7] = mem7;
     memory[6] = mem6;
     memory[5] = mem5;
     memory[4] = mem4;
     memory[3] = mem3;
     memory[2] = mem2;
     memory[1] = mem1;
     memory[0] = mem0;
     oEMPTY = 1'b0;
end


begin : read_block
     oDOUT = memory[pointer];
     oDONE = 1'b1;
     pointer = pointer + 1;
     if (pointer == 9)
     begin
          pointer = 4'h0;
          oEMPTY = 1'b1;
    end
end
endmodule

Please point out anything else that could be done more efficiently or
whatever.

Cheers,
Tim



Sat, 09 Feb 2002 03:00:00 GMT  
 Parallel in Serial out
Hi Tim,

I think your problems arise because many signals in your module are edge
triggered - but off more than one edge.

For example your memory elements are reset to 0 on the clock negative edge
as befits a synchronously reset register file, but are updated to new values
on the edge of iWR as befits an asynchronous memory. Your oEMPTY signal is
reset to 0 on the clock edge, cleared on a write by the edge of iWR and set
on the final read by the edge of iRD.

My suggestion would be to use only the clock edge and design a fully
synchronous module. The behaviour would change slightly, ie new data would
get written to the memory on the clock edge during which iWR was asserted
rather than on the trailing edge of iWR, and new output would be asserted
after the clock edge during which iRD was asserted rather than on the
trailing edge of iRD.

I would be happy to rework your design to reflect this if that is of interest
to you.

Regards, Robert.

Quote:

> Hi All,

> I am hoping someone can help me out. I need to implement a memory element
> the accepts a 72 bit input (9 bytes) and outputs 1 byte at a time each time
> an input enable goes high. I would like a Verilog behavioural model and it
> has to be synthesizeable. I had a design that simulated right but when I
> synthesized it there we errors because more then one always block is
> assigning a given variable.

> This is what I had before:

> module mem9_1 ( iCLK,
>   iRST,
>   iWR,
>   iRD,
>   iDIN,
>   oDOUT,
>   oDONE,
>   oEMPTY );

> input  iCLK;
> input  iRST;
> input  iWR;
> input  iRD;
> input [71:0] iDIN;

> output [7:0] oDOUT;
> output  oDONE;
> output  oEMPTY;

> wire  iCLK;
> wire  iRST;
> wire  iWR;
> wire  iRD;

> wire [7:0] mem8 = iDIN[71:64];
> wire [7:0] mem7 = iDIN[63:56];
> wire [7:0] mem6 = iDIN[55:48];
> wire [7:0] mem5 = iDIN[47:40];
> wire [7:0] mem4 = iDIN[39:32];
> wire [7:0] mem3 = iDIN[31:24];
> wire [7:0] mem2 = iDIN[23:16];
> wire [7:0] mem1 = iDIN[15:8];
> wire [7:0] mem0 = iDIN[7:0];

> reg [7:0] memory [8:0];
> reg [7:0] oDOUT;
> reg  oDONE;
> reg  oEMPTY;
> reg [3:0] pointer;


> begin
>     if (!iRST)
>     begin
>          if (iRD)
>          begin
>             oDONE = 1'b1;
>           end

>       else
>       begin
>            oDONE = 1'b0;
>       end
> end

> else
> begin
>       oDONE = 1'b0;
>       pointer = 4'h0;
>       oDOUT = 8'h00;
>       oEMPTY = 1'b1;

>       memory[8] = 8'h00;
>       memory[7] = 8'h00;
>       memory[6] = 8'h00;
>       memory[5] = 8'h00;
>       memory[4] = 8'h00;
>       memory[3] = 8'h00;
>       memory[2] = 8'h00;
>       memory[1] = 8'h00;
>       memory[0] = 8'h00;
>      end
> end


> begin : write_block
>      memory[8] = mem8;
>      memory[7] = mem7;
>      memory[6] = mem6;
>      memory[5] = mem5;
>      memory[4] = mem4;
>      memory[3] = mem3;
>      memory[2] = mem2;
>      memory[1] = mem1;
>      memory[0] = mem0;
>      oEMPTY = 1'b0;
> end


> begin : read_block
>      oDOUT = memory[pointer];
>      oDONE = 1'b1;
>      pointer = pointer + 1;
>      if (pointer == 9)
>      begin
>           pointer = 4'h0;
>           oEMPTY = 1'b1;
>     end
> end
> endmodule

> Please point out anything else that could be done more efficiently or
> whatever.

> Cheers,
> Tim

--
=========================================================================
Robert R Fairlie - IC Design, Motorola, Scotland, Tel.  - +44 1355 356039
=========================================================================


Sat, 09 Feb 2002 03:00:00 GMT  
 Parallel in Serial out
Hi Robert,

Yes I would be very interested in this. After I posted my problem I looked
at what I had and changed the code to operate off of one single clock but I
am still having problems. For some guidelines I need the module to perform
the following:
- the write operation should write all 9 bytes in one clock cycle (not very
critical but would help)
- a byte should only be outputted when the RD line is inserted
- only one byte should be outputted at one time

Thanks for you help and I look forward to seeing what you come up with.

Cheers,
Tim
[snip]

Quote:

>My suggestion would be to use only the clock edge and design a fully
>synchronous module. The behaviour would change slightly, ie new data would
>get written to the memory on the clock edge during which iWR was asserted
>rather than on the trailing edge of iWR, and new output would be asserted
>after the clock edge during which iRD was asserted rather than on the
>trailing edge of iRD.

>I would be happy to rework your design to reflect this if that is of
interest
>to you.

>Regards, Robert.



Sat, 09 Feb 2002 03:00:00 GMT  
 Parallel in Serial out
Tim,

This may not be perfect, but it should get you pretty close.

module mem9_1 ( iCLK,
  iRST,
  iWR,
  iRD,
  iDIN,
  oDOUT,
  oDONE,
  oEMPTY );

input  iCLK;
input  iRST;
input  iWR;
input  iRD;
input [71:0] iDIN;

output [7:0] oDOUT;
output  oDONE;
output  oEMPTY;

reg [7:0] oDOUT;
reg [71:0] mem;
reg [3:0] pointer;
reg oDONE;


   if (~iRST)
      mem <= 72'h000000000000000000;
   else if (iWR)
      mem <= iDIN;


   if (~iRST) begin
      pointer <= 4'h0;
      oDONE <= 1'b1;
   end
   else if ((iWR)  || (pointer == 4'h8)) begin
      pointer <= 4'h0;
      oDONE <= iWR ? 1'b0 : 1'b1;
   end
   else if (iRD) begin
      pointer <= pointer + 1'b1;
      oDONE <= 1'b0;
   end

assign oEMPTY = oDONE;


   if (~iRD)
      oDOUT <= 8'hzz;
   else
      case (pointer)
         4'h0: oDOUT <= mem[7:0];
         4'h1: oDOUT <= mem[15:8];
         4'h2: oDOUT <= mem[23:16];
         4'h3: oDOUT <= mem[31:24];
         4'h4: oDOUT <= mem[39:32];
         4'h5: oDOUT <= mem[47:40];
         4'h6: oDOUT <= mem[55:48];
         4'h7: oDOUT <= mem[63:56];
         4'h8: oDOUT <= mem[71:64];
         default: oDOUT <= 8'h00;
      endcase

--

Motorola WSSG  M/S: CH275   phone: (480)814-4920            
1300 N. Alma School Rd.     fax:   (480)814-3107
Chandler, AZ 85224



Sat, 09 Feb 2002 03:00:00 GMT  
 Parallel in Serial out
Tim,

I was beaten to the draw !

That's what comes of living in a significantly different time zone.

Anyway, here's my attempt, for what it's worth...

module mem9_1 ( iCLK,
                iRST,
                iWR,
                iRD,
                iDIN,
                oDOUT,
                oDONE,
                oEMPTY );

   input        iCLK;
   input        iRST;
   input        iWR;
   input        iRD;
   input [71:0] iDIN;

   output [7:0] oDOUT;
   output       oDONE;
   output       oEMPTY;
   reg [7:0]    oDOUT;
   reg          oDONE;
   reg          oEMPTY;

   reg [71:0]   mem;
   reg [3:0]    pointer;

   // =======================================================================
   // oDOUT
   // =====
   // The output of the memory has valid data when there is an active read
   // strobe asserted, otherwise it is high impedance.

     if (~iRD)
       oDOUT <= 8'hzz;
     else
       case (pointer)
         4'h0: oDOUT <= mem[7:0];
         4'h1: oDOUT <= mem[15:8];
         4'h2: oDOUT <= mem[23:16];
         4'h3: oDOUT <= mem[31:24];
         4'h4: oDOUT <= mem[39:32];
         4'h5: oDOUT <= mem[47:40];
         4'h6: oDOUT <= mem[55:48];
         4'h7: oDOUT <= mem[63:56];
         4'h8: oDOUT <= mem[71:64];
         default: oDOUT <= 8'h00;
       endcase // case(pointer)
   // =======================================================================

   // =======================================================================
   // oDONE
   // =====
   // This output asserts in the clock cycle immediately following a read access

     if (iRST)
       oDONE <= 1'b0;
     else if (iRD)
       oDONE <= 1'b1;
     else
       oDONE <= 1'b0;
   // =======================================================================

   // =======================================================================
   // oEMPTY
   // ======
   // This indicates that the last of the current memory contents has just been
   // read, so it gets set on a read when the pointer points to the last entry,
   // and cleared again on a write. If a write happens simultaneously with the
   // final read (this is cool in a synchronous module) then the oEMPTY flag
   // remains clear.

     if (iRST)
       oEMPTY <= 1'b1;
     else if (iWR)
       oEMPTY <= 1'b0;
     else if (iRD == 1'b1 && pointer[3:0] == 4'b1000)
       oEMPTY <= 1'b1;
   // =======================================================================

   // =======================================================================
   // pointer
   // =======
   // This points to the memory byte that will appear on the output the next
   // time iRD is asserted, after which it will be incremented. It wraps back
   // from 8 to 0.

     if (iRST)
       pointer[3:0] <= 4'b0000;
     else if (iRD)
       begin
          if (pointer[3:0] == 4'b1000)
            pointer[3:0] <= 4'b0000;
          else
            pointer[3:0] <= pointer[3:0] + 1;
       end // if (iRD)
   // =======================================================================

   // =======================================================================
   // mem
   // ===
   // The actual memory.

     if (iRST)
       mem[71:0] <= 72'b0;
     else if (iWR)
       mem[71:0] <= iDIN[71:0];
   // =======================================================================

   // That's all, Folks!!!

endmodule // mem9_1

...plus a wee test bench...

module test_mem;

   reg [71:0] iDIN;
   reg        iCLK,
              iRST,
              iRD,
              iWR;
   wire [7:0] oDOUT;
   wire       oDONE,
              oEMPTY;

mem9_1 mem9_1 ( iCLK,
                iRST,
                iWR,
                iRD,
                iDIN,
                oDOUT,
                oDONE,
                oEMPTY );

   initial
     begin
        $signalscan;
        $recordvars;
     end

   initial
     begin
        iCLK <= 1'b1;
        iRST <= 1'b1;
        iWR  <= 1'b0;
        iRD  <= 1'b0;
     end

   always
     #5 iCLK <= ~iCLK;

   initial
     begin
        #15 iRST = 1'b0;
        #10 iWR  = 1'b1;
        #0  iDIN = 72'h0123456789ABCDEF01;   // some random rubbish!
        #10 iWR  = 1'b0;
        #0  iRD  = 1'b1;
        #80 iWR  = 1'b1;
        #0  iDIN = 72'hfedcba9876543210fe;
        #10 iWR  = 1'b0;
        #90 iRD  = 1'b0;
        #20 $stop;
     end // initial begin

endmodule // test_mem

Note that my effort uses active high synchronous reset, whilst Mark's uses
active low asynchronous reset. That's just a matter of preference.

Regards, Robert.

Quote:

> Tim,

> This may not be perfect, but it should get you pretty close.

> module mem9_1 ( iCLK,
>   iRST,
>   iWR,
>   iRD,
>   iDIN,
>   oDOUT,
>   oDONE,
>   oEMPTY );

> input  iCLK;
> input  iRST;
> input  iWR;
> input  iRD;
> input [71:0] iDIN;

> output [7:0] oDOUT;
> output  oDONE;
> output  oEMPTY;

> reg [7:0] oDOUT;
> reg [71:0] mem;
> reg [3:0] pointer;
> reg oDONE;


>    if (~iRST)
>       mem <= 72'h000000000000000000;
>    else if (iWR)
>       mem <= iDIN;


>    if (~iRST) begin
>       pointer <= 4'h0;
>       oDONE <= 1'b1;
>    end
>    else if ((iWR)  || (pointer == 4'h8)) begin
>       pointer <= 4'h0;
>       oDONE <= iWR ? 1'b0 : 1'b1;
>    end
>    else if (iRD) begin
>       pointer <= pointer + 1'b1;
>       oDONE <= 1'b0;
>    end

> assign oEMPTY = oDONE;


>    if (~iRD)
>       oDOUT <= 8'hzz;
>    else
>       case (pointer)
>          4'h0: oDOUT <= mem[7:0];
>          4'h1: oDOUT <= mem[15:8];
>          4'h2: oDOUT <= mem[23:16];
>          4'h3: oDOUT <= mem[31:24];
>          4'h4: oDOUT <= mem[39:32];
>          4'h5: oDOUT <= mem[47:40];
>          4'h6: oDOUT <= mem[55:48];
>          4'h7: oDOUT <= mem[63:56];
>          4'h8: oDOUT <= mem[71:64];
>          default: oDOUT <= 8'h00;
>       endcase

> --

> Motorola WSSG  M/S: CH275   phone: (480)814-4920
> 1300 N. Alma School Rd.     fax:   (480)814-3107
> Chandler, AZ 85224

--
=========================================================================
Robert R Fairlie - IC Design, Motorola, Scotland, Tel.  - +44 1355 356039
=========================================================================


Sun, 10 Feb 2002 03:00:00 GMT  
 Parallel in Serial out
Thanks to both of you. I slightly adapted the ideas presented but I think I
finally have something that works. Can one of you guys tell me why between
reads you tristate the bus? Is this something commonly done? Just a
question. The code I wrote does not do this but I have seen this done on
more then one occasion.

Are both of you in ASIC design with Motorola? Or do you just know your
verilog. You might have guessed that I have not been using Verilog for very
long but I think I am starting to get a little clue.

Thanks again,
Tim



Sun, 10 Feb 2002 03:00:00 GMT  
 Parallel in Serial out
When you need to switch the direction of a tri-state bus, you have to
take some measures against the possibility that both sides will drive
the bus for a short while. If you turn-off one side and turn-on the
other at the same clock edge, there is a chance that because of
placement and other factors which effect the delays to the drivers,
both drivers will be on, ie if the to-be-inactive side is slow and
to-be-active side is fast. So it is always a good idea to put a clock
cycle of tri-state bus to get around this issue.

Quote:

>Thanks to both of you. I slightly adapted the ideas presented but I think I
>finally have something that works. Can one of you guys tell me why between
>reads you tristate the bus? Is this something commonly done? Just a
>question. The code I wrote does not do this but I have seen this done on
>more then one occasion.

>Are both of you in ASIC design with Motorola? Or do you just know your
>verilog. You might have guessed that I have not been using Verilog for very
>long but I think I am starting to get a little clue.

>Thanks again,
>Tim

muzo

Verilog, ASIC/FPGA and NT Driver Development Consulting (remove nospam from email)



Sun, 10 Feb 2002 03:00:00 GMT  
 Parallel in Serial out

Quote:

> Thanks to both of you. I slightly adapted the ideas presented but I think I
> finally have something that works.

Good!

Quote:
> Can one of you guys tell me why between
> reads you tristate the bus? Is this something commonly done? Just a
> question. The code I wrote does not do this but I have seen this done on
> more then one occasion.

If there are no other drivers for whatever bus oDOUT is connected to,
then there is no need to tri-state oDOUT.  I guess Robert and I just
assumed (bad mistake) that if you have a "read" signal then you only
want to drive the bus when it's asserted.

Quote:
> Are both of you in ASIC design with Motorola? Or do you just know your
> verilog. You might have guessed that I have not been using Verilog for very
> long but I think I am starting to get a little clue.

I'm not sure of Robert's job function, but I do ASIC design.  We have
worked together to develop Moto's Verilog coding standards.

Mark



Sun, 10 Feb 2002 03:00:00 GMT  
 
 [ 8 post ] 

 Relevant Pages 

1. Serial-parallel and Parallel-serial converter

2. Making parallel data less parallel, or serial

3. SERIAL VS PARALLEL PRINTER OPERATION

4. multiple, parallel, asynchronous, continuous Serial VISA reads

5. Parallel port/NT4.0/Serial drivers

6. Parallel - Serial Converter

7. Parallel port for serial commuication?

8. Question: serial/parallel port

9. RDA serial, parallel port

10. Read from serial port and others task in parallel

11. digital serial signal to parallel signal

12. serial to parallel

 

 
Powered by phpBB® Forum Software