OpenCores
URL https://opencores.org/ocsvn/orsoc_graphics_accelerator/orsoc_graphics_accelerator/trunk

Subversion Repositories orsoc_graphics_accelerator

[/] [orsoc_graphics_accelerator/] [trunk/] [rtl/] [verilog/] [gfx/] [gfx_line.v] - Rev 6

Compare with Previous | Blame | View Log

/*
ORSoC GFX accelerator core
Copyright 2012, ORSoC, Per Lenander, Anton Fosselius.
 
Bresenham line algarithm 
 
 This file is part of orgfx.
 
 orgfx is free software: you can redistribute it and/or modify
 it under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version. 
 
 orgfx is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU Lesser General Public License for more details.
 
 You should have received a copy of the GNU Lesser General Public License
 along with orgfx.  If not, see <http://www.gnu.org/licenses/>.
 
*/
// trigger on high
 
module bresenham_line(clk_i, rst_i,
pixel0_x_i, pixel0_y_i, pixel1_x_i, pixel1_y_i, 
draw_line_i, read_pixel_i, 
busy_o, x_major_o, major_o, minor_o, valid_o
);
 
parameter point_width = 16;
parameter subpixel_width = 16;
 
input clk_i;
input rst_i;
 
input signed [point_width-1:-subpixel_width] pixel0_x_i;
input signed [point_width-1:-subpixel_width] pixel1_x_i;
input signed [point_width-1:-subpixel_width] pixel0_y_i;
input signed [point_width-1:-subpixel_width] pixel1_y_i;
 
input draw_line_i;
input read_pixel_i;
 
output reg busy_o;
output reg valid_o;
 
output reg signed [point_width-1:0] major_o;
output reg signed [point_width-1:0] minor_o;
 
//line drawing reg & wires
reg [point_width-1:-subpixel_width] xdiff; // dx
reg [point_width-1:-subpixel_width] ydiff; // dy
output reg x_major_o; // if x is the major axis (for each x, y changes less then x)
 
reg signed [point_width-1:-subpixel_width] left_pixel_x; // this is the left most pixel of the two input pixels
reg signed [point_width-1:-subpixel_width] left_pixel_y; 
reg signed [point_width-1:-subpixel_width] right_pixel_x; // this is the right most pixel of the two input pixels
reg signed [point_width-1:-subpixel_width] right_pixel_y;
 
reg [point_width-1:-subpixel_width] delta_major; // if x is major this value is xdiff, else ydiff
reg [point_width-1:-subpixel_width] delta_minor; // if x is minor this value is xdiff, else ydiff
 
reg minor_slope_positive; // true if slope is in first quadrant 
 
reg  signed          [point_width-1:0] major_goal;
reg  signed [2*point_width-1:-subpixel_width] eps;
wire signed [2*point_width-1:-subpixel_width] eps_delta_minor;
wire done;
 
// State machine
reg [2:0] state;
parameter wait_state = 0, line_prep_state = 1, line_state = 2, raster_state = 3;
 
assign eps_delta_minor = eps+delta_minor;
 
always@(posedge clk_i or posedge rst_i)
if(rst_i)
  state <= wait_state;
else
  case (state)
 
    wait_state:
      if(draw_line_i)
        state <= line_prep_state; // if request for drawing a line, go to line drawing state
 
    line_prep_state:
      state <= line_state;
 
    line_state:
      state <= raster_state;
 
    raster_state:
      if(!busy_o)
        state <= wait_state;
 
  endcase
 
wire is_inside_screen = (minor_o >= 0) & (major_o >= -1);
reg previously_outside_screen;
 
always@(posedge clk_i or posedge rst_i)
begin
  if(rst_i)
  begin
    minor_slope_positive <= 1'b0;
    eps                  <= 1'b0;
    major_o              <= 1'b0;
    minor_o              <= 1'b0;
    busy_o               <= 1'b0;
    major_goal           <= 1'b0;
    x_major_o            <= 1'b0;
    delta_minor          <= 1'b0;
    delta_major          <= 1'b0;
    valid_o              <= 1'b0;
    left_pixel_x         <= 1'b0;
    left_pixel_y         <= 1'b0;
    right_pixel_x        <= 1'b0;
    right_pixel_y        <= 1'b0;
    xdiff                <= 1'b0;
    ydiff                <= 1'b0;
    previously_outside_screen <= 1'b0;
  end
  else
  begin
 
// ## new magic
    // Start a raster line operation 
   case (state)
 
      wait_state:
        if(draw_line_i)
        begin
          // set busy!
          previously_outside_screen <= 1'b0;
          busy_o  <= 1'b1;
          valid_o <= 1'b0;
          // check diff in x and y
          if(pixel0_x_i > pixel1_x_i)
          begin
            xdiff         <= pixel0_x_i - pixel1_x_i;
 
            // pixel0 is greater then pixel1, pixel1 is left of pixel0.
            left_pixel_x  <= pixel1_x_i;
            left_pixel_y  <= pixel1_y_i;
            right_pixel_x <= pixel0_x_i;
            right_pixel_y <= pixel0_y_i;
 
            // check diff for y axis (swapped)
            if(pixel1_y_i > pixel0_y_i)
            begin
              ydiff                <= pixel1_y_i - pixel0_y_i;
              minor_slope_positive <= 1'b0;
            end
            else
            begin
              ydiff                <= pixel0_y_i - pixel1_y_i;
              minor_slope_positive <= 1'b1;
            end
 
          end
          else
          begin
            xdiff         <= pixel1_x_i - pixel0_x_i;
 
            // pixel1 is greater then pixel0, pixel0 is left of pixel1.
            left_pixel_x  <= pixel0_x_i;
            left_pixel_y  <= pixel0_y_i;
            right_pixel_x <= pixel1_x_i;
            right_pixel_y <= pixel1_y_i;
 
            // check diff for y axis
            if(pixel0_y_i > pixel1_y_i)
            begin
              ydiff                <= pixel0_y_i - pixel1_y_i;
              minor_slope_positive <= 1'b0; // the slope is "\" negative
            end
            else
            begin
              ydiff                <= pixel1_y_i - pixel0_y_i;
              minor_slope_positive <= 1'b1; // the slope is "/" positive
            end
          end
        end
 
    // Prepare linedrawing
      line_prep_state:
      begin
        if(xdiff > ydiff)
        begin // x major axis
          x_major_o    <= 1'b1;
          delta_major  <= xdiff;
          delta_minor  <= ydiff;
        end
        else
        begin // y major axis 
          x_major_o    <= 1'b0;    
          delta_major  <= ydiff;
          delta_minor  <= xdiff; 
        end
      end
 
 
      // Rasterize a line between dest_pixel0 and dest_pixel1 (rasterize = generate the pixels)
      line_state:
      begin
          if(x_major_o) 
          begin
            major_o    <= $signed(left_pixel_x[point_width-1:0]);
            minor_o    <= $signed(left_pixel_y[point_width-1:0]);
            major_goal <= $signed(right_pixel_x[point_width-1:0]);
          end
          else 
          begin
            major_o    <= $signed(left_pixel_y[point_width-1:0]);
            minor_o    <= $signed(left_pixel_x[point_width-1:0]);
            major_goal <= $signed(right_pixel_y[point_width-1:0]);
          end
          eps          <= 1'b0;
          busy_o       <= 1'b1;
          valid_o      <= (left_pixel_x >= 0 && left_pixel_y >= 0);
 
          previously_outside_screen <= ~(left_pixel_x >= 0 && left_pixel_y >= 0);
      end
 
    raster_state:
    begin
      // pixels is now valid!           
      valid_o <= (previously_outside_screen | read_pixel_i) & is_inside_screen;
 
      previously_outside_screen <= ~is_inside_screen;
 
      //bresenham magic
      if((read_pixel_i & is_inside_screen) | previously_outside_screen)
      begin
        if((major_o < major_goal) & minor_slope_positive & x_major_o & busy_o) // if we are between endpoints and want to draw a line, continue
        begin
          major_o   <=  major_o + 1'b1; // major axis increeses
 
          if((eps_delta_minor*2) >= $signed(delta_major))
          begin
            eps     <=  eps_delta_minor - delta_major;
            minor_o <=  minor_o + 1'b1; // minor axis increeses
          end
          else
            eps     <=  eps_delta_minor;
        end
        else if((major_o < major_goal) & minor_slope_positive & !x_major_o & busy_o) 
        begin
          major_o   <=  major_o + 1'b1; // major axis increeses
 
          if((eps_delta_minor*2) >= $signed(delta_major))
          begin
            eps     <=  eps_delta_minor - delta_major;
            minor_o <=  minor_o + 1'b1; // minor axis increeses
          end
          else
            eps     <=  eps_delta_minor;
        end
        else if((major_o > major_goal) & !minor_slope_positive & !x_major_o & busy_o)// the slope is negative
        begin
          major_o   <=  major_o - 1'b1; // major axis decreeses
 
          if((eps_delta_minor*2) >= $signed(delta_major))
          begin
            eps     <=  eps_delta_minor - delta_major;
            minor_o <=  minor_o + 1'b1; // minor axis increeses
          end
          else
            eps     <=  eps_delta_minor;
        end
        else if((major_o < major_goal) & !minor_slope_positive & x_major_o & busy_o)// special to fix ocant 4 & 8.
        begin
          major_o   <=  major_o + 1'b1; // major axis increeses
 
          if((eps_delta_minor*2) >= $signed(delta_major))
          begin
            eps     <=  eps_delta_minor - delta_major;
            minor_o <=  minor_o - 1'b1; // minor axis decreeses
          end
          else
            eps     <=  eps_delta_minor;
        end
        // if we have reached tho goal and are busy, stop being busy.
        else if(busy_o)
        begin
          busy_o <=  1'b0;
          valid_o <= 1'b0;
        end
      end
    end
    endcase
  end
end
 
endmodule
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.