§ Код адаптера

Используется 64Кб памяти и 1Кб палитры.
/**
 * Общий экран 320 на 200, 256 цветов
 */
module vga
(
    input               clock,
    output  reg [3:0]   r,
    output  reg [3:0]   g,
    output  reg [3:0]   b,
    output              hs,
    output              vs,
    output              vb,         // =1 VBlank
    output  reg [15:0]  a,          // Запрос данных
    input       [ 7:0]  i,          // Цвет точки
    output  reg [ 7:0]  c,          // Запрос цвета
    input       [15:0]  p           // Палитра
);
// -----------------------------------------------------------------------------
// Тайминги для горизонтальной и вертикальной развертки
parameter
//  Visible     Front       Sync        Back        Whole
    hzv =  640, hzf =   16, hzs =   96, hzb =   48, hzw =  800,
    vtv =  400, vtf =   12, vts =    2, vtb =   35, vtw =  449;
// -----------------------------------------------------------------------------
assign hs = x < (hzb + hzv + hzf);
assign vs = y < (vtb + vtv + vtf);
assign vb = x == xmax && y == ymax;
// -----------------------------------------------------------------------------
reg  [ 9:0] x = 0;
reg  [ 9:0] y = 0;
wire [ 9:0] X = x - hzb;
wire [ 9:0] Y = y - vtb;
// -----------------------------------------------------------------------------
wire xmax  = (x == hzw - 1);
wire ymax  = (y == vtw - 1);
wire show  = x >= hzb && x < hzb + hzv && y >= vtb && y < vtb + vtv;
// -----------------------------------------------------------------------------
always @(posedge clock) begin

    // Кадровая развертка
    x <= xmax ?         0 : x + 1;
    y <= xmax ? (ymax ? 0 : y + 1) : y;

    // Каждые 2Т присылается новый цвет из палитры
    if (show) begin

        if (x[0]) begin a <= Y[8:1]*320 + X[9:1]; {r, g, b} <= p; end
        else      begin c <= i; end

    end else {r,g,b} <= 12'h000;

end
endmodule

§ TOP-модуль

  • Подключение VGA к памяти и физическому интерфейсу
  • Блоки памяти 1Кб (палитра) 64Кб (видеобуфер)
wire [15:0] a, p;
wire [ 7:0] i, c;

vga VGA
(
    .clock  (clock_25),
    .r      (VGA_R),
    .g      (VGA_G),
    .b      (VGA_B),
    .hs     (VGA_HS),
    .vs     (VGA_VS),
    .a      (a),
    .i      (i),
    .c      (c),
    .p      (p),
);

m1  M1(.clock(~clock_25), .a(c), .q(p));
m64 M2(.clock(~clock_25), .a(a), .q(i));

§ Утилита создания палитры

Берется некоторое PNG изображение 24-бит размером 1 на 256 пикселей и пропускается сквозь этот скрипт.
  • Аргумент 1 – исходная картинка
  • Аргумент 2 – файл mif, палитра
<?php

$im = imagecreatefrompng($argv[1]);

$m = [
    "WIDTH=16;",
    "DEPTH=256;",
    "ADDRESS_RADIX=HEX;",
    "DATA_RADIX=HEX;",
    "CONTENT BEGIN",
];

for ($y = 0; $y < 256; $y++)
{
    $c = imagecolorat($im, 0, $y);
    $r = ($c >> 16) & 255;
    $g = ($c >>  8) & 255;
    $b = ($c >>  0) & 255;
    $o = ($r>>4)*256 + ($g>>4)*16 + ($b>>4);
    $m[] = sprintf("  %02X: %04X;", $y, $o);
}

$m[] = "END;";

file_put_contents($argv[2], join("\n", $m));

§ Утилита создания 256-цветного образа

Для этого потребуется PNG картинка размером 320 на 200, 256 цветов.
  • Аргумент 1 – исходная картинка
  • Аргумент 2 – файл mif, палитра
  • Аргумент 3 – файл mif, фреймбуфер
<?php

$im = imagecreatefrompng($argv[1]);

function mifhead($a, $b)
{
    return [
        "WIDTH=$a;",
        "DEPTH=$b;",
        "ADDRESS_RADIX=HEX;",
        "DATA_RADIX=HEX;",
        "CONTENT BEGIN",
    ];
}

// -----------------------------------------------------------------------------
// Читаем и пишем палитру
$m = mifhead(16,256);
for ($i = 0; $i < 256; $i++)
{
    $c = imagecolorsforindex($im, $i);
    $r = $c['red'];
    $g = $c['green'];
    $b = $c['blue'];
    $o = ($r>>4)*256 + ($g>>4)*16 + ($b>>4);
    $m[] = sprintf("  %02X: %04X;", $i, $o);
}
$m[] = "END;";
file_put_contents($argv[2], join("\n", $m));

// -----------------------------------------------------------------------------
// Читаем пиксели и пишем пиксели
$m = mifhead(8,65536);
for ($y = 0; $y < 200; $y++)
for ($x = 0; $x < 320; $x++) {
    $m[] = sprintf("  %04X: %02X;", $x + $y*320, imagecolorat($im, $x, $y));
}
$m[] = "  [FA00..FFFF]: 00;";
$m[] = "END;";
file_put_contents($argv[3], join("\n", $m));