aboutsummaryrefslogtreecommitdiff
path: root/task3/circle.sv
blob: c8dd60d061a09cd15aa7961de44b0718f59fd68d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
`define VGA_W 160
`define VGA_H 120

module circle(clk, rst_n, colour, centre_x, centre_y, radius, start, done,
	vga_x, vga_y, vga_colour, vga_plot);

	input logic clk, rst_n, start;
	input logic [2:0] colour;
	input logic [6:0] centre_y;
	input logic [7:0] centre_x, radius;

	output logic done, vga_plot;
	output logic [2:0] vga_colour;
	output logic [6:0] vga_y;
	output logic [7:0] vga_x;

	logic clear;
	logic [2:0] octant;
	logic [7:0] offset_x, offset_y, offset_x_next, offset_y_next;
	/* One bit larger since these are signed. */
	logic signed [7:0] vga_y_next;
	logic signed [8:0] vga_x_next, crit, crit_next;

	assign vga_colour = colour;

	always_comb case (octant)
		3'd0: begin
			vga_x_next = centre_x + offset_x;
			vga_y_next = centre_y + offset_y;
		end
		3'd1: begin
			vga_x_next = centre_x + offset_y;
			vga_y_next = centre_y + offset_x;
		end
		3'd2: begin
			vga_x_next = centre_x - offset_y;
			vga_y_next = centre_y + offset_x;
		end
		3'd3: begin
			vga_x_next = centre_x - offset_x;
			vga_y_next = centre_y + offset_y;
		end
		3'd4: begin
			vga_x_next = centre_x - offset_x;
			vga_y_next = centre_y - offset_y;
		end
		3'd5: begin
			vga_x_next = centre_x - offset_y;
			vga_y_next = centre_y - offset_x;
		end
		3'd6: begin
			vga_x_next = centre_x + offset_y;
			vga_y_next = centre_y - offset_x;
		end
		3'd7: begin
			vga_x_next = centre_x + offset_x;
			vga_y_next = centre_y - offset_y;
		end
	endcase

	always_comb begin
		offset_x_next = offset_x;
		offset_y_next = offset_y + 1;

		if (crit <= 0)
			crit_next = crit + 2 * offset_y_next + 1;
		else begin
			offset_x_next = offset_x - 1;
			crit_next = crit
				+ 2 * (offset_y_next - offset_x_next) + 1;
		end
	end

	always_ff @(posedge clk) begin
		if (rst_n !== 1) begin
			done <= 1'b0;

			/* Initialise the registers for the circle algorithm. */
			vga_x <= 8'b0;
			vga_y <= 7'b0;
			vga_plot <= 1'b0;
			octant <= 3'b0;
			offset_y <= 8'b0;
			offset_x <= radius;
			crit <= 1 - radius;
		end

		/* Draw the circle using the Bresenham circle algorithm. */
		if (start && ~done) begin
			if (offset_y <= offset_x) begin
				if ((vga_x_next >= 0) && (vga_x_next <= `VGA_W))
					vga_x <= vga_x_next;
				if ((vga_y_next >= 0) && (vga_y_next <= `VGA_H))
					vga_y <= vga_y_next;

				/* Plot only within the monitor's geometry. */
				vga_plot <= ((vga_x_next >= 0)
					&& (vga_x_next <= `VGA_W)
					&& (vga_y_next >= 0)
					&& (vga_y_next <= `VGA_H));

				octant <= octant + 1;

				/* The last octant. */
				if (octant == 7) begin
					offset_x <= offset_x_next;
					offset_y <= offset_y_next;
					crit <= crit_next;
				end
			/* Finished. */
			end else begin
				done <= 1'b1;
				vga_plot <= 1'b0;
			end
		/* Wait for start to be deasserted. */
		end else if (~start && done)
			done <= 1'b0;
	end
endmodule