目录
1. 简介
- 本文讨论在 PYNQ 框架下,使用 Python 驱动 Vitis HLS Kernel。
- 使用 Registermap 也可以完成驱动,即直接操作所有寄存器。
- 通过 Python 方式编写的驱动更直观,可以理解为对 Registermap 的封装。
- Registermap 和 Python 驱动,底层都是调用 MMIO 的读写。
2. PixelPacker HLS 实现
2.1 PixelPacker HLS 源码
Pixel Packerhttps://github.com/Xilinx/PYNQ/tree/master/boards/ip/hls/pixel_pack
#include <ap_fixed.h>
#include <ap_int.h>
#include "hls_stream.h"
#include <ap_axi_sdata.h>
typedef ap_axiu<24,1,0,0> narrow_pixel;
typedef ap_axiu<32,1,0,0> wide_pixel;
typedef hls::stream<narrow_pixel> narrow_stream;
typedef hls::stream<wide_pixel> wide_stream;
#define V_24 0
#define V_32 1
#define V_8 2
#define V_16 3
#define V_16C 4
void pixel_pack(narrow_stream& stream_in_24 ,
wide_stream& stream_out_32,
int mode,
ap_uint<8> alpha) {
#pragma HLS INTERFACE mode=axis register_mode=both depth=24 port=stream_in_24 register
#pragma HLS INTERFACE mode=axis register_mode=both depth=24 port=stream_out_32 register
#pragma HLS INTERFACE mode=s_axilite port=mode register
#pragma HLS INTERFACE mode=s_axilite port=alpha register
#pragma HLS INTERFACE mode=ap_ctrl_none port=return
bool last = false;
bool delayed_last = false;
narrow_pixel in_pixel;
wide_pixel out_pixel;
switch (mode) {
case V_24:
while (!delayed_last) {
#pragma HLS pipeline II=4
delayed_last = last;
ap_uint<96> buffer;
ap_uint<4> has_last;
ap_uint<4> has_user;
for (int j = 0; j < 4; ++j) {
if (!last) {
stream_in_24.read(in_pixel);
buffer(j*24 + 23, j*24) = in_pixel.data;
has_user[j] = in_pixel.user;
has_last[j] = in_pixel.last;
last = in_pixel.last;
}
}
if (!delayed_last) {
for (int i = 0; i < 3; ++i) {
out_pixel.data = buffer(i*32 + 31, i*32);
out_pixel.user = has_user[i];
out_pixel.last = has_last[i+1];
stream_out_32.write(out_pixel);
}
}
}
break;
case V_32:
while (!last) {
#pragma HLS pipeline II=1
ap_uint<32> data;
stream_in_24.read(in_pixel);
data(23, 0) = in_pixel.data;
data(31, 24) = alpha;
out_pixel.data = data;
out_pixel.last = in_pixel.last;
out_pixel.user = in_pixel.user;
last = in_pixel.last;
stream_out_32.write(out_pixel);
}
break;
case V_8:
while (!delayed_last) {
#pragma HLS pipeline II=4
delayed_last = last;
bool user = false;
ap_uint<32> data;
for (int i = 0; i < 4; ++i) {
if (!last) {
stream_in_24.read(in_pixel);
user |= in_pixel.user;
last = in_pixel.last;
data(i*8 + 7, i * 8) = in_pixel.data(7,0);
}
}
if (!delayed_last) {
out_pixel.user = user;
out_pixel.last = last;
out_pixel.data = data;
stream_out_32.write(out_pixel);
}
}
break;
case V_16:
while (!last) {
#pragma HLS pipeline II=2
bool user = false;
ap_uint<32> data;
for (int i = 0; i < 2; ++i) {
stream_in_24.read(in_pixel);
user |= in_pixel.user;
last = in_pixel.last;
data(i*16 + 15, i*16) = in_pixel.data(16,0);
}
out_pixel.user = user;
out_pixel.last = last;
out_pixel.data = data;
stream_out_32.write(out_pixel);
}
break;
case V_16C:
while (!last) {
#pragma HLS pipeline II=2
bool user = false;
ap_uint<48> data;
for (int i = 0; i < 2; ++i) {
stream_in_24.read(in_pixel);
user |= in_pixel.user;
last = in_pixel.last;
data(i*24 + 23, i*24) = in_pixel.data;
}
ap_uint<32> out_data;
ap_uint<9> out_c1 = ap_uint<9>(data(15,8)) + ap_uint<9>(data(39,32));
ap_uint<9> out_c2 = ap_uint<9>(data(23,16)) + ap_uint<9>(data(47,40));
out_data(7,0) = data(7,0);
out_data(15,8) = out_c1(8,1);
out_data(23,16) = data(31,24);
out_data(31,24) = out_c2(8,1);
out_pixel.user = user;
out_pixel.last = last;
out_pixel.data = out_data;
stream_out_32.write(out_pixel);
}
break;
}
}
2.2 PixelPacker 功能简介
pixel_pack kernel,从一个输入流 stream_in_24 读取24位像素数据,并根据给定的模式 mode 将这些数据转换和打包成32位的数据,然后将转换后的数据写入到输出流 stream_out_32 中。
Kernel 中定义了五种模式:V_24, V_32, V_8, V_16, V_16C,每种模式都有其特定的处理逻辑。
1). V_24: 这个模式将读取4个24位的像素,将它们合并成一个96位的缓冲区,然后从这个缓冲区中提取出3个32位的像素并写入到输出流中。
2). V_32: 在这个模式中,每个24位的输入像素被扩展到32位,通过在最高的8位加上一个 alpha 值(透明度信息)。然后将这32位的数据写入到输出流中。
3). V_8: 此模式将4个24位的输入像素的最低8位提取出来,并将这些8位数据打包成一个32位的像素。
4). V_16: 在这个模式下,每两个24位的输入像素被组