bresenhem.v

module bresenhem (CLK, reset, init, Ax_in, Ay_in, Bx_in, By_in, lock, busy, done,
                  we, addr_reg_x, addr_reg_y, data_reg);
   input       CLK;
   wire        CLK;
   // active-high reset
   input       reset;
   wire        reset;
   // external signal to start. ax, ay, bx, by are set
   input       init;
   wire        init;
   input signed [9:0] Ax_in, Ay_in, Bx_in, By_in;
   wire signed [9:0]  Ax_in, Ay_in, Bx_in, By_in;
   //  did we lose the lock?
   input              lock;
   wire               lock;
   // SRAM (or data-store) control
   output             we;
   output [8:0]       addr_reg_x, addr_reg_y;
   output [1:0]       data_reg;

   reg                we; // write enable
   reg [8:0]          addr_reg_x, addr_reg_y;
   reg [1:0]          data_reg;
   
   //reg [17:0]         addr_reg;
   //reg [15:0]         data_reg;
   
   reg signed [9:0]   Ax, Ay, Bx, By;
   // signal raised to show that the algo. isn't done
   // only high if init is high.
   // is never high when done is high.
   output      busy;
   reg         busy = 1'b0;
   // signal raised to show that the ax,ay,bx,by line is drawn.
   // only high for as long as init is not going posedge.
   output      done;
   reg         done = 1'b0;

   reg signed [9:0] Ax_last, Ay_last, Bx_last, By_last;
   reg signed [9:0] dX, dY, Xincr, Yincr;
   reg signed [9:0] dPr, dPru, P, loop_end;

   wire signed [9:0] Ax_incr, Ay_incr;
   assign            Ax_incr = Ax + Xincr;
   assign            Ay_incr = Ay + Yincr;
   
   reg [3:0]     state; // state machine variable for current state
   //reg           lock;   // the hardware lock

   parameter     init_line = 4'd0,
                   lineDX = 4'd1,
                   lineDY = 4'd2,
                   done_line = 4'd3,
                   SCREEN_TOP = 10'd1,
                   SCREEN_DOWN = 10'd238,
                   SCREEN_LEFT = 10'd3,
                   SCREEN_RIGHT = 10'd319,
                   debug_drawing = 1'b1,
                   debug_bresenhem = 1'b1;
   
   always @(posedge CLK) begin
      if (reset) begin
         // last lines?
         Ax_last <= 10'd0;
         Ay_last <= 10'd0;
         Bx_last <= 10'd0;
         By_last <= 10'd0;

         busy <= 1'b0;
         done <= 1'b0;
         state <= done_line;
         we <= 1'b0;
      end else if (lock) begin
         case (state)
           done_line: begin
              // progress only if there is new input
              if (init == 1'b1) begin
                 // this may hang if the requester asks the module
                 // to draw the same points twice!
                 // requester must de-asserted init line for at least
                 // one cycle in order to reset
                 if (Ax_in != Ax_last & Ay_in != Ay_last &
                     Bx_in != Bx_last & By_in != By_last) begin
                    // a new and different line was just requested thru ax,ay,bx,by

                    // saving to compare
                    Ax_last <= Ax_in;
                    Ay_last <= Ay_in;
                    Bx_last <= Bx_in;
                    By_last <= By_in;
                    // saving as state variables
                    Ax <= Ax_in;
                    Ay <= Ay_in;
                    Bx <= Bx_in;
                    By <= By_in;

                    // setting some differential variables
                    // dX gets abs (Bx - Ax)
                    // Xincr gets (Ax < Bx) or (Bx > Ax)
                    if (Bx_in > Ax_in) begin
                       dX <= Bx_in - Ax_in;
                       Xincr <= 10'd1;
                    end else begin
                       dX <= Ax_in - Bx_in;
                       Xincr <= -10'd1;
                    end
                    // dY gets abs (By - Ay)
                    // Yincr gets (Ay < By) or (By > Ay)
                    if (By_in > Ay_in) begin
                       dY <= By_in - Ay_in;
                       Yincr <= 10'd1;
                    end else begin
                       dY <= Ay_in - By_in;
                       Yincr <= -10'd1;
                    end

                    // start drawing this line
                    state <= init_line;

                    // not done drawing line. busy.
                    busy <= 1'b1;
                    done <= 1'b0;
                 end else begin
                    // done drawing the line. finished.
                    busy <= 1'b0;
                    done <= 1'b1;
                 end
              end else begin
                 // communicate to software that we are reset and ready.

                 // here: nothing
                 busy <= 1'b0;
                 done <= 1'b0;

                 Ax_last <= 10'd0;
                 Ay_last <= 10'd0;
                 Bx_last <= 10'd0;
                 By_last <= 10'd0;
              end
           end // case: done_line
           init_line: begin
              if (dX >= dY) begin
                 dPr <= (dY << 10'b1);
                 dPru <= (dY << 10'b1) - (dX << 10'b1);
                 P <= (dY << 10'b1) - dX;
                 loop_end <= dX;

                 state <= lineDX;
              end else begin
                 dPr <= (dX << 10'b1);
                 dPru <= (dX << 10'b1) - (dY << 10'b1);
                 P <= (dX << 10'b1) - dY;
                 loop_end <= dY;

                 state <= lineDY;
              end // else: !if(dX >= dY)

              // draw the initial point?
              if (Ax_incr >= SCREEN_LEFT & Ax_incr < SCREEN_RIGHT &
                  Ay_incr >= SCREEN_TOP & Ay_incr < SCREEN_DOWN) begin
                 // plot the thing
                 //lock <= 1'b1;
                 addr_reg_x <= Ax[8:0];
                 addr_reg_y <= Ay[8:0];
                 //data_reg <= 16'hffff;
                 data_reg <= 2'b01; // white dot
                 we <= 1'b1;
                 if (debug_drawing) begin
                    $display("Drawing (%d, %d).", Ax[8:0], Ay[8:0]);
                 end
              end else begin
                 we <= 1'b0;
              end // else: !if(Ax >= SCREEN_LEFT & Ax < SCREEN_RIGHT &...
                 
           end // case: init_line
           lineDX: begin
              // for the case when dX >= dY
              if (loop_end > 0) begin
                 if (P > 0) begin
                    Ax <= Ax_incr;
                    Ay <= Ay_incr;
                    P <= P + dPru;
                 end else begin
                    Ax <= Ax_incr;
                    P <= P + dPr;
                 end // else: !if(P > 0)

                 // draw?
                 if (Ax_incr >= SCREEN_LEFT & Ax_incr < SCREEN_RIGHT &
                     Ay_incr >= SCREEN_TOP & Ay_incr < SCREEN_DOWN) begin
                    // plot the thing
                    //lock <= 1'b1;
                    //addr_reg <= { Ax_incr[8:0], (P > 0) ? Ay_incr[8:0] : Ay[8:0] };
                    addr_reg_x <= Ax_incr[8:0];
                    addr_reg_y <= (P > 0) ? Ay_incr[8:0] : Ay[8:0];
                    //data_reg <= 16'hffff;
                    data_reg <= 2'b01;
                    we <= 1'b1;
                 end else begin
                    we <= 1'b0;
                 end // else: !if(Ax >= SCREEN_LEFT & Ax < SCREEN_RIGHT &...

                 loop_end <= loop_end - 1;
              end // if (loop_end > 0)
              else begin
                 state <= done_line;
                 busy <= 1'b0;
                 done <= 1'b1;
              end // else: !if(loop_end > 0)
           end // case: lineDX

           lineDY: begin
              // for the case when dX < dY
              if (loop_end > 0) begin
                 if (P > 0) begin
                    if (debug_bresenhem) begin
                       $display("lineDY_a: Ax = %d, Xincr = %d, Ax + Xincr = %d",
                                Ax, Xincr, Ax_incr);
                    end
                    Ax <= Ax_incr;
                    Ay <= Ay_incr;
                    P <= P + dPru;
                 end else begin
                    if (debug_bresenhem) begin
                       $display("lineDY_b: Ax = %d, Xincr = %d, Ax + Xincr = %d",
                                Ax, Xincr, Ax_incr);
                    end
                    Ay <= Ay_incr;
                    P <= P + dPr;
                 end

                 // draw?
                 if (Ax_incr >= SCREEN_LEFT & Ax_incr < SCREEN_RIGHT &
                     Ay_incr >= SCREEN_TOP & Ay_incr < SCREEN_DOWN) begin
                    // plot the thing
                    //lock <= 1'b1;
                    //addr_reg <= { (P > 0) ? Ax_incr[8:0] : Ax[8:0], Ay_incr[8:0] };
                    addr_reg_x <= (P > 0) ? Ax_incr[8:0] : Ax[8:0];
                    addr_reg_y <= Ay_incr[8:0];
                    //data_reg <= 16'hffff;
                    data_reg <= 2'b01; // white dot
                    we <= 1'b1;
                 end else begin
                    we <= 1'b0;
                 end // else: !if(Ax >= SCREEN_LEFT & Ax < SCREEN_RIGHT &...
                 
                 loop_end <= loop_end - 1;
              end else begin // if (loop_end > 0)
                 state <= done_line;
                 busy <= 1'b0;
                 done <= 1'b1;
              end // else: !if(loop_end > 0)
           end // case: lineDY
         endcase // case (state)
      end
   end // always @ (posedge CLK)
endmodule



2007-12-02