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