пятница, 27 февраля 2015 г.

Python для ПЛИС

В предыдущим посте я упоминал про MyHDL, теперь буду разбираться с этой темой. Библиотека предоставляет псевдоверилоговский синтаксис для Python, благодаря которому можно транслировать написанные блоки на Verilog/VHDL и/или моделировать их, используя встроенные в Python средства(matplotlib) и/или создавать временные диаграммы. Возможностей на самом деле больше, но надо разбираться.

Перед тем, как погружаться в MyHDL, коротко моя сборка Python. Я пользуюсь miniconda 2.7 с установленными из репозитория пакетами numpy, matplotlib, pip (-через cmd в папке /Scrips conda install), установленным через pip spyder(-там же pip install) и скаченным c github myhdl (-cmd > python setup.py install в распакованной папке). Вот необходимый минимум.

На сайте MyHDL много описания и примеров. Моей конечной целью будет переписать CORDIC (снова, опять). Забавное совпадение, что в примерах для MyHDL есть CORDIC. Как раз посмотрю есть ли у меня где-нибудь недочеты.

Единственное новое с чем я столкнулся - декораторы и генераторы в Python. Про декораторы хорошо расписано на хабре, а генераторы по любой ссылке в гугле. Я опущу примеры с сайта MyHDL и начну с "хвоста", то есть в тестбенча.
# -*- coding: utf-8 -*-

from myhdl import *
import matplotlib.pyplot as plt

plt_clk = []
plt_cnt = []
def clkgen():
    global plt_clk, plt_cnt
    r_cnt = Signal(modbv(0, 0, 4))
    r_clock = Signal(bool(0))
    @instance
    def posedge_negedge():
        while True:            
            yield delay(10)
            r_clock.next = 1            
            yield delay(10)
            r_clock.next = 0

    @always(r_clock.posedge)
    def count():
        r_cnt.next = r_cnt + 1

    @instance
    def monitor():
        while True:
            plt_clk.append(int(r_clock))
            plt_cnt.append(int(r_cnt))
            print "%d_%d" %(now(), r_clock)
            yield delay(1)
            

    return posedge_negedge, count, monitor

inst = traceSignals(clkgen)
sim = Simulation(inst)
sim.run(100)


fig, ax = plt.subplots(2,1)
ax[0].plot(plt_clk,'ro-')
ax[1].plot(plt_cnt,'bo-')
fig.tight_layout()

Получившиеся графики в Pthon:
Так же в рабочей папке появится файл .vcd, который можно открыть в gtkwave:

Видно, что результат получился одинаковым, но открывать .vcd файл дольше. В ModelSim тоже можно отрыть .vcd, но сначала нужно сконвертировать vcd2wlf в окне команд ModelSim'а.

пятница, 6 февраля 2015 г.

Миграция CORDIC на python

Уже в какой раз возвращаюсь к CORDIC. Изначально писался он на C/C++, портировался на verilog, результаты тестов прогонялись через FreeMat для получения графиков. Поскольку уже было проверено, что результаты работы сишной программы и verilog одинаковы, то смысл имело анализировать результаты из си, потому что это быстрее. FreeMat оказался тоже не очень удобным в использовании, поэтому я решил мигрировать на python 2.7.
Пайтон оказался мне по душе. По привычке писал классы, потому что это понятие ближе к верилоговскому понятию module. В каждом классе написал функию генерации верилоговского файла(достаточно муторно, нужно попробовать myhdl). Легко посмотреть спектр сгенерированной последовательности, легко перевести его в децибелы.
Что касается самого алгоритма? Как показали тесты: наименьшие искажения получаются при использовании целых с округлением. При этом в спектре всегда присутствуют гармоники на частоте f(1+4n), n = 0,1,2.., где f - генерируемая частота. Уровень гармоник зависит от разрядности модуля и количества итерация в алгоритме CORDIC(а количество итераций зависит от разрядности фазы). Вот например график спектра для gen = Generator(f, F, 14,16,16), где f = 400 Гц - генерируемая частота, F = 8000 Гц - частота дискретизации, N = 14 - число итераций, 16 и 16 - разрядности модуля и фазы.
При такой реализации уровень гармоник не превышает уровня -80 дБ. -150 дБ - константа, добавленная в результаты ДПФ, чтобы можно было без проблем взять десятичный логарифм. Такой же график для f = 40 Гц:
В общем теперь можно легко менять параметры и смотреть к чему это приведет. Зачем я делал метод перевода в verilog? Потому, что при изменении количество шагов и разрядности фазы, менялись коэффициенты углов и CORDIC gain. То есть сам модуль CORDIC был плохо параметризуемым. Метод для генерации: gen.Generator_verilog(20000000). Аргумент - системная частота.

Ссылка не репозиторий, может кому-то понадобится.