Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: DMA: Verilog->Nios
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Системы на ПЛИС - System on a Programmable Chip (SoPC)
Veg@
Начинаю изучать работу с DMA для дальнейшего его применения в качестве способа передачи больших объемов данных из Verilog-модуля в Nios. Подскажите с чего начать, какие посоветуете источники информации по этой теме (сам я ничего подходящего не нашел) и/или, желательно, примеры реализации на Verilog+C? Спасибо.
arexol
Цитата(Veg@ @ Mar 31 2010, 19:42) *
Начинаю изучать работу с DMA для дальнейшего его применения в качестве способа передачи больших объемов данных из Verilog-модуля в Nios. Подскажите с чего начать, какие посоветуете источники информации по этой теме (сам я ничего подходящего не нашел) и/или, желательно, примеры реализации на Verilog+C? Спасибо.


Возможно у Вас не совсем верное представление ...

ДМА это модуль у которого есть мастер чтения и мастер записи
оба мастера должны подлючаться к соотвествующим слейвам.

Процессор это модуль у которого есть мастер чтения инструкций и мастер данных который может либо читать из слейва либо писать в слейв.

т.е говорить о том что передавать данные из верилог модуля(я так понимаю слейва) в процессор - некорректно,
так как процессор не является слейвом.

Если Вы хотите ускорить доступ к порции данных , например из ДДР, то один из вариантов это выкачать с помощью ДМА из ДДР слейва в ончип память
обработать процессором эту ончип память и опять с помощью ДМА залить в ДДР из ончип памяти.

Суть ускорения в том что ДДР будет работать в бурст режиме , а не в рандом.
И когда мастрер данных процессора будет читать из ончип в рандоме то это всёравно как из кеша читать\писать.
Veg@
2 arexol
Уточню: Verilog-код, как я понимаю, находится в ПЛИС, код на C - в sdram. Каким образом я могу обратиться из программы на C (код для Nios) к Verilog-буферу, состоящему из регистров, и нужно ли вообще для этого его предварительно скопировать из ПЛИС, например, в тот же sdram?

Сформулирую свой вопрос по-другому:
Нужно реализовать такую программу (псевдокод):
Код
Старт копирования данных из буфера, размещенного в памяти ПЛИС (регистр Verilog)

while(пока не скопировались данные)
выполнение полезной работы;

Обработка скопировавшихся данных

т.е. обычный асинхронный запрос к памяти, выполняющийся параллельно с основным потоком программы. Корректно ли для этого использовать DMA? В какую сторону копать? Спасибо.
vadimuzzz
Цитата(Veg@ @ Apr 1 2010, 01:05) *
т.е. обычный асинхронный запрос к памяти, выполняющийся параллельно с основным потоком программы. Корректно ли для этого использовать DMA?

да, корректно. для этого нужно оснастить verilog-модуль 2-мя интерфейсами Avalon: Avalon-MM-мастер(для доступа к памяти), Avalon-MM-слейв (чтобы NIOS мог управлять модулем и следить за его состоянием). соответственно читать: http://www.altera.com/literature/manual/mnl_avalon_spec.pdf + посмотреть пример http://www.altera.com/support/examples/nio...celeration.html. для устройств с DMA очень важно следить, чтобы они не вылезали за границы, если они имеют доступ на запись.
arexol
Ваш верилог модуль из которого можно прочитать процессором что либо должен иметь слейв интерфейс (читайте спецификацию).
Грубо говоря это набор сигналов и правил для этих сигналов.
простой слейв будет выгляеть примерно вот так

Код
module MyModule (
input  clk;
input  reset;
input  chipselect;
input  read;
input  [3:0]  adress;
output  reg [31:0] readdata;
input  write;
input  [31:0] writedata;
);

reg [31:0] buffer;

always @(posedge clk or posedge reset )
begin
   if (reset)
    begin
      readdata<=0;
      buffer<=5;
    end
   else
     begin
        if (chipselect & write)
          begin
             buffer<=writedata; // writing
          end
        
       if (chipselect & read)
        begin
          if (adress==2)  
            readdata<=buffer;
          else
            readdata<=0;
        end
        
     end
end

endmodule

обратите внимание на адрес - 5 бит
в соотв разрядности будет выделено адресное пространство

когда Вы сделаете указатель на это адресное пространство в Си коде
то при чтении или записи по этому указателю будет инициироваться транзакция чтения или записи мастером данных процессора

ну и вот если вы запишете в это адресное пространство число то оно попадёт в регистр буффер

чтобы считать записанное значение надо будет потом обратиться к адресу базовый + 2


ps.
если есть ошибки то прошу прощения - не компилировал


вот нашёл ещё мелкий слейв для учебных целей
Код
module MyModule(
    clk,
    chipselect,
    reset,
    address,
    read,
    readdata,
    write,
    writedata,
    irq

);

input clk;
input chipselect;
input reset;
input [3:0]address;
input read;
output [31:0]readdata;
reg [31:0]readdata;
input write;
input [31:0]writedata;
output irq;
reg irq;
// internal regs
reg [31:0]reg0;
reg [31:0]reg1;
reg [31:0]reg2;
reg [31:0]reg3;


always @(posedge clk or posedge reset)
begin
if(reset)
  begin
    irq<=1'b0;
    readdata<=32'b0;
    reg0=32'd0;
    reg1=32'd1;
    reg2=32'd2;
    reg3=32'd3;
  end
else
begin


  if (chipselect & read) // ANALON READING TO CPU
   case (address)
    4'd0: readdata<=reg0;
    4'd1: readdata<=reg1;
    4'd2: readdata<=reg2;
    4'd3: readdata<=reg3;
   endcase


  if (chipselect & write) //AVALON WRITING FROM CPU
   case(address)
    4'd0: reg0<=writedata;
    4'd1: reg1<=writedata+reg0;
    4'd2: reg2<=writedata-reg1;
    4'd3: reg3<=writedata*reg2;
   endcase


  if (reg0==32'd12)  // IRQ PROCESSING
   irq<=1;
  else
   irq<=0;


end
end



endmodule
Veg@
1. Понемногу разбираюсь с DMA. Инициализировал прием следующим образом:
Код
rxchan = alt_dma_rxchan_open("/dev/dma");
alt_dma_rxchan_ioctl(rxchan, ALT_DMA_RX_ONLY_ON, (void *)(TEST_COMPONENT_BASE);
alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_32, NULL);
alt_dma_rxchan_prepare (rxchan,rx_buffer,16,done,NULL);
В результате происходит чтение по адресу TEST_COMPONENT_BASE с нулевым смещением. Т.е., насколько я понял, для того, чтобы принять из этого компонента объем данных >4Б (напр., массив регистров), необходимо в нем хранить указатель на следующую порцию отправляемых данных и после каждой отправки 4Б увеличивать его соответственно на 4Б. Думаю, это будет работать, но верное и стандартное ли это решение? (все примеры, которые я рассматривал, принимали данные в компонент по DMA, но не отправляли).

2. Реализованный мной пример чтения данных из TEST_COMPONENT верно работает при их копировании в onchip_memory. Мне же, в конечном итоге, нужно их доставить в SDRAM, где находится программа на Си. В приведенном ниже коде я попытался это реализовать, но данные в массив data не попадают. В чем ошибка: в коде или SOPC ?



Код
#include <stdio.h>
#include <stdlib.h>
#include <sys/alt_dma.h>
#include "system.h"
#include "io.h"

static volatile int rx_done = 0;
alt_dma_txchan txchan;
alt_dma_rxchan rxchan;
int rc;
  
static void done (void* handle, void* data)
{
  rx_done++;
}

void init_dma()
{
  if ((rxchan = alt_dma_rxchan_open("/dev/dma")) == NULL)
  {
    printf ("Failed to open the DMA transmit channel\n");
    exit(1);
  }
  if ((rc = alt_dma_rxchan_ioctl(rxchan, ALT_DMA_RX_ONLY_ON, (void *)(TEST_COMPONENT_BASE))) < 0)
  {
    printf ("Failed to set the DMA channel to transmit only, reason = %i\n", rc);
    exit(1);
  }
  if ((rc = alt_dma_rxchan_ioctl(rxchan, ALT_DMA_SET_MODE_32, NULL)) < 0)
  {
    printf ("Failed to set the DMA channel to word access, reason = %i\n", rc);
    exit(1);
  }
}

int main()
{
  unsigned long data[7];                    
  void* rx_buffer = data;

  init_dma();
  if ((rc = alt_dma_rxchan_prepare (rxchan,rx_buffer,4,done,NULL)) < 0)
  {
    printf ("Failed to post read request, reason = %i\n", rc);
    exit (1);
  }

  while (!rx_done);

  printf ("\nTransfer successful!\n");
  printf ("0x%X\n0x%X\n0x%X\n0x%X\n",data[0],data[1],data[2],data[3]);
  return 0;
}
vadimuzzz
1. делать так можно, но это не айс. в данном случае лучше использовать memory to memory транзакции. тогда адреса сами будут инкрементиться.
2. похоже на фокусы с data cache. попробуйте воткнуть alt_dcache_flush_all() в функцию done().
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.