6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Mon Apr 29, 2024 3:25 am

All times are UTC




Post new topic Reply to topic  [ 66 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next
Author Message
 Post subject: Concatenation in Verilog
PostPosted: Thu Oct 24, 2013 12:45 am 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Another n00b question regarding Verilog and concatenation of bits using the '{}' operator.
Is it {MSb,LSb}? which I would have found more logical, but has always thrown me in a loop.
Or {LSb,MSb}? I just need confirmation. Is this really correct thinking?

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 24, 2013 12:59 am 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
Quote:
Is it {MSb,LSb}? which I would have found more logical,


It's {MSB...LSB}. MSB on the left, LSBs to the right.

I've been following along, and I don't understand why the VSYNC signal would need significant delays. It can't be out more than a few clock cycles. Shouldn't the propagation delay in the VSYNC be about the same as the delay in the HSYNC ?

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 24, 2013 1:16 am 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
That's what I would have thought as well... Thanks Rob!
Let me finish the block diagram... My lack of understanding hinders me, but I still make progress...

What I can say is any delays I have put on any of the signals that affect VSYNC do not actually delay pixel output vertically. Which is why I've had to resort to delaying horizontally "a great many cycles" in order to align vertically. For example, in order to delay 2 pixels vertically, I have had to delay the 'hstart' signal by 2x1024 cycles.

This has worked but it is not efficient and I am puzzled why delaying a VSYNC signal differs from delaying an HSYNC signal.

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Thu Oct 24, 2013 5:22 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
For vertical offset, keep in mind that you'd have to delay vsync in steps of a whole line, which is in effect "a great many cycles" if you count the pixels, but is only a small number if you count hlines.

But the question remains why you'd need such fixed offsets anyway.


Top
 Profile  
Reply with quote  
PostPosted: Fri Oct 25, 2013 1:28 am 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Arlet wrote:
...But the question remains why you'd need such fixed offsets anyway.

I think it may have to do with how I am attempting to sync the state machines used in your vga module between successive boards.
When a positive HSYNCin or VSYNCin is detected, it resets the appropriate counters just like the hcount_ done and vcount_done signals do.
Code:
...// adjust down counter. Reload when it's done.
always @(posedge clk)
        if ( HSYNCin | hcount_done )
            hcount <= { 1'b0, hload };...

Code:
...// adjust down counter. Reload when it's done.
always @(posedge clk)
   if( venable ) begin
        if ( VSYNCin | vcount_done )
            vcount <= { 1'b0, vload };...

Also, when HSYNCin or VSYNCin goes active, The state machine is forced to the VIDEO state. Maybe this is wrong? But when I try to sync to any other state, I see no video.
Code:
...// when down counter is done, go to next state
always @(posedge clk)
      if( hcount_done )
         case( hstate )
            VIDEO : hstate <= FRONT;
            FRONT : hstate <= SYNC;
            SYNC  : hstate <= BACK;
            BACK  : hstate <= VIDEO;
         endcase
            else if (HSYNCin)
               hstate <= VIDEO;...

Code:
...// when down counter is done, go to next state
always @(posedge clk)
   if( venable & vcount_done )
         case( vstate )
            VIDEO : vstate <= FRONT;
            FRONT : vstate <= SYNC;
            SYNC  : vstate <= BACK;
            BACK  : vstate <= VIDEO;
         endcase
      else if (VSYNCin)
         vstate <= VIDEO;...

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 06, 2013 7:50 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
...unrelated to previous questions...

For a signal that is common to some modules, is it best to have the logic that derives that signal on the top level?
For example, if I need a display enable signal, 3 signals are needed to generate it: hstart, hblank and vblank. I could generate the display enable within it's own module and output it to other modules, or I could generate it on the top_level. What is the accepted method in Verilog?

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 06, 2013 8:01 pm 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
I would place it at the level most appropriate for the functional decomposition of your system. If you have a sub-module whose function is video control, I'd put it in that module, and bring it up to the top module and distribute it from there. However, if you don't have a module whose function is video control, I'd generate the signal in the top module until such time as there's a need to create a video control module.

_________________
Michael A.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 06, 2013 9:17 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Michael, thanks for the pointer, what you say makes sense maybe I'm getting tunnel vision. Just FYI, Arlet's original .vga controller outputs hstart, hblank, vstart and vblank. Maybe it's a clue...
But let's say for arguments' sake that I modify that video control module to output a display enable signal:
Code:
//display enable
always @(posedge clk)
   if ( hstart )
      countflag <= 1;
      else if ( hblank | vblank )
         countflag <= 0;

So it uses 3 signals and no other modules use those signals. But another module, the external RAM interface, uses the vstart signal to start the pixel counter used for the address:
Code:
// pixel counters for 2MBx18 external SyncRAM
reg [9:0] X;
reg [9:0] Y;

always @(posedge clk)
   if ( vstart | X == 1023 & Y == 767 ) begin
         X <= 0;
         Y <= 0;
      end
         else if ( X == 1023 ) begin
            Y <= Y + 1;
            X <= 0;
         end
            else if ( countflag )
               X <= X + 1;

If the situation were reversed and 3 signals were used externally, and 1 internal would it be best to have this code present in the top module? What about 2 external and 2 internal? or will the tools just figure this stuff out?
So far in my testing I haven't noticed any change but I am chasing down a problem, so I'm 'getting my ducks in a row'. Thanks!

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 06, 2013 9:21 pm 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
I would probably make a separate module to fetch bitmaps from memory, and send the pixel data to the video output, so that the external RAM interface would just offer a multi-port generic memory interface, without any dependency on pixels or screen sizes.


Top
 Profile  
Reply with quote  
PostPosted: Wed Nov 06, 2013 10:06 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
Arlet, I think you're right. Everything seems jumbled now. I am dealing with code that I wrote when I first started learning Verilog. I had some early successes, but they weren't necessarily correct. I'm now having a problem generating a simple border using one video board!

I hate to realize this, but I may have to start from scratch...

But before I do I would like to ask you Verilog experts how to go about making a piece of code sleeker. It is the Line and circle hardware plotter...

I put delays in there to make the simulations look correct and in real life it works, but the code is not pretty. What is the simplest structural change I can make to make this more efficient?

Thanks for your input all!
Code:
`timescale 1ns / 1ps

module LineGen ( input clk,
                 input lineCS,
                 input [15:0] cpuDO,
                 input [3:0] cpuAB,
                 input countflag,
                 input [15:0] SRD,
                 output reg RAMWE,
                 output reg LGREADY,
                 output reg [aw:0] X,
                 output reg [aw:0] Y,
                 output reg [15:0] color,
                 output reg [15:0] border
               );

parameter aw = 10;      //2048
               
//blitter variables
reg [15:0] bXlen, bYlen;
reg [aw:0] bXc, bYc, bXp, bYp;

//linegen variables               
reg [aw:0] x0, x1, dx, x0t, x1t, y0, y1, dy, y0t, y1t;   //internal module registers
         
reg [aw+1:0] D;                   //error accumulator + carry bit. if D[aw+1] = 1, it is negative
reg [0:0] steep,                   //1 when dy>dx
          dyneg,                   //1 when dy is negative
          dxneg;                    //1 when dx is negative

//circle variables
reg [aw:0] xc, yc, rad, x, y = 0;
reg [aw+1:0] raderr;

reg [4:0] state;
parameter WAIT = 0, LOAD = 1, SLOPE = 2, DXDY = 3, CALC1 = 4, CALC2 = 5, PLOT = 6,
          CALC3 = 7, CALC4 = 8, OCT1 = 9, OCT2 = 10, OCT3 = 11, OCT4 = 12, OCT5 = 13, OCT6 = 14, OCT7 = 15, OCT8 = 16,
          DEL1 = 17, DEL2 = 18, DEL3 = 19, DEL4 = 20, DEL5= 21, DEL6 = 22, DEL7 = 23, DEL8 = 24;
 
always @(posedge clk) begin
   if (lineCS && cpuAB == 4'b0000)         //variables for line generator
      x0t <= cpuDO;
   if (lineCS && cpuAB == 4'b0001)
      y0t <= cpuDO;
   if (lineCS && cpuAB == 4'b0010)
      x1t <= cpuDO;
   if (lineCS && cpuAB == 4'b0011)
      y1t <= cpuDO;
   
   if (lineCS && cpuAB == 4'b0100)         //variables for circle generator
      xc <= cpuDO;
   if (lineCS && cpuAB == 4'b0101)
      yc <= cpuDO;
   if (lineCS && cpuAB == 4'b0110)
      rad <= cpuDO;
      
   if (lineCS && cpuAB == 4'b0111)         //color variable
      color <= cpuDO;
      
   if (lineCS && cpuAB == 4'b1000)         //X length of blitter
      bXlen <= cpuDO;
   if (lineCS && cpuAB == 4'b1001)         //Y length of blitter
      bYlen <= cpuDO;
   if (lineCS && cpuAB == 4'b1010)         //X start copy
      bXc <= cpuDO;
   if (lineCS && cpuAB == 4'b1011)         //Y start copy
      bYc <= cpuDO;
   if (lineCS && cpuAB == 4'b1100)         //X start paste
      bXp <= cpuDO;
   if (lineCS && cpuAB == 4'b1101)         //Y start paste
      bYp <= cpuDO;
   
   if (lineCS && cpuAB == 4'b1110)         //border color
      border <= cpuDO;   
   
   
end
               
always @(posedge clk) begin
   state <= WAIT;

      case (state)
         WAIT:
            begin
               if (lineCS && cpuAB == 3'b011)            //draw a line
                    state <= LOAD;
                  else if (lineCS && cpuAB == 3'b110)      //draw a circle
                     state <= CALC3;
                     else state <= WAIT;
            end
         
         LOAD:
            state <= SLOPE;
           
         SLOPE:
            state <= DXDY;
           
         DXDY:                 
            state <= CALC1;   
           
         CALC1:               
            state <= CALC2;   
         
         CALC2:               
            state <= PLOT;     
           
         PLOT:
         begin
            if (!dyneg && steep)           //e.g. (0,0) to (2,10)
               if (y0 != y1)
                    state <= CALC2;
               else state <= WAIT;
               
            if (!dyneg && !steep)         //e.g. (0,0) to (10,10)
               if (x0 != x1)
                    state <= CALC2;
               else state <= WAIT;
       
            if (dyneg && !steep)          //e.g. (0,10) to (10,0)
               if (x0 != x1)
                    state <= CALC2;
               else state <= WAIT;

            if (dyneg && steep)            //e.g. (0,20) to (2,0)
               if (y0 != y1)
                    state <= CALC2;
               else state <= WAIT;
         end
         
         CALC3:
            state <= OCT1;
            
         CALC4:
            state <= OCT1;
            
         OCT1:
            if ( x >= y )
            state <= DEL1;
               else state <= WAIT;
         DEL1:
            state <= OCT2;
            
         OCT2:
            state <= DEL2;
         
         DEL2:
            state <= OCT3;
            
         OCT3:
            state <= DEL3;
            
         DEL3:
            state <= OCT4;
            
         OCT4:
            state <= DEL4;
         
         DEL4:
            state <= OCT5;
            
         OCT5:
            state <= DEL5;
            
         DEL5:
            state <= OCT6;
            
         OCT6:
            state <= DEL6;
         
         DEL6:
            state <= OCT7;
            
         OCT7:
            state <= DEL7;
            
         DEL7:
            state <= OCT8;
            
         OCT8:
            state <= DEL8;
            
         DEL8:
            state <= CALC4;
            
     endcase
end

always @(posedge clk) begin
   case (state)
      WAIT:
         begin
         RAMWE <= 0;
         LGREADY <= 1;
            if (x0t > x1t)
               dxneg <= 1;
               else dxneg <= 0;
         end
         
      LOAD:
         begin
         LGREADY <= 0;
         if (dxneg)
            begin
               x0 <= x1t;
               y0 <= y1t;
               x1 <= x0t;
               y1 <= y0t;               
            end
            else begin
               x0 <= x0t;
               y0 <= y0t;
               x1 <= x1t;
               y1 <= y1t;
            end
         end
     
      SLOPE:
         if (y0 > y1)
              dyneg <= 1;
         else dyneg <= 0;
         
      DXDY:               
         begin           
            dx <= x1 - x0;
            RAMWE <= 1;
            X <= x0;
            Y <= y0;
            if (dyneg)
                 dy <= y0 - y1;
            else dy <= y1 - y0;
         end
         
      CALC1:
         begin
            RAMWE <= 0;      
         if (dx >= dy) begin   
            steep <= 0;
            D <= (dy*2 - dx);   
         end
            else begin
               steep <= 1;
               D <= (dx*2 - dy);   
            end
         end
     
      CALC2:
         begin
            RAMWE <= 0;
         if (steep) begin   
            if ( D[10] == 0 ) begin     
               x0 <= x0 + 1;           
               y0 <= dyneg ? y0 - 1:
                             y0 + 1;           
               D <= D + (dx*2 - dy*2);   
            end
               else begin
                  y0 <= dyneg ? y0 - 1:
                                y0 + 1;   
                  D <= D + dx*2;
               end
         end
            else if ( D[10] == 0 ) begin   
               x0 <= x0 + 1;           
               y0 <= dyneg ? y0 - 1:
                             y0 + 1;           
               D <= D + (dy*2 - dx*2);   
            end
               else begin
                  x0 <= x0 + 1;   
                  D <= D + dy*2;
               end
         end
         
      PLOT:   
         begin
            RAMWE <= 1;
            X <= x0;
            Y <= y0;
         end
      
      CALC3:
         begin
            x <= rad;
            y <= 0;
            raderr <= 1 - x;
            LGREADY <= 0;
            RAMWE <= 0;
         end
         
      CALC4:
         begin
            RAMWE <= 0;
            y <= y + 1;
            if ( raderr[10] )
               raderr <= raderr + (y+1);
               else begin
                  x <= x - 1;
                  raderr <= raderr + (y-x)+1;
               end
         end
         
      OCT1:                              //       |
         begin                           //         |
            RAMWE <= 1;                  //      -------   
            X <= xc + (x);               //         |   Oct1
            Y <= yc + y;               //         |
         end
         
      OCT2:
         begin                           //         |
            RAMWE <= 1;                  //         |
            X <= xc + (y);               //      -------
            Y <= yc + (x);               //         |
         end                           //         |   Oct2
         
      OCT3:                              //         |
         begin                           //         |
            RAMWE <= 1;                  //      -------
            X <= xc - x;               //   Oct3   |
            Y <= yc + y;               //         |
         end
      
      OCT4:                              //         |
         begin                           //         |
            RAMWE <= 1;                  //      -------
            X <= xc - (y);               //         |
            Y <= yc + (x);               //   Oct4   |
         end
         
      OCT5:                              //         |
         begin                           //   Oct5   |
            RAMWE <= 1;                  //      -------
            X <= xc - (x);               //         |
            Y <= yc - y;               //         |
         end
         
      OCT6:                              //   Oct6   |
         begin                           //         |
            RAMWE <= 1;                  //      -------
            X <= xc - (y);               //         |
            Y <= yc - x;               //         |
         end
         
      OCT7:                              //         |
         begin                           //         |   Oct7
            RAMWE <= 1;                  //      -------
            X <= xc + (x);               //         |
            Y <= yc - y;               //         |
         end
         
      OCT8:                              //         |   Oct8
         begin                           //         |
            RAMWE <= 1;                  //      -------
            X <= xc + (y);               //         |
            Y <= yc - (x);               //         |
         end
         
      DEL1:
         RAMWE <= 1;
         
      //DEL2:
      //   RAMWE <= 1;
      
      //DEL3:
      //   RAMWE <= 1;
      
      //DEL4:
      //   RAMWE <= 1;
      
      //DEL5:
      //   RAMWE <= 1;
      
      //DEL6:
      //   RAMWE <= 1;
      
      //DEL7:
      //   RAMWE <= 1;
      
      //DEL8:
      //   RAMWE <= 1;
      
   endcase

end

endmodule

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 24, 2013 7:24 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
All those 'if' statements:
Code:
always @(posedge clk) begin
   if (lineCS && cpuAB == 5'b00000)         //variables for line generator
      x0t <= cpuDO;
   if (lineCS && cpuAB == 5'b00001)
      y0t <= cpuDO;
   if (lineCS && cpuAB == 5'b00010)
      x1t <= cpuDO;
   if (lineCS && cpuAB == 5'b00011)
      y1t <= cpuDO;
   
   if (lineCS && cpuAB == 5'b00100)         //variables for circle generator
      xc <= cpuDO;
   if (lineCS && cpuAB == 5'b00101)
      yc <= cpuDO;
   if (lineCS && cpuAB == 5'b00110)
      rad <= cpuDO;
      
   if (lineCS && cpuAB == 5'b00111)         //color variable
      color <= cpuDO;
      
   if (lineCS && cpuAB == 5'b01000)         //X length of blitter
      bXlen <= cpuDO;
   if (lineCS && cpuAB == 5'b01001)         //Y length of blitter
      bYlen <= cpuDO;
   if (lineCS && cpuAB == 5'b01010)         //X start copy
      bXc <= cpuDO;
   if (lineCS && cpuAB == 5'b01011)         //Y start copy
      bYc <= cpuDO;
   if (lineCS && cpuAB == 5'b01100)         //X start paste
      bXp <= cpuDO;
   if (lineCS && cpuAB == 5'b01101)         //Y start paste
      bYp <= cpuDO;
   
   if (lineCS && cpuAB == 5'b01110)         //border color
      border <= cpuDO;   
   
   if (lineCS && cpuAB == 5'b10000)         //horizontal offset
      hoffset <= cpuDO;
   if (lineCS && cpuAB == 5'b10001)         //vertical offset
      voffset <= cpuDO;
      
end
can be replaced by a more succinct:
Code:
// Register addresses
always @(posedge clk)
 if ( lineCS )
   case ( cpuAB [4:0] )
      5'b00000: x0t <= cpuDO;               //variables for line generator
      5'b00001: y0t <= cpuDO;
      5'b00010: x1t <= cpuDO;
      5'b00011: y1t <= cpuDO;
      
      5'b00100: xc  <= cpuDO;               //variables for circle generator
      5'b00101: yc  <= cpuDO;
      5'b00110: rad <= cpuDO;
      
      5'b00111: color <= cpuDO;            //pixel color variable
      
      5'b01000: bXlen <= cpuDO;            //X length of blitter
      5'b01001: bYlen <= cpuDO;            //Y length of blitter
      5'b01010: bXc   <= cpuDO;            //X start copy
      5'b01011: bYc   <= cpuDO;            //Y start copy
      5'b01100: bXp   <= cpuDO;            //X start paste
      5'b01101: bYp   <= cpuDO;            //Y start paste
      
      5'b01110: border <= cpuDO;            //border color
      
   endcase

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 25, 2013 3:27 am 
Offline
User avatar

Joined: Tue Aug 06, 2013 6:46 pm
Posts: 23
Location: Oregon
ElEctric_EyE wrote:
if (lineCS && cpuAB == 5'b10000) //horizontal offset
hoffset <= cpuDO;
if (lineCS && cpuAB == 5'b10001) //vertical offset
voffset <= cpuDO;


Are you not missing these in your new case statement?

I would suggest you add a default to your case statement just in case you get a situation you are not expecting.


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 25, 2013 2:46 pm 
Offline

Joined: Mon Mar 02, 2009 7:27 pm
Posts: 3258
Location: NC, USA
player55328 wrote:
if (lineCS && cpuAB == 5'b10000) //horizontal offset
hoffset <= cpuDO;
if (lineCS && cpuAB == 5'b10001) //vertical offset
voffset <= cpuDO;
Are you not missing these in your new case statement?...

Good eye! But I actually don't need those delay registers on my final output board.
player55328 wrote:
...I would suggest you add a default to your case statement just in case you get a situation you are not expecting.

That seems to be a good practice, but I'm not sure how I would go about that in this case.

_________________
65Org16:https://github.com/ElEctric-EyE/verilog-6502


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 25, 2013 3:53 pm 
Offline
User avatar

Joined: Mon Apr 23, 2012 12:28 am
Posts: 760
Location: Huntsville, AL
player55328 wrote:
I would suggest you add a default to your case statement just in case you get a situation you are not expecting.

When I read EEyE's post yesterday, I had the same thought initially, but I changed my mind.

First, the if construction that he's using in a single always block is correct. It could be expanded into 17 separate always blocks and the structure would generate the expected logic behavior. That is, only when the condition is true is the register updated, and at all other times the register holds its last value.

Second, it is true that the case statement in the second example, nested inside an if statement, is missing the recommended default clause that prevents the generation of inferred latches. However, since these two statements are inside a clocked always block, there is no need to add the default clause.
ElEctricEyE wrote:
That seems to be a good practice, but I'm not sure how I would go about that in this case.

I also have the same thought. I generally include a default clause to all case statements, and in particular, to case statements in combinatorial always blocks. However, I think this is an example where that general recommendation is not appropriate. In my opinion, adding a default clause to this case statement will reduce the readability of the code.

_________________
Michael A.


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 25, 2013 6:14 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
Just a note: I've found out that sometimes case statements provide better performance than if/else if statements. This is with the Webpack synthesis tools.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 66 posts ]  Go to page Previous  1, 2, 3, 4, 5  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 11 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: