diff --git a/demo/fpga/Artix-7-HDMI-processing.xpr b/demo/fpga/Artix-7-HDMI-processing.xpr
index 1ce0331..11265d2 100644
--- a/demo/fpga/Artix-7-HDMI-processing.xpr
+++ b/demo/fpga/Artix-7-HDMI-processing.xpr
@@ -42,7 +42,7 @@
-
+
diff --git a/demo/fpga/src/term_renderer.v b/demo/fpga/src/term_renderer.v
index 44d6d32..4a62825 100644
--- a/demo/fpga/src/term_renderer.v
+++ b/demo/fpga/src/term_renderer.v
@@ -8,6 +8,8 @@ input in_blank, in_vsync, in_hsync,
input [19:0] glyphmem_data,
output [15:0] glyphmem_r_addr,
+input [11:0] scroll_y,
+
output out_hsync, out_vsync,
output [7:0] out_red,
output [7:0] out_green,
@@ -158,11 +160,11 @@ always @(posedge clk) begin
end
if (in_vsync_last && !in_vsync) begin
- glyph_y <= 0;
- px_y <= 0;
+ glyph_y <= scroll_y / FONT_GLYPH_H;
+ px_y <= scroll_y % FONT_GLYPH_H;
end
end
end
-endmodule
\ No newline at end of file
+endmodule
diff --git a/demo/fpga/src/top.v b/demo/fpga/src/top.v
index 635ef15..2f2b1ff 100644
--- a/demo/fpga/src/top.v
+++ b/demo/fpga/src/top.v
@@ -180,6 +180,7 @@ wire [19:0] glyph_buffer_w_data;
wire win_blank;
wire [11:0] win_w;
wire [11:0] win_h;
+wire [11:0] win_scroll_y;
wire out_data_en;
wire out_data_valid;
wire [7:0] matcher_debug;
@@ -306,6 +307,8 @@ term_renderer #(
.in_blank(win_blank),
.in_vsync(in_vsync),
.in_hsync(in_hsync),
+
+ .scroll_y(win_scroll_y),
.out_hsync(),
.out_vsync(),
@@ -347,6 +350,7 @@ window_matcher window_matcher_i (
.win_locked(win_locked),
.win_w(win_w),
.win_h(win_h),
+ .win_scroll_y(win_scroll_y),
.win_x_dbg(win_x_dbg),
.win_y_dbg(win_y_dbg),
@@ -368,4 +372,4 @@ window_matcher window_matcher_i (
.out_blue(out_blue)
);
-endmodule
\ No newline at end of file
+endmodule
diff --git a/demo/fpga/src/window_matcher.v b/demo/fpga/src/window_matcher.v
index 95abe44..6770a99 100644
--- a/demo/fpga/src/window_matcher.v
+++ b/demo/fpga/src/window_matcher.v
@@ -25,6 +25,7 @@ module window_matcher(
output reg [11:0] win_h,
output reg [11:0] win_right,
output reg [11:0] win_bottom,
+ output reg [11:0] win_scroll_y,
output reg win_locked,
input [7:0] win_red, [7:0] win_green, [7:0] win_blue,
@@ -208,6 +209,8 @@ module window_matcher(
reg [11:0] win_y_int;
reg [11:0] win_w_int;
reg [11:0] win_h_int;
+ reg [11:0] win_scroll_y_int;
+ reg [11:0] win_sof_marker_int;
assign win_x_dbg = win_x_int;
assign win_y_dbg = win_y_int;
@@ -221,17 +224,11 @@ module window_matcher(
ST_MAT_RX3 = 5'b01000,
ST_MAT_DATA = 5'b10000;
reg [4:0] matcher_state;
- wire matched = matcher_state[4];
+ reg matched;
reg [11:0] dval_x_reg;
- reg [11:0] dval_y_reg;
always @(posedge clk) begin
- if (rst == 1) begin
- out_data_valid <= 0;
- out_data_en <= 0;
- end
-
if (rst || in_vsync) begin
matcher_state <= ST_MAT_WAITING;
win_x_int <= 0;
@@ -239,68 +236,82 @@ module window_matcher(
win_w_int <= 0;
win_h_int <= 0;
dval_x_reg <= 0;
- dval_y_reg <= 0;
+ win_scroll_y_int <= 0;
+ win_sof_marker_int <= 0;
+ matched <= 0;
+ out_data_en <= 0;
+ out_data_valid <= 0;
end
if (!rst) begin
if (in_blank) begin
- /* Reset state if the header is only partially contained in this frame */
- if (matcher_state != ST_MAT_DATA) begin
- matcher_state <= ST_MAT_WAITING;
- end
+ if (!in_blank_reg) begin
+ if (matcher_state != ST_MAT_DATA) begin
+ out_data_en <= 0;
+ end
+
+ matcher_state <= ST_MAT_WAITING;
+ end
end else begin
case (matcher_state)
ST_MAT_WAITING: begin
if (in_pxd_pattern_match) begin
matcher_state <= ST_MAT_RX0;
- win_x_int <= scan_x_reg[7];
- win_y_int <= scan_y;
+ if (!matched) begin
+ win_x_int <= scan_x_reg[7];
+ win_y_int <= scan_y;
+ end
end
end
ST_MAT_RX0: begin
matcher_state <= ST_MAT_RX1;
+ win_sof_marker_int <= in_pxd;
end
+
ST_MAT_RX1: begin
matcher_state <= ST_MAT_RX2;
+ if (!matched) begin
+ win_scroll_y_int <= in_pxd;
+ end
end
+
ST_MAT_RX2: begin
matcher_state <= ST_MAT_RX3;
- win_w_int <= in_pxd;
+ if (!matched) begin
+ win_w_int <= in_pxd;
+ end
end
+
ST_MAT_RX3: begin
matcher_state <= ST_MAT_DATA;
- win_h_int <= in_pxd;
- out_data_valid <= 1;
- out_data_en <= 1;
- dval_x_reg <= 13;
- dval_y_reg <= 0;
+ if (!matched) begin
+ matched <= 1;
+ win_h_int <= in_pxd;
+ end
+
+ if (win_sof_marker_int[7]) begin
+ out_data_valid <= 1;
+ out_data_en <= 1;
+
+ end else if (out_data_en) begin
+ out_data_valid <= 1;
+ end
+
+ dval_x_reg <= 13;
end
+
+ ST_MAT_DATA: begin
+ if (out_data_en) begin
+ dval_x_reg <= dval_x_reg + 1;
+ end
+
+ if (dval_x_reg == win_w_int || in_blank) begin
+ out_data_valid <= 0;
+ end
+ end
endcase
end
-
- if (matcher_state == ST_MAT_DATA) begin
- /* blank */
- if (scan_x == win_x_int && out_data_en) begin
- out_data_valid <= 1;
- dval_x_reg <= 1;
-
- end else if (out_data_en) begin
- dval_x_reg <= dval_x_reg + 1;
- end
-
- if (dval_x_reg == win_w_int || in_blank) begin
- out_data_valid <= 0;
- end
-
- if (!in_blank_reg && in_blank) begin
- dval_y_reg <= dval_y_reg + 1;
- end
-
- if (dval_y_reg == win_h_int) begin
- out_data_en <= 0;
- end
- end
end
end
@@ -351,6 +362,7 @@ module window_matcher(
win_y <= 0;
win_right <= 0;
win_bottom <= 0;
+ win_scroll_y <= 0;
end else begin
if (in_vsync_reg == 0 && in_vsync == 1) begin
@@ -363,6 +375,7 @@ module window_matcher(
win_y <= win_y_int;
win_right <= win_x_int + win_w_int + 1;
win_bottom <= win_y_int + win_h_int + 1;
+ win_scroll_y <= win_scroll_y_int;
end else begin
win_w <= 0;
@@ -371,6 +384,7 @@ module window_matcher(
win_y <= 0;
win_right <= 0;
win_bottom <= 0;
+ win_scroll_y <= 0;
end
end
end
diff --git a/demo/fpga/test_bench/window_matcher_tb_gen.ipynb b/demo/fpga/test_bench/window_matcher_tb_gen.ipynb
index ac7847c..0948c0d 100644
--- a/demo/fpga/test_bench/window_matcher_tb_gen.ipynb
+++ b/demo/fpga/test_bench/window_matcher_tb_gen.ipynb
@@ -32,7 +32,7 @@
},
{
"cell_type": "code",
- "execution_count": 55,
+ "execution_count": 61,
"id": "preliminary-virus",
"metadata": {},
"outputs": [],
@@ -104,12 +104,13 @@
" def encode_val(val):\n",
" return np.array([(val//65536)&0xff, (val%65536//256)&0xff, (val%256)&0xff]).astype(int)\n",
" \n",
- " win_data[0, :8, :3] = WINDOW_MAGIC\n",
- " win_data[0, 8, :3] = encode_val(win_x)\n",
- " win_data[0, 9, :3] = encode_val(win_y)\n",
- " win_data[0, 10, :3] = encode_val(win_w)\n",
- " win_data[0, 11, :3] = encode_val(win_h)\n",
- " win_data[0, :12, 3] |= AlphaFlags.WIN_HEADER.value;\n",
+ " for y in range(win_h):\n",
+ " win_data[y, :8, :3] = WINDOW_MAGIC\n",
+ " win_data[y, 8, :3] = encode_val(0x85 if y%3 == 0 else 0)\n",
+ " win_data[y, 9, :3] = encode_val(y)\n",
+ " win_data[y, 10, :3] = encode_val(win_w)\n",
+ " win_data[y, 11, :3] = encode_val(win_h)\n",
+ " win_data[y, :12, 3] |= AlphaFlags.WIN_HEADER.value;\n",
" \n",
" win_h, win_w, _ = win_data.shape\n",
" h, w, _ = fb.shape\n",
@@ -721,7 +722,7 @@
},
{
"cell_type": "code",
- "execution_count": 56,
+ "execution_count": 62,
"id": "7da9e05f-aa7e-42e6-b1ee-2c6453468bf3",
"metadata": {},
"outputs": [
@@ -731,13 +732,13 @@
"(-0.5, 229.5, 109.5, -0.5)"
]
},
- "execution_count": 56,
+ "execution_count": 62,
"metadata": {},
"output_type": "execute_result"
},
{
"data": {
- "image/png": "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\n",
+ "image/png": "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\n",
"text/plain": [
""
]
@@ -757,7 +758,7 @@
},
{
"cell_type": "code",
- "execution_count": 57,
+ "execution_count": 63,
"id": "4d3a1a2d-4b31-47cf-8502-b45ac31a74e0",
"metadata": {},
"outputs": [],
@@ -771,7 +772,7 @@
},
{
"cell_type": "code",
- "execution_count": 58,
+ "execution_count": 64,
"id": "f542f9bc-671b-4b4e-a8f6-ece54783d619",
"metadata": {},
"outputs": [
diff --git a/demo/fw/src/main.c b/demo/fw/src/main.c
index d70c843..e63c53c 100644
--- a/demo/fw/src/main.c
+++ b/demo/fw/src/main.c
@@ -323,7 +323,7 @@ int main(void)
con_printf("Received %d bytes: %s\r\n", rv, rd_buf);
*/
- con_printf_blocking(" #%u", i);
+ con_printf_blocking(" #%u heap memory usage: %zu used / %zu free / %zu fresh blocks", i, ta_num_used(), ta_num_free(), ta_num_fresh());
/*
if (k == 0)
spif_printf(&spif, "\33[1m");
@@ -379,6 +379,13 @@ int main(void)
spif_printf(&spif, "\033[1;91mDecryption error!\033[0m\nInvalid payload size %zx\n", payload_len);
continue;
}
+ con_printf_blocking("Payload size %zu\r\n", payload_len);
+ for (size_t i=0; i
-
-
+
+
+

+
+
+
''').strip()
@@ -84,8 +89,11 @@ def img_to_bytes(img, fmt='png'):
@click.option('--smtp-port', type=int, default=465)
@click.option('-k', '--key', 'keys', multiple=True, required=True)
@click.option('-s', '--subject', default='tachibana/age encrypted message')
+@click.option('--payload-width', type=int, default=300)
+@click.option('--payload-height', type=int)
@click.argument('content', type=click.File('r'))
-def create_age_email(content, sender, recipients, cc, bcc, keys, subject, smtp_server, smtp_port, smtp_user, smtp_password):
+def create_age_email(content, sender, recipients, cc, bcc, keys, subject, smtp_server, smtp_port, smtp_user,
+ smtp_password, payload_width, payload_height):
encrypted = age_encrypt(content.read(), keys)
@@ -106,9 +114,11 @@ def create_age_email(content, sender, recipients, cc, bcc, keys, subject, smtp_s
# remove <...> angle brackets from cids in
tags
msg.set_content(pack_html(payload_img_cid[1:-1], hint_img_data), subtype='html')
- w = max(200, math.ceil(math.sqrt(len(encrypted))))
- h = math.ceil((len(encrypted) + 64) / w)
- img_bytes = img_to_bytes(tb_data_encoder.data_encode(encrypted, w, h))
+ if payload_height is None:
+ payload_height = len(encrypted) // 16 * 16
+ img_bytes = img_to_bytes(tb_data_encoder.data_encode(encrypted, payload_width, payload_height))
+ #with open('/tmp/test.png', 'wb') as f:
+ # f.write(img_bytes)
msg.add_related(img_bytes, 'image', 'png', cid=payload_img_cid)
if not smtp_server:
@@ -122,7 +132,7 @@ def create_age_email(content, sender, recipients, cc, bcc, keys, subject, smtp_s
smtp.login(smtp_user, smtp_password)
smtp.send_message(msg)
smtp.quit()
- print('Message sent!')
+ print('Message sent!', file=sys.stderr)
if __name__ == '__main__':
#print(pack_html('foobar'))
diff --git a/demo/fw/tools/tb_data_encoder.py b/demo/fw/tools/tb_data_encoder.py
index 454aef7..c1a31ec 100644
--- a/demo/fw/tools/tb_data_encoder.py
+++ b/demo/fw/tools/tb_data_encoder.py
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
import sys
+import math
import numpy as np
import click
@@ -22,26 +23,44 @@ def tb_int_to_px(val):
return np.array([(val//0x10000)&0xff, (val//0x100)&0xff, val&0xff], dtype=np.uint8)
def data_encode(data, width, height):
+ HEADER_W = 12
+ assert width > HEADER_W
data = struct.pack('>I', len(data)) + data
data = np.frombuffer(data, dtype=np.uint8)
+ for i in range(len(data) - 4):
+ print(f'{data[i+4]:02x} ', end='')
+ if i%16 == 15 and i > 0:
+ print()
data_expanded = np.repeat(data, 2).reshape((-1, 2))
data_expanded[:, 0] &= 0xf0
data_expanded[:, 1] = (data_expanded[:, 1] & 0x0f) << 4
data_expanded = data_expanded.flatten()
- win = np.zeros([height*width*3], dtype=np.uint8)
- win[12*3:12*3+len(data_expanded)] = data_expanded
- win = win.reshape((height, width, 3))
+ payload_w = width-HEADER_W
+ line_capacity = payload_w*3
+ print(payload_w, line_capacity, line_capacity / 2)
+ block_height = math.ceil(len(data_expanded)/line_capacity)
+ data_expanded = np.hstack([data_expanded, np.zeros(line_capacity*block_height - len(data_expanded), dtype=np.uint8)])
+ block = np.zeros((block_height, payload_w, 3), dtype=np.uint8)
+ block[:,:,:] = data_expanded.reshape((block_height, payload_w, 3))
- win[0, :8] = WINDOW_MAGIC
- win[0, 8] = tb_int_to_px(0)
- win[0, 9] = tb_int_to_px(0)
- win[0, 10] = tb_int_to_px(width)
- win[0, 11] = tb_int_to_px(height)
+ payload_area = np.vstack(
+ [block] * (height // block_height) +
+ [np.zeros((height % block_height, payload_w, 3), dtype=np.uint8)])
+
+ header = np.zeros((height, HEADER_W, 3), dtype=np.uint8)
+ for y in range(height):
+ header[y, :8] = WINDOW_MAGIC
+ if y % block_height == 0 and y + block_height <= height:
+ header[y, 8] = tb_int_to_px(0x88)
+ else:
+ header[y, 8] = tb_int_to_px(0)
+ header[y, 9] = tb_int_to_px(y)
+ header[y, 10] = tb_int_to_px(width)
+ header[y, 11] = tb_int_to_px(height)
- #print('out:', ' '.join(f'{x:02x}' for x in win.flatten()[:256]))
- return Image.fromarray(win)
+ return Image.fromarray(np.hstack([header, payload_area]))
@click.command()
@click.option('-w', '--width', type=int, default=400)