added files
This commit is contained in:
parent
72ba761443
commit
940920d18b
6
.gitignore
vendored
6
.gitignore
vendored
@ -102,6 +102,12 @@
|
||||
*.html
|
||||
*/*/bd/*/ip/*/*.tcl
|
||||
*/*/*/bd/*/ip/*/*.tcl
|
||||
db/
|
||||
incremental_db/
|
||||
output_files/
|
||||
*.sof
|
||||
*.pof
|
||||
*.qws
|
||||
hw_handoff
|
||||
ipshared
|
||||
|
||||
|
||||
101
Logic2_D7.csv
Normal file
101
Logic2_D7.csv
Normal file
@ -0,0 +1,101 @@
|
||||
Time [s],D7
|
||||
0.0000000000000000,0
|
||||
0.0000000010000000,0
|
||||
0.0000000020000000,1
|
||||
0.0000000030000000,1
|
||||
0.0000000040000000,0
|
||||
0.0000000050000000,0
|
||||
0.0000000060000000,1
|
||||
0.0000000070000000,1
|
||||
0.0000000080000000,0
|
||||
0.0000000090000000,0
|
||||
0.0000000100000000,1
|
||||
0.0000000110000000,1
|
||||
0.0000000120000000,0
|
||||
0.0000000130000000,0
|
||||
0.0000000140000000,1
|
||||
0.0000000150000000,1
|
||||
0.0000000160000000,0
|
||||
0.0000000170000000,0
|
||||
0.0000000180000000,1
|
||||
0.0000000190000000,1
|
||||
0.0000000200000000,0
|
||||
0.0000000210000000,0
|
||||
0.0000000220000000,1
|
||||
0.0000000230000000,1
|
||||
0.0000000240000000,0
|
||||
0.0000000250000000,0
|
||||
0.0000000260000000,1
|
||||
0.0000000270000000,1
|
||||
0.0000000280000000,0
|
||||
0.0000000290000000,0
|
||||
0.0000000300000000,1
|
||||
0.0000000310000000,1
|
||||
0.0000000320000000,0
|
||||
0.0000000330000000,0
|
||||
0.0000000340000000,1
|
||||
0.0000000350000000,1
|
||||
0.0000000360000000,0
|
||||
0.0000000370000000,0
|
||||
0.0000000380000000,1
|
||||
0.0000000390000000,1
|
||||
0.0000000400000000,0
|
||||
0.0000000410000000,0
|
||||
0.0000000420000000,1
|
||||
0.0000000430000000,1
|
||||
0.0000000440000000,0
|
||||
0.0000000450000000,0
|
||||
0.0000000460000000,1
|
||||
0.0000000470000000,1
|
||||
0.0000000480000000,0
|
||||
0.0000000490000000,0
|
||||
0.0000000500000000,1
|
||||
0.0000000510000000,1
|
||||
0.0000000520000000,0
|
||||
0.0000000530000000,0
|
||||
0.0000000540000000,1
|
||||
0.0000000550000000,1
|
||||
0.0000000560000000,0
|
||||
0.0000000570000000,0
|
||||
0.0000000580000000,1
|
||||
0.0000000590000000,1
|
||||
0.0000000600000000,0
|
||||
0.0000000610000000,0
|
||||
0.0000000620000000,1
|
||||
0.0000000630000000,1
|
||||
0.0000000640000000,0
|
||||
0.0000000650000000,0
|
||||
0.0000000660000000,1
|
||||
0.0000000670000000,1
|
||||
0.0000000680000000,0
|
||||
0.0000000690000000,0
|
||||
0.0000000700000000,1
|
||||
0.0000000710000000,1
|
||||
0.0000000720000000,0
|
||||
0.0000000730000000,0
|
||||
0.0000000740000000,1
|
||||
0.0000000750000000,1
|
||||
0.0000000760000000,0
|
||||
0.0000000770000000,0
|
||||
0.0000000780000000,1
|
||||
0.0000000790000000,1
|
||||
0.0000000800000000,0
|
||||
0.0000000810000000,0
|
||||
0.0000000820000000,1
|
||||
0.0000000830000000,1
|
||||
0.0000000840000000,0
|
||||
0.0000000850000000,0
|
||||
0.0000000860000000,1
|
||||
0.0000000870000000,1
|
||||
0.0000000880000000,0
|
||||
0.0000000890000000,0
|
||||
0.0000000900000000,1
|
||||
0.0000000910000000,1
|
||||
0.0000000920000000,0
|
||||
0.0000000930000000,0
|
||||
0.0000000940000000,1
|
||||
0.0000000950000000,1
|
||||
0.0000000960000000,0
|
||||
0.0000000970000000,0
|
||||
0.0000000980000000,1
|
||||
0.0000000990000000,1
|
||||
|
30
Logic2_to_FPGA.qpf
Normal file
30
Logic2_to_FPGA.qpf
Normal file
@ -0,0 +1,30 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Copyright (C) 1991-2013 Altera Corporation
|
||||
# Your use of Altera Corporation's design tools, logic functions
|
||||
# and other software and tools, and its AMPP partner logic
|
||||
# functions, and any output files from any of the foregoing
|
||||
# (including device programming or simulation files), and any
|
||||
# associated documentation or information are expressly subject
|
||||
# to the terms and conditions of the Altera Program License
|
||||
# Subscription Agreement, Altera MegaCore Function License
|
||||
# Agreement, or other applicable license agreement, including,
|
||||
# without limitation, that your use is for the sole purpose of
|
||||
# programming logic devices manufactured by Altera and sold by
|
||||
# Altera or its authorized distributors. Please refer to the
|
||||
# applicable agreement for further details.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Quartus II 64-Bit
|
||||
# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition
|
||||
# Date created = 05:32:19 June 01, 2026
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
|
||||
QUARTUS_VERSION = "13.1"
|
||||
DATE = "05:32:19 June 01, 2026"
|
||||
|
||||
# Revisions
|
||||
|
||||
PROJECT_REVISION = "Logic2_to_FPGA"
|
||||
71
Logic2_to_FPGA.qsf
Normal file
71
Logic2_to_FPGA.qsf
Normal file
@ -0,0 +1,71 @@
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Copyright (C) 1991-2013 Altera Corporation
|
||||
# Your use of Altera Corporation's design tools, logic functions
|
||||
# and other software and tools, and its AMPP partner logic
|
||||
# functions, and any output files from any of the foregoing
|
||||
# (including device programming or simulation files), and any
|
||||
# associated documentation or information are expressly subject
|
||||
# to the terms and conditions of the Altera Program License
|
||||
# Subscription Agreement, Altera MegaCore Function License
|
||||
# Agreement, or other applicable license agreement, including,
|
||||
# without limitation, that your use is for the sole purpose of
|
||||
# programming logic devices manufactured by Altera and sold by
|
||||
# Altera or its authorized distributors. Please refer to the
|
||||
# applicable agreement for further details.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Quartus II 64-Bit
|
||||
# Version 13.1.0 Build 162 10/23/2013 SJ Web Edition
|
||||
# Date created = 05:32:19 June 01, 2026
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
#
|
||||
# Notes:
|
||||
#
|
||||
# 1) The default values for assignments are stored in the file:
|
||||
# Logic2_to_FPGA_assignment_defaults.qdf
|
||||
# If this file doesn't exist, see file:
|
||||
# assignment_defaults.qdf
|
||||
#
|
||||
# 2) Altera recommends that you do not modify this file. This
|
||||
# file is updated automatically by the Quartus II software
|
||||
# and any changes you make may be lost or overwritten.
|
||||
#
|
||||
# -------------------------------------------------------------------------- #
|
||||
|
||||
|
||||
set_global_assignment -name FAMILY "Cyclone IV E"
|
||||
set_global_assignment -name DEVICE EP4CE6E22C8
|
||||
set_global_assignment -name TOP_LEVEL_ENTITY top
|
||||
set_global_assignment -name ORIGINAL_QUARTUS_VERSION 13.1
|
||||
set_global_assignment -name PROJECT_CREATION_TIME_DATE "05:32:19 JUNE 01, 2026"
|
||||
set_global_assignment -name LAST_QUARTUS_VERSION 13.1
|
||||
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
|
||||
set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0
|
||||
set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85
|
||||
set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1
|
||||
set_global_assignment -name NOMINAL_CORE_SUPPLY_VOLTAGE 1.2V
|
||||
set_global_assignment -name EDA_SIMULATION_TOOL "ModelSim-Altera (Verilog)"
|
||||
set_global_assignment -name EDA_TIME_SCALE "1 ps" -section_id eda_simulation
|
||||
set_global_assignment -name EDA_OUTPUT_DATA_FORMAT "VERILOG HDL" -section_id eda_simulation
|
||||
set_global_assignment -name POWER_PRESET_COOLING_SOLUTION "23 MM HEAT SINK WITH 200 LFPM AIRFLOW"
|
||||
set_global_assignment -name POWER_BOARD_THERMAL_MODEL "NONE (CONSERVATIVE)"
|
||||
set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top
|
||||
set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top
|
||||
set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top
|
||||
set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "2.5 V"
|
||||
set_location_assignment PIN_23 -to CLK50
|
||||
set_location_assignment PIN_87 -to GPIO0
|
||||
set_location_assignment PIN_7 -to KEY0
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to CLK50
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to GPIO0
|
||||
set_instance_assignment -name IO_STANDARD "3.3-V LVTTL" -to KEY0
|
||||
set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top
|
||||
set_global_assignment -name SOURCE_FILE Logic2_to_FPGA.qpf
|
||||
set_global_assignment -name SOURCE_FILE Logic2_to_FPGA.qsf
|
||||
set_global_assignment -name SDC_FILE omdazz.sdc
|
||||
set_global_assignment -name VERILOG_FILE top.v
|
||||
set_global_assignment -name VERILOG_FILE pattern_rom.v
|
||||
set_global_assignment -name VERILOG_FILE pattern_player.v
|
||||
3
omdazz.sdc
Normal file
3
omdazz.sdc
Normal file
@ -0,0 +1,3 @@
|
||||
create_clock -period 20 -name clk [get_ports clk]
|
||||
|
||||
|
||||
82
pattern_player.v
Normal file
82
pattern_player.v
Normal file
@ -0,0 +1,82 @@
|
||||
// pattern_player.v
|
||||
// Проигрывает один раз последовательность сегментов из pattern_rom.
|
||||
|
||||
module pattern_player #(
|
||||
parameter TICKS_WIDTH = 32,
|
||||
parameter DEPTH = 128
|
||||
)(
|
||||
input wire clk,
|
||||
input wire rst,
|
||||
input wire start, // 1 → начать воспроизведение
|
||||
output reg out, // выход на пин
|
||||
output reg busy // 1, пока идёт воспроизведение
|
||||
);
|
||||
|
||||
// Адрес в ROM
|
||||
reg [$clog2(DEPTH)-1:0] addr;
|
||||
|
||||
// Текущие {level, ticks}
|
||||
reg [TICKS_WIDTH:0] cur_data;
|
||||
reg [TICKS_WIDTH-1:0] ticks_cnt;
|
||||
|
||||
wire [TICKS_WIDTH:0] rom_data;
|
||||
|
||||
// Экземпляр ROM (Автогенерированный pattern_rom.v от Python-скрипта)
|
||||
pattern_rom #(
|
||||
.TICKS_WIDTH(TICKS_WIDTH),
|
||||
.DEPTH(DEPTH)
|
||||
) rom_inst (
|
||||
.addr(addr),
|
||||
.data(rom_data)
|
||||
);
|
||||
|
||||
// Простая машина состояний
|
||||
localparam IDLE = 2'd0;
|
||||
localparam LOAD = 2'd1;
|
||||
localparam RUN = 2'd2;
|
||||
|
||||
reg [1:0] state;
|
||||
|
||||
always @(posedge clk or posedge rst) begin
|
||||
if (rst) begin
|
||||
state <= IDLE;
|
||||
addr <= 0;
|
||||
ticks_cnt <= 0;
|
||||
out <= 0;
|
||||
busy <= 0;
|
||||
end else begin
|
||||
case (state)
|
||||
IDLE: begin
|
||||
busy <= 0;
|
||||
if (start) begin
|
||||
addr <= 0;
|
||||
state <= LOAD;
|
||||
busy <= 1;
|
||||
end
|
||||
end
|
||||
|
||||
LOAD: begin
|
||||
cur_data <= rom_data;
|
||||
out <= rom_data[TICKS_WIDTH]; // уровень
|
||||
ticks_cnt <= rom_data[TICKS_WIDTH-1:0]; // длительность
|
||||
state <= RUN;
|
||||
end
|
||||
|
||||
RUN: begin
|
||||
if (ticks_cnt == 0) begin
|
||||
if (addr == DEPTH - 1) begin
|
||||
// Проиграли все сегменты один раз → назад в IDLE
|
||||
state <= IDLE;
|
||||
end else begin
|
||||
addr <= addr + 1;
|
||||
state <= LOAD;
|
||||
end
|
||||
end else begin
|
||||
ticks_cnt <= ticks_cnt - 1;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
69
pattern_rom.v
Normal file
69
pattern_rom.v
Normal file
@ -0,0 +1,69 @@
|
||||
// Автогенерация из CSV: Logic2_D7.csv
|
||||
// F_CLK_HZ = 48000000
|
||||
// Количество сегментов (DEPTH) = 50
|
||||
|
||||
module pattern_rom #(
|
||||
parameter TICKS_WIDTH = 32,
|
||||
parameter DEPTH = 50
|
||||
) (
|
||||
input wire [$clog2(DEPTH)-1:0] addr,
|
||||
output reg [TICKS_WIDTH:0] data // {level[MSB], ticks[LSB:0]}
|
||||
);
|
||||
|
||||
// Простейший ROM на case по адресу
|
||||
always @* begin
|
||||
case (addr)
|
||||
0: data = {1'b0, 32'd1};
|
||||
1: data = {1'b1, 32'd1};
|
||||
2: data = {1'b0, 32'd1};
|
||||
3: data = {1'b1, 32'd1};
|
||||
4: data = {1'b0, 32'd1};
|
||||
5: data = {1'b1, 32'd1};
|
||||
6: data = {1'b0, 32'd1};
|
||||
7: data = {1'b1, 32'd1};
|
||||
8: data = {1'b0, 32'd1};
|
||||
9: data = {1'b1, 32'd1};
|
||||
10: data = {1'b0, 32'd1};
|
||||
11: data = {1'b1, 32'd1};
|
||||
12: data = {1'b0, 32'd1};
|
||||
13: data = {1'b1, 32'd1};
|
||||
14: data = {1'b0, 32'd1};
|
||||
15: data = {1'b1, 32'd1};
|
||||
16: data = {1'b0, 32'd1};
|
||||
17: data = {1'b1, 32'd1};
|
||||
18: data = {1'b0, 32'd1};
|
||||
19: data = {1'b1, 32'd1};
|
||||
20: data = {1'b0, 32'd1};
|
||||
21: data = {1'b1, 32'd1};
|
||||
22: data = {1'b0, 32'd1};
|
||||
23: data = {1'b1, 32'd1};
|
||||
24: data = {1'b0, 32'd1};
|
||||
25: data = {1'b1, 32'd1};
|
||||
26: data = {1'b0, 32'd1};
|
||||
27: data = {1'b1, 32'd1};
|
||||
28: data = {1'b0, 32'd1};
|
||||
29: data = {1'b1, 32'd1};
|
||||
30: data = {1'b0, 32'd1};
|
||||
31: data = {1'b1, 32'd1};
|
||||
32: data = {1'b0, 32'd1};
|
||||
33: data = {1'b1, 32'd1};
|
||||
34: data = {1'b0, 32'd1};
|
||||
35: data = {1'b1, 32'd1};
|
||||
36: data = {1'b0, 32'd1};
|
||||
37: data = {1'b1, 32'd1};
|
||||
38: data = {1'b0, 32'd1};
|
||||
39: data = {1'b1, 32'd1};
|
||||
40: data = {1'b0, 32'd1};
|
||||
41: data = {1'b1, 32'd1};
|
||||
42: data = {1'b0, 32'd1};
|
||||
43: data = {1'b1, 32'd1};
|
||||
44: data = {1'b0, 32'd1};
|
||||
45: data = {1'b1, 32'd1};
|
||||
46: data = {1'b0, 32'd1};
|
||||
47: data = {1'b1, 32'd1};
|
||||
48: data = {1'b0, 32'd1};
|
||||
49: data = {1'b1, 32'd1};
|
||||
default: data = {1'b0, {TICKS_WIDTH{1'b0}}};
|
||||
endcase
|
||||
end
|
||||
endmodule
|
||||
244
to_FPGA.py
Normal file
244
to_FPGA.py
Normal file
@ -0,0 +1,244 @@
|
||||
import csv
|
||||
from pathlib import Path
|
||||
|
||||
# ==========================
|
||||
# НАСТРОЙКИ ПОЛЬЗОВАТЕЛЯ
|
||||
# ==========================
|
||||
|
||||
# Входной файл из Logic 2 (CSV только с Time [s] и D7)
|
||||
CSV_FILE = "Logic2_D7.csv"
|
||||
|
||||
# Выходной Verilog-файл
|
||||
VERILOG_FILE = "pattern_rom.v"
|
||||
|
||||
# Тактовая частота в МК/FPGA, Гц (должна совпадать с тем, что реально в железе)
|
||||
F_CLK_HZ = 48_000_000 # пример: 48 МГц
|
||||
|
||||
# Имена колонок в CSV (посмотри заголовок в своём файле и подгони при необходимости)
|
||||
TIME_COL = "Time [s]" # колонка с временем
|
||||
LEVEL_COL = "D7" # колонка с уровнем сигнала
|
||||
|
||||
# Сколько бит отвести под счётчик тиков в Verilog
|
||||
TICKS_WIDTH = 32
|
||||
|
||||
|
||||
# ==========================
|
||||
# ЧТЕНИЕ CSV ИЗ LOGIC 2
|
||||
# ==========================
|
||||
|
||||
def read_digital_trace(csv_path: str):
|
||||
"""
|
||||
Читает CSV-файл в формате Logic 2 и возвращает два списка:
|
||||
times[i] - время в секундах (float),
|
||||
levels[i] - уровень (0 или 1) в моменты времени times[i].
|
||||
|
||||
Ожидается, что первая строка CSV — заголовок с колонками TIME_COL и LEVEL_COL.
|
||||
"""
|
||||
times = []
|
||||
levels = []
|
||||
|
||||
with open(csv_path, newline="") as f:
|
||||
reader = csv.DictReader(f)
|
||||
|
||||
# Проверяем наличие нужных столбцов
|
||||
if TIME_COL not in reader.fieldnames or LEVEL_COL not in reader.fieldnames:
|
||||
raise RuntimeError(
|
||||
f"В CSV нет ожидаемых колонок '{TIME_COL}' и/или '{LEVEL_COL}'. "
|
||||
f"Найденные столбцы: {reader.fieldnames}"
|
||||
)
|
||||
|
||||
# Проходим по всем строкам после заголовка
|
||||
for row in reader:
|
||||
# Время
|
||||
t = float(row[TIME_COL])
|
||||
# Уровень (0 или 1)
|
||||
lvl = int(row[LEVEL_COL])
|
||||
|
||||
times.append(t)
|
||||
levels.append(lvl)
|
||||
|
||||
if not times:
|
||||
raise RuntimeError("CSV пустой или не содержит данных (только заголовок).")
|
||||
|
||||
return times, levels
|
||||
|
||||
|
||||
# ==========================
|
||||
# ПОСТРОЕНИЕ СЕГМЕНТОВ
|
||||
# ==========================
|
||||
|
||||
def build_segments(times, levels):
|
||||
"""
|
||||
Строит сегменты постоянного уровня.
|
||||
|
||||
На входе:
|
||||
times[i], levels[i] — выборки (временная метка + уровень).
|
||||
|
||||
На выходе:
|
||||
segments: список кортежей (level, duration_sec), где:
|
||||
level — 0 или 1,
|
||||
duration_sec — длительность в секундах (> 0).
|
||||
|
||||
Пример:
|
||||
times = [0.0, 1e-6, 2e-6, 3e-6]
|
||||
levels = [0, 0, 1, 1 ]
|
||||
|
||||
→ segments = [(0, 2e-6), (1, 1e-6)]
|
||||
"""
|
||||
segments = []
|
||||
|
||||
current_level = levels[0]
|
||||
start_time = times[0]
|
||||
|
||||
# Идём по всем точкам, начиная со второй
|
||||
for i in range(1, len(times)):
|
||||
t = times[i]
|
||||
lvl = levels[i]
|
||||
|
||||
# Если уровень поменялся — значит, закончился сегмент
|
||||
if lvl != current_level:
|
||||
duration = t - start_time
|
||||
if duration > 0:
|
||||
segments.append((current_level, duration))
|
||||
# Начинаем новый сегмент с новым уровнем
|
||||
start_time = t
|
||||
current_level = lvl
|
||||
|
||||
# Последний сегмент: от последней смены до конца записи
|
||||
end_time = times[-1]
|
||||
duration = end_time - start_time
|
||||
if duration > 0:
|
||||
segments.append((current_level, duration))
|
||||
|
||||
# Если ни одного сегмента не получилось (например, уровень вообще не менялся)
|
||||
if not segments:
|
||||
full_duration = times[-1] - times[0]
|
||||
if full_duration <= 0:
|
||||
raise RuntimeError("Не удалось построить сегменты: время не растёт.")
|
||||
segments.append((levels[0], full_duration))
|
||||
|
||||
return segments
|
||||
|
||||
|
||||
# ==========================
|
||||
# КВАНТОВАНИЕ В ТИКИ
|
||||
# ==========================
|
||||
|
||||
def quantize_segments(segments, f_clk_hz: float):
|
||||
"""
|
||||
Переводит длительность сегментов из секунд в количество тиков таймера.
|
||||
|
||||
На входе:
|
||||
segments: список (level, duration_sec)
|
||||
|
||||
На выходе:
|
||||
segments_ticks: список (level, ticks)
|
||||
ticks — целое положительное число (>= 1)
|
||||
"""
|
||||
result = []
|
||||
|
||||
for idx, (level, duration_sec) in enumerate(segments):
|
||||
# Перевод секунд в тики
|
||||
ticks = round(duration_sec * f_clk_hz)
|
||||
|
||||
# Страховка от нулевой длительности
|
||||
if ticks <= 0:
|
||||
ticks = 1
|
||||
|
||||
result.append((level, ticks))
|
||||
|
||||
return result
|
||||
|
||||
|
||||
# ==========================
|
||||
# ГЕНЕРАЦИЯ VERILOG ROM
|
||||
# ==========================
|
||||
|
||||
def generate_verilog_rom(segments_ticks, out_path: str):
|
||||
"""
|
||||
Генерирует Verilog-модуль pattern_rom с ROM вида:
|
||||
data = {level, ticks}, где
|
||||
level — самый старший бит (1 бит),
|
||||
ticks — младшие TICKS_WIDTH бит.
|
||||
|
||||
Интерфейс модуля:
|
||||
module pattern_rom #(
|
||||
parameter TICKS_WIDTH = ...,
|
||||
parameter DEPTH = ...
|
||||
)(
|
||||
input wire [$clog2(DEPTH)-1:0] addr,
|
||||
output reg [TICKS_WIDTH:0] data
|
||||
);
|
||||
|
||||
// data[TICKS_WIDTH] - уровень (0 или 1)
|
||||
// data[TICKS_WIDTH-1:0] - ticks
|
||||
"""
|
||||
depth = len(segments_ticks)
|
||||
|
||||
lines = []
|
||||
lines.append(f"// Автогенерация из CSV: {CSV_FILE}")
|
||||
lines.append(f"// F_CLK_HZ = {F_CLK_HZ}")
|
||||
lines.append(f"// Количество сегментов (DEPTH) = {depth}")
|
||||
lines.append("")
|
||||
lines.append("module pattern_rom #(")
|
||||
lines.append(f" parameter TICKS_WIDTH = {TICKS_WIDTH},")
|
||||
lines.append(f" parameter DEPTH = {depth}")
|
||||
lines.append(") (")
|
||||
lines.append(" input wire [$clog2(DEPTH)-1:0] addr,")
|
||||
lines.append(" output reg [TICKS_WIDTH:0] data // {level[MSB], ticks[LSB:0]}")
|
||||
lines.append(");")
|
||||
lines.append("")
|
||||
lines.append(" // Простейший ROM на case по адресу")
|
||||
lines.append(" always @* begin")
|
||||
lines.append(" case (addr)")
|
||||
|
||||
for i, (level, ticks) in enumerate(segments_ticks):
|
||||
# Проверяем, помещается ли длительность в TICKS_WIDTH бит
|
||||
if ticks >= (1 << TICKS_WIDTH):
|
||||
raise ValueError(
|
||||
f"Сегмент {i}: ticks={ticks} не помещается в {TICKS_WIDTH} бит. "
|
||||
"Увеличьте TICKS_WIDTH или уменьшите F_CLK_HZ."
|
||||
)
|
||||
|
||||
# Строка ROM:
|
||||
# i: data = {1'bL, TICKS_WIDTH'dticks};
|
||||
lines.append(
|
||||
f" {i}: data = {{1'b{level}, {TICKS_WIDTH}'d{ticks}}};"
|
||||
)
|
||||
|
||||
# Значение по умолчанию (на всякий случай)
|
||||
lines.append(" default: data = {1'b0, {TICKS_WIDTH{1'b0}}};")
|
||||
lines.append(" endcase")
|
||||
lines.append(" end")
|
||||
lines.append("endmodule")
|
||||
lines.append("")
|
||||
|
||||
# Запись Verilog-файла
|
||||
Path(out_path).write_text("\n".join(lines), encoding="utf-8")
|
||||
|
||||
|
||||
# ==========================
|
||||
# ТОЧКА ВХОДА
|
||||
# ==========================
|
||||
|
||||
def main():
|
||||
# 1. Читаем CSV Logic 2
|
||||
times, levels = read_digital_trace(CSV_FILE)
|
||||
|
||||
# 2. Строим сегменты постоянного уровня
|
||||
segments = build_segments(times, levels)
|
||||
|
||||
# 3. Переводим длительность сегментов в тики тактового генератора
|
||||
segments_ticks = quantize_segments(segments, F_CLK_HZ)
|
||||
|
||||
# 4. Генерируем Verilog ROM
|
||||
generate_verilog_rom(segments_ticks, VERILOG_FILE)
|
||||
|
||||
# Немного статистики в консоль
|
||||
print(f"OK: прочитано выборок: {len(times)}")
|
||||
print(f" построено сегментов: {len(segments_ticks)}")
|
||||
print(f" Verilog ROM записан: {VERILOG_FILE}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
53
top.v
Normal file
53
top.v
Normal file
@ -0,0 +1,53 @@
|
||||
// top.v — верхний уровень для Cyclone IV (OMDAZZ)
|
||||
// Внутри — pattern_player + pattern_rom (ROM сгенерирован Python-скриптом)
|
||||
|
||||
module top (
|
||||
input wire CLK50, // системный клок с платы (например, 50 МГц)
|
||||
input wire KEY0, // кнопка reset (на OMDAZZ часто активный низ)
|
||||
output wire GPIO0 // выход на пин (оптопара/LED и т.п.)
|
||||
);
|
||||
|
||||
// ==========================
|
||||
// Сброс (reset)
|
||||
// ==========================
|
||||
// Предположим, что KEY0 замыкает на 0, когда нажата → делаем rst = !KEY0.
|
||||
wire rst = ~KEY0;
|
||||
|
||||
// ==========================
|
||||
// Сигнал запуска плеера
|
||||
// ==========================
|
||||
// Для начала можем просто держать start = 1,
|
||||
// чтобы паттерн проигрывался один раз после сброса.
|
||||
// Если нужен запуск по кнопке — можно сделать простую логіку отдельно.
|
||||
wire start = 1'b1;
|
||||
|
||||
// ==========================
|
||||
// Параметры должны совпадать с pattern_rom.v
|
||||
// ==========================
|
||||
localparam TICKS_WIDTH = 32;
|
||||
// DEPTH возьми из комментария в созданном pattern_rom.v
|
||||
// (Python-скрипт его печатает). Например:
|
||||
localparam DEPTH = 128;
|
||||
|
||||
// ==========================
|
||||
// Соединения с pattern_player
|
||||
// ==========================
|
||||
wire out_sig;
|
||||
wire busy;
|
||||
|
||||
pattern_player #(
|
||||
.TICKS_WIDTH(TICKS_WIDTH),
|
||||
.DEPTH(DEPTH)
|
||||
) u_player (
|
||||
.clk (CLK50), // тот же клок, что и в Python (F_CLK_HZ = 50e6)
|
||||
// если F_CLK_HZ другое — нужен PLL и другой сигнал clk
|
||||
.rst (rst),
|
||||
.start (start),
|
||||
.out (out_sig),
|
||||
.busy (busy)
|
||||
);
|
||||
|
||||
// Выводим сигнал на внешний пин
|
||||
assign GPIO0 = out_sig;
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue
Block a user