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

240 lines
5.3 KiB
Systemverilog

`timescale 1ns/100ps
`default_nettype none
/**
* HSL to RGB translation.
*
* H, S, L = [0..1)
*
* Q = | L < 0.5 ? L + L*S
* | L >= 0.5 ? L + S - L*S
*
* P = 2 * L - Q
*
* TR = H < 2/3 ? H + 1/3 : 1/3 - (1 - H)
* TG = H
* TB = H >= 1/3 ? H - 1/3 : 1 - H
*
* COLORX = | TX < 1/6 ? P + ((Q - P) * 6 * TX)
* | 1/6 <= TX < 1/2 ? Q
* | 1/2 <= TX < 2/3 ? P + ((Q - P) * (2/3 - TX) * 6)
* | else : P
*/
/*
* Datapath:
*
* if l < [1/2]
* then: lls = l + (l * s)
* else: lls = l - (l * s)
*
* m1h = ~(h - 1)
*
* tr =
* if h < [2/3]
* then: h + [1/3]
* else: [1/3] - m1h
*
* tg = h
*
* tb =
* if h >= [1/3]
* then: h - [1/3]
* else: m1h
*
* q =
* if l < [1/2]
* then: lls
* else: lls + s
*
* p = l * 2 - q
* qp = (q - l) * 2
*
* r =
* p + 6 * qp * tr
* p + 6 * qp * ([2/3] - tr)
*
* g =
* p + 6 * qp * tg
* p + 6 * qp * ([2/3] - tg)
*
* b =
* p + 6 * qp * tb
* p + 6 * qp * ([2/3] - tb)
*/
module hsl2rgb
(input wire clock,
input wire reset,
input wire [7:0] h,
input wire [7:0] s,
input wire [7:0] l,
input wire ready_i,
output reg [7:0] r,
output reg [7:0] g,
output reg [7:0] b,
output wire valid_o);
`define C1_6 43
`define C1_3 85
`define C1_2 128
`define C2_3 171
`define C1_1 256
localparam STAGES = 5;
logic [STAGES-1:0] valid;
assign valid_o = valid[STAGES-1];
always_ff @ (posedge clock, posedge reset)
if (reset)
valid <= '0;
else
valid <= { valid[STAGES-2:0], ready_i };
/* ---------------- Stage 1 ---------------- */
logic [8:0] lls; // lls = l0 ± (l0 * s0)
logic ls_sub;
/* verilator lint_off UNUSED */
logic [31:0] mac_lls_o;
/* verilator lint_on UNUSED */
assign lls = {mac_lls_o[16:8]};
assign ls_sub = l < `C1_2 ? 1'b0 : 1'b1;
ice40_mac16x16 mac_lls
(.clock, .reset,
.a({8'b0, l}),
.b({8'b0, s}),
.s({16'b0, l, 8'b0}),
.sub(ls_sub),
.y(mac_lls_o));
/* propagate to next stage */
logic [7:0] h1, s1, l1;
always_ff @ (posedge clock) begin
h1 <= h;
s1 <= s;
l1 <= l;
end
/* ---------------- stage 2 ---------------- */
logic [8:0] q_pre;
logic [7:0] q;
logic [7:0] minus1h; // minus1h = 256 - h = ~(h - 1)
always_ff @ (posedge clock) begin
q_pre <= l1 < `C1_2 ? lls : lls + s1;
minus1h <= ~(h1 - 1);
end
assign q = q_pre[8] ? 8'hff : q_pre[7:0];
/* propagate to next stage */
logic [7:0] h2, l2;
always_ff @ (posedge clock) begin
h2 <= h1;
l2 <= l1;
end
/* ---------------- stage 3 ---------------- */
logic [7:0] tr, tg, tb;
logic [8:0] p_pre;
logic [7:0] p; // p = l * 2 - q
logic [7:0] qp; // qp = q - p
always_ff @ (posedge clock) begin
tr <= h2 < 8'(`C2_3) ? h2 + 8'(`C1_3) : 8'(`C1_3) - minus1h;
tg <= h2;
tb <= h2 >= 8'(`C1_3) ? h2 - 8'(`C1_3) : minus1h;
p_pre <= (9'(l2) << 1) - q;
qp <= 8'((q - l2) << 1);
end
assign p = p_pre[8] ? 8'hff : p_pre[7:0];
/* propagate to next stage */
logic [7:0] q3;
always_ff @ (posedge clock)
q3 <= q;
/* ---------------- stage 4 ---------------- */
logic [7:0] trx, tgx, tbx;
logic [10:0] qp6;
/* verilator lint_off UNUSED */
logic [31:0] mac_r_o;
logic [31:0] mac_g_o;
logic [31:0] mac_b_o;
/* verilator lint_on UNUSED */
assign qp6 = (11'(qp) << 1) + (11'(qp) << 2);
assign trx = (tr < `C1_6) ? tr : `C2_3 - tr;
assign tgx = (tg < `C1_6) ? tg : `C2_3 - tg;
assign tbx = (tb < `C1_6) ? tb : `C2_3 - tb;
ice40_mac16x16 mac_r
(.clock, .reset,
.a({5'b0, qp6}),
.b({8'b0, trx}),
.s({16'b0, p, 8'b0}),
.sub(1'b0),
.y(mac_r_o));
ice40_mac16x16 mac_g
(.clock, .reset,
.a({5'b0, qp6}),
.b({8'b0, tgx}),
.s({16'b0, p, 8'b0}),
.sub(1'b0),
.y(mac_g_o));
ice40_mac16x16 mac_b
(.clock, .reset,
.a({5'b0, qp6}),
.b({8'b0, tbx}),
.s({16'b0, p, 8'b0}),
.sub(1'b0),
.y(mac_b_o));
/* propagate to next stage */
logic [7:0] tr4, tg4, tb4;
logic [7:0] p4;
logic [7:0] q4;
always_ff @ (posedge clock) begin
tr4 <= tr;
tg4 <= tg;
tb4 <= tb;
p4 <= p;
q4 <= q3;
end
/* ---------------- stage 5 ---------------- */
always_ff @ (posedge clock) begin
if (tr4 < `C1_6) r <= mac_r_o[16] ? 8'hff : mac_r_o[15:8];
else if (tr4 < `C1_2) r <= q4;
else if (tr4 < `C2_3) r <= mac_r_o[16] ? 8'hff : mac_r_o[15:8];
else r <= p4;
end
always_ff @ (posedge clock) begin
if (tg4 < `C1_6) g <= mac_g_o[16] ? 8'hff : mac_g_o[15:8];
else if (tg4 < `C1_2) g <= q4;
else if (tg4 < `C2_3) g <= mac_g_o[16] ? 8'hff : mac_g_o[15:8];
else g <= p4;
end
always_ff @ (posedge clock) begin
if (tb4 < `C1_6) b <= mac_b_o[16] ? 8'hff : mac_b_o[15:8];
else if (tb4 < `C1_2) b <= q4;
else if (tb4 < `C2_3) b <= mac_b_o[16] ? 8'hff : mac_b_o[15:8];
else b <= p4;
end
endmodule // hsl2rgb