224 lines
5.2 KiB
Systemverilog
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
|