sugar-lissajous/source/fig_drawer.sv
2021-02-28 18:59:56 +03:00

224 lines
5.2 KiB
Systemverilog

`timescale 1ns/100ps
`default_nettype none
`include "assert.vh"
module fig_drawer #(parameter FIG_W = 8,
parameter FIG_H = 8,
parameter FIG_ROM_FILE = "fig_circle_8x8.rom")
(input wire clock,
input wire reset,
input wire [7:0] x_i,
input wire [8:0] y_i,
input wire [7:0] h_i,
input wire [7:0] s_i,
input wire [7:0] v_i,
input wire req_i,
output reg ack_o,
output reg [7:0] fb_x_o,
output reg [8:0] fb_y_o,
output reg [15:0] fb_color_o,
output reg fb_req_o,
input wire fb_ack_i);
initial begin
`assert(FIG_W > 0);
`assert(FIG_H > 0);
/* Check power of 2 */
`assert(FIG_W == 1 << $clog2(FIG_W));
`assert(FIG_H == 1 << $clog2(FIG_H));
end
/* Figure bitmap */
localparam FIG_SIZE = FIG_W * FIG_H;
localparam FIG_W_CW = $clog2(FIG_W);
localparam FIG_H_CW = $clog2(FIG_H);
localparam FIG_CW = $clog2(FIG_SIZE);
logic [7:0] fig[FIG_SIZE];
initial $readmemh(FIG_ROM_FILE, fig, 0, FIG_SIZE-1);
logic [FIG_CW-1:0] fig_addr;
logic [7:0] fig_data;
always_ff @ (posedge clock)
fig_data <= fig[fig_addr];
/* Scale brightness */
logic [31:0] mac_v_o;
logic [7:0] fig_v;
assign fig_v = mac_v_o[15:8];
ice40_mac16x16 mac_v
(.clock, .reset,
.a({8'b0, fig_data}),
.b({8'b0, v_i}),
.s(32'b0),
.sub(1'b0),
.y(mac_v_o));
/* Convert HSV ro RGB */
logic hsv_ready;
logic rgb_valid;
logic [7:0] r, g, b;
hsv2rgb hsv2rgb_i
(.clock, .reset,
.h(h_i), .s(s_i), .v(fig_v),
.ready_i(hsv_ready),
.r(r), .g(g), .b(b),
.valid_o(rgb_valid));
/* FSM states */
enum int unsigned {
ST_IDLE = 0, // 0
ST_READ_PIX, // 1
ST_MULT_V, // 2
ST_HSV_READY, // 3
ST_RGB_WAIT, // 4
ST_WAIT_FB, // 5
ST_NEXT_PIXEL, // 6
ST_DONE // 7
} state, next;
/* FSM sync part */
always_ff @(posedge clock, posedge reset)
if (reset) state <= ST_IDLE;
else state <= next;
/* Pixel coordinate */
logic [FIG_W_CW-1:0] pix_x;
logic [FIG_H_CW-1:0] pix_y;
logic pix_reset, pix_next;
assign fig_addr = {pix_y, pix_x};
always_ff @(posedge clock)
if (pix_reset) begin
pix_x <= '0;
pix_y <= '0;
end
else
if (pix_next)
if (pix_x == FIG_H_CW'(FIG_H-1)) begin
pix_x <= '0;
if (pix_y == FIG_W_CW'(FIG_W-1))
pix_y <= '0;
else
pix_y <= pix_y + 1'b1;
end
else
pix_x <= pix_x + 1'b1;
/* Frame buffer control */
logic [7:0] fb_x;
logic [8:0] fb_y;
logic [15:0] fb_color;
logic fb_hold, fb_restore;
logic fb_req;
always_ff @ (posedge clock, posedge reset)
if (reset)
fb_req_o <= 1'b0;
else
if (fb_req)
fb_req_o <= 1'b1;
else
if (fb_ack_i)
fb_req_o <= 1'b0;
assign fb_x = x_i + 8'(pix_x);
assign fb_y = y_i + 9'(pix_y);
always_ff @ (posedge clock) begin
if (rgb_valid) begin
fb_color <= {r[7:3], g[7:2], b[7:3]};
if (~fb_hold)
fb_color_o <= {r[7:3], g[7:2], b[7:3]};
end
if (fb_restore)
fb_color_o <= fb_color;
end
always_ff @ (posedge clock)
if (fb_req) begin
fb_x_o <= fb_x;
fb_y_o <= fb_y;
end
/* FSM comb part */
always_comb begin
next = state;
pix_reset = 1'b0;
pix_next = 1'b0;
fb_req = 1'b0;
fb_hold = 1'b0;
fb_restore = 1'b0;
ack_o = 1'b0;
hsv_ready = 1'b0;
case (state)
ST_IDLE:
if (req_i) begin
pix_reset = 1'b1;
next = ST_READ_PIX;
end
ST_READ_PIX:
next = ST_MULT_V;
ST_MULT_V:
if (fig_data == '0) begin
pix_next = 1'b1;
next = ST_NEXT_PIXEL;
end
else
next = ST_HSV_READY;
ST_HSV_READY: begin
hsv_ready = 1'b1;
next = ST_RGB_WAIT;
end
ST_RGB_WAIT:
if (rgb_valid) begin
if (fb_req_o && !fb_ack_i) begin
fb_hold = 1'b1;
next = ST_WAIT_FB;
end
else begin
fb_req = 1'b1;
pix_next = 1'b1;
next = ST_NEXT_PIXEL;
end
end
ST_WAIT_FB:
if (fb_ack_i) begin
fb_restore = 1'b1;
fb_req = 1'b1;
pix_next = 1'b1;
next = ST_NEXT_PIXEL;
end
ST_NEXT_PIXEL:
if (pix_x == '0 && pix_y == '0)
next = ST_DONE;
else
next = ST_MULT_V;
ST_DONE: begin
ack_o = 1'b1;
next = ST_IDLE;
end
endcase
end
endmodule // fig_drawer