aboutsummaryrefslogtreecommitdiff
path: root/task3/circle.sv
diff options
context:
space:
mode:
authorWarrick Lo <wlo@warricklo.net>2026-03-01 08:17:53 -0800
committerWarrick Lo <wlo@warricklo.net>2026-03-01 08:17:53 -0800
commit1d38da9510fc886366247272c6b6f3d16e03ff89 (patch)
treefd6ebc407864b4a5bb4de021f40b7b4bdf7d1aef /task3/circle.sv
parentAdd task 2 code (diff)
Add task 3 code
Signed-off-by: Warrick Lo <wlo@warricklo.net>
Diffstat (limited to 'task3/circle.sv')
-rw-r--r--task3/circle.sv149
1 files changed, 142 insertions, 7 deletions
diff --git a/task3/circle.sv b/task3/circle.sv
index 112426d..c6218d8 100644
--- a/task3/circle.sv
+++ b/task3/circle.sv
@@ -1,8 +1,143 @@
-module circle(input logic clk, input logic rst_n, input logic [2:0] colour,
- input logic [7:0] centre_x, input logic [6:0] centre_y, input logic [7:0] radius,
- input logic start, output logic done,
- output logic [7:0] vga_x, output logic [6:0] vga_y,
- output logic [2:0] vga_colour, output logic vga_plot);
- // draw the circle
-endmodule
+`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, ready;
+ 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 = clear ? 3'b000 : 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) begin
+ done <= 1'b0;
+ ready <= 1'b0;
+
+ /* Start clearing the screen. */
+ clear <= 1'b1;
+ vga_x <= 8'b0;
+ vga_y <= 7'b0;
+ vga_plot <= 1'b1;
+ end
+
+ /* Clear the screen. */
+ if (clear) begin
+ if (vga_y < 120) begin
+ /* Check for one column less since it takes
+ * one clock cycle to reset and increment. */
+ if (vga_x < 159)
+ vga_x <= vga_x + 1;
+ else begin
+ vga_x <= 8'b0;
+ vga_y <= vga_y + 1;
+ end
+ end else begin
+ clear <= 1'b0;
+ ready <= 1'b1;
+ vga_x <= 8'b0;
+ vga_y <= 7'b0;
+ vga_plot <= 1'b0;
+ end
+ /* Initialise the registers for the circle algorithm. */
+ end else if (ready && start && ~done) begin
+ ready <= 1'b0;
+ octant <= 3'b0;
+ offset_y <= 8'b0;
+ offset_x <= radius;
+ crit <= 1 - radius;
+ /* Draw the circle using the Bresenham circle algorithm. */
+ end else 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;
+ ready <= 1'b1;
+ vga_plot <= 1'b0;
+ end
+ /* Wait for start to be deasserted. */
+ end else if (~start && done)
+ done <= 1'b0;
+ end
+endmodule