§ Главный шаблон

Скачать весь шаблон можно тут.
module max2
(
    input           clock,
    input   [3:0]   key,
    inout   [7:0]   led,
    inout   [9:0]   f0,
    inout   [9:0]   f1,
    inout   [9:0]   f2,
    inout   [9:0]   f3,
    inout   [9:0]   f4,
    inout   [9:0]   f5,
    inout           dp,
    inout           dn,
    inout           pt
);

assign f0 = 10'hz; assign f1 = 10'hz; assign f2 = 10'hz;
assign f3 = 10'hz; assign f4 = 10'hz; assign f5 = 10'hz;

wire [15:0] datain;
wire        ready;

altufm_reader UFMReaderUnit
(
    .osc        (osc),
    .address    (9'h1),
    .datain     (datain),
    .ready      (ready)
);

endmodule

§ Блок AltUFM

Этот блок инициализирует физический модуль ufm.
//synopsys translate_off
`timescale 1 ps / 1 ps

//synopsys translate_on
module altufm
(
    input   arclk,      // Запись на позитивном фронте АДРЕС
    input   ardin,      // Входящий бит адреса (MSB), первый бит старший
    input   arshft,     // =1 последовательная загрузка адреса, =0 то +1 к адресу
    output  busy,       // =1 Устройство занято
    input   drclk,      // Запись на позитивном фронте ДАННЫХ
    input   drdin,      // Входящие бит MSB
    output  drdout,     // Исходящий бит MSB
    input   drshft,     // =0 @posedge drclk, копирование из/в UFM, =1 вдвиг бита
    input   erase,      // =1 очистить блок
    output  osc,        // Тактовый осциллятор ~ 5.5 Мгц
    input   oscena,     // =1 Разрешение тактового генератора
    input   program,    // =1 Программирование UFM
    output  rtpbusy     // =1 Устройство занято программированием
);

maxii_ufm maxii_ufm_block1
(
    .arclk          (arclk),
    .ardin          (ardin),
    .arshft         (arshft),
    .bgpbusy        (rtpbusy),
    .busy           (busy),
    .drclk          (drclk),
    .drdin          (drdin),
    .drdout         (drdout),
    .drshft         (drshft),
    .erase          (erase),
    .osc            (osc),
    .oscena         (oscena),
    .program        (program),
    // synopsys translate_off
    .ctrl_bgpbusy   (1'b0),
    .devclrn        (1'b1),
    .devpor         (1'b1),
    .sbdin          (1'b0),
    .sbdout         ()
    // synopsys translate_on
);

defparam
    maxii_ufm_block1.address_width   = 9,
    maxii_ufm_block1.erase_time      = 500000000,
    maxii_ufm_block1.init_file       = "ufm.mif",
    // Копия тестовых данных 1Кб
    maxii_ufm_block1.mem1            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem2            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem3            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem4            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem5            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem6            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem7            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem8            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem9            = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem10           = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem11           = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem12           = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem13           = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem14           = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem15           = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.mem16           = 512'hFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF,
    maxii_ufm_block1.osc_sim_setting = 180000,
    maxii_ufm_block1.program_time    = 1600000,
    maxii_ufm_block1.lpm_type        = "maxii_ufm";

endmodule

§ Работа с UFM

Когда приходит сигнал ready, тогда можно установить новый адрес сразу же и получить данные.
Top-уровень
wire [15:0] datain;
wire        ready;

altufm_reader UFMReaderUnit
(
    .osc        (osc),
    .address    (9'h1),
    .datain     (datain),
    .ready      (ready)
);
Модуль считывания
module altufm_reader
(
    output              osc,            // Осциллятор
    input        [8:0]  address,        // Заданный адрес
    output  reg  [15:0] datain,         // Полученные данные
    output              ready           // Признак готовности данных
);

assign      ready = (cnt == 27);
reg [4:0]   cnt     = 1'b0;
reg         ardin   = 1'b0;
reg         drshft  = 1'b0;
wire        drdout;

altufm AltUFMUnit
(
    .arclk  (osc),
    .drclk  (osc),
    .drdin  (1'b0),     // Данные для программирования Flash
    .drdout (drdout),   // Выходные данные
    .drshft (drshft),   // 0: Защелка, 1: Задвижка
    .ardin  (ardin),    // Данные для адреса
    .arshft (1'b1),     // Всегда последовательный адрес
    .oscena (1'b1),     // Активировать осциллятор
    .osc    (osc)       // Осциллятор 5.56 Мгц
);

always @(posedge osc)
begin

    cnt    <= cnt + 1;
    drshft <= cnt > 9;
    ardin  <= cnt < 9 ? address[8 - cnt] : 1'b0;
    datain <= {datain[14:0], drdout};

    // Данные готовы
    if (ready) cnt <= 0;

end

endmodule

§ Эмулятор UFM

Здесь osc — это input-провод, поскольку osc задается в tb.v
module altufm
(
    input   wire    oscena,
    input   wire    osc,

    input   wire    arclk,
    input   wire    ardin,
    input   wire    arshft,

    input   wire    drclk,
    input   wire    drdin,
    input   wire    drshft,
    output  wire    drdout,

    input   wire    prgram
);

// ---------------------------------------------------------------------
reg [15:0] ufm[512];
initial begin $readmemh("ufm.hex", ufm, 0); end
// ---------------------------------------------------------------------

assign drdout = datareg[15];

// 512 x 16 = 1024 байт памяти
reg [ 8:0] address;
reg [15:0] datareg;

// Вдвиг адреса или увеличение на +1
always @(posedge arclk)
    address <= arshft ? {address[7:0], ardin} : address + 1;

always @(posedge drclk or posedge prgram)
if (prgram)
    ufm[address] <= datareg;
else if (drshft)
    datareg <= {datareg[14:0], drdin};
else
    datareg <= ufm[address];

endmodule