240 lines
5.3 KiB
Systemverilog
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
|