ライン描画回路を作ってみる
今日は簡単なネタで。
Vivado HLS で昔懐かしい Bresenham line アルゴリズムを実装してみました。
simpleLine.c として、
#include "ap_cint.h" #define SCREEN_WIDTH (640) #define abs(x) (((x) >= 0) ? (x) : (-x)) #define sgn(x, y) (((x) > 0) ? (y) : ((x) < 0) ? (-y) : 0) void simpleLine(volatile unsigned short *vram, short xpos, short ypos, short dx, short dy, unsigned short count, unsigned short color) { unsigned short c; short delta = 0; unsigned short adx = abs(dx); unsigned short ady = abs(dy); int sdx = sgn(dx, 1); int sdy = sgn(dy, SCREEN_WIDTH); short a, b; int sx, sy; vram = vram + ypos * SCREEN_WIDTH + xpos; if (adx >= ady) { a = adx; b = ady; sx = sdx; sy = sdy; } else { a = ady; b = adx; sx = sdy; sy = sdx; } loop_count: for (c = 0; c < count; ++c) { *vram = color; vram = vram + sx; delta = delta + (b << 1); vram = vram + ((delta >= a) ? sy : 0); delta = delta - ((delta >= a) ? (a << 1) : 0); } }
とし、テストベンチを tb_simpleLine.c として
#include <stdio.h> #include <math.h> #define SCREEN_WIDTH (640) #define SCREEN_HEIGHT (480) #define LINE_LENGTH (100.0) #define INNER_LENGTH (10.0) #define VGACOLOR(c,p) ((c >> p) & 0xf) static void line(volatile unsigned short *vram, short xpos, short ypos, short dx, short dy, unsigned short count, unsigned short color) { simpleLine(vram, xpos, ypos, dx, dy, count, color); } static void drawLine(volatile unsigned short *vram, short xs, short ys, short xe, short ye, unsigned color) { short dx = xe - xs; short dy = ye - ys; unsigned short count = (abs(dx) >= abs(dy)) ? abs(dx): abs(dy); line(vram, xs, ys, dx, dy, count, color); } static void clearScreen(volatile unsigned short *vram) { int pos; for (pos = 0; pos < SCREEN_WIDTH * SCREEN_HEIGHT; ++pos) { vram[pos] = 0; } } int main() { static unsigned short v[SCREEN_WIDTH * SCREEN_HEIGHT]; static unsigned short color[] = { 0x00f, 0x0f0, 0xf00, 0xf0f, 0x0ff, 0xf0f, 0xfff, 0x008, 0x080, 0x800, 0x808, 0x088, 0x808, 0x888 }; int i, j; int xh = SCREEN_WIDTH / 2; int yh = SCREEN_HEIGHT / 2; FILE *f; clearScreen(&v[0]); for (i = 0, j = 0; i < 360; i = i + 30, j = j + 1) { double c = cos(i * M_PI / 180.0); double s = sin(i * M_PI / 180.0); int x = xh + INNER_LENGTH * c; int y = yh + INNER_LENGTH * s; line(&v[0], x, y, (short)(c * 10000.0), (short)(s * 10000.0), LINE_LENGTH, color[j]); } drawLine(&v[0], 0, 0, 639, 20, 0xfff); drawLine(&v[0], 0, 20, 639, 0, 0xf00); drawLine(&v[0], 0, 0, 20, 479, 0x0f0); drawLine(&v[0], 20, 0, 0, 479, 0x00f); f = fopen("localram.ppm", "wb"); fprintf(f, "P6\n640 480\n15\n"); for (i = 0; i < SCREEN_WIDTH * SCREEN_HEIGHT; ++i) { fprintf(f, "%c", VGACOLOR(v[i], 8)); fprintf(f, "%c", VGACOLOR(v[i], 4)); fprintf(f, "%c", VGACOLOR(v[i], 0)); } fclose(f); return 0; }
と定義します。(テストベンチ中で ppm ファイルを出力してチェックするように設定)
Vivado HLS で論理合成したところ、LUT 400 個ほどで実装できました。
(メモリアクセスは ap_bus を使用)
for 文は semi perfect loop になるように作ってあるので、PIPELINE 指定が可能です。
実際に指定してみると回路規模はそのままで latency をドット数 + 5 くらいに抑えることが
できました。