na realidade se vc demora 200ms para mover os dados via DMA, vai demorar uns 1000ms para mover os mesmos dados na unha via codigo. pegue esse 200ms do DMA e divida pelo volume de dados, provavelmente vc vai ter 1 clock para ler a memoria e 1 clock para escrever na memoria. uma implementacao simples disso em verilog vai gerar um pseudo-hardware mais ou menos assim:
reg [1:0] DMASTATE = 0; // estado do controlador: 0 = parado, 1 = leitura, 2 = escrita
reg [15:0] WPTR = 0; // ponteiro de escrita
reg [15:0] RPTR = 0; // ponteiro de leitura
reg [15:0] SIZE = 0; // tamanho
wire [15:0] DMAADDR = DMASTATE==1 ? RPTR : DMASTATE==2 ? WPTR : 16'hzzzz;
wire [15:0] DMADATA = DMASTATE==2 ? DATA : 16'hzzzz;
wire DMARD = DMASTATE==1 : 1'bz;
wire DMAWR = DMASTATE==2 : 1'bz;
reg [15:0] DATA; // temporario
always(posedge CLK)
begin
DATA <= DMASTATE==1 ? DMADATA : DATA;
RPTR <= DMASTATE==0 ? RPTR_PROG : DMASTATE==1 ? RPTR+1 : RPTR;
WPTR <= DMASTATE==0 ? WPTR_PROG : DMASTATE==2 ? WPTR+1 : WPTR;
SIZE <= DMASTATE==0 ? SIZE_PROG : DMASTATE==2 ? SIZE-1 : SIZE;
DMASTATE <= DMASTATE==0 && DMAENA ? 1 : DMASTATE==1 ? 2 : DMASTATE==2 && SIZE ? 1 : 0;
end
os estados de operacao sao 3:
quando DMASTATE==0, ele programa os ponteiros WPTR, RPTR e o tamanho SIZE, vindo de algum registro de configuracao, bem como deixa o DMAADDR em tri-state, para o processador usar. se neste estado parado o DMAEN mudar para 1, ele liga a maquina de estado que fica trocando DMASTATE entre os estados 1 e 2. com DMASTATE==1, o DMAADDR sai de tri-state e passa a ter o endereco de leitura da memoria. no caso, provavelmente DMASTATE diferente de zero para o processador, para q o controlador de DMA use o barramento de dados. eventualmente, em uma implementacao onde o processador tem cache, o processador pode continuar rodando a partir da cache. anyway, note que enquanto DMAADDR estah enderecando a memoria, o resultado serah gravado no registro DATA ao mesmo tempo em que RPTR eh incrementado e SIZE eh decrementado (como um pipeline, eu adianto isso para no proximo ciclo poder testar SIZE). DMASTATE vai entao para 2, onde ocorre algo similar, mas agora na escrita, com WPTR apontando a memoria de escrita e DATA sendo colocado no barramento de dados. enquanto a memoria estah gravando DATA no endereco DMAADDR, WPTR eh incrementado e tambem ocorre a mudanca de DMASTATE, que depende do valor de SIZE. se SIZE for zero, DMASTATE vai para 0 e a transferencia se encerra, senao vai para o estado 1 novamente e assim por diante.
bom, o conceito eh esse... note o numero de operacoes que eu faco em apenas dois clocks:
clock 1 = ler o dado em um registro temporario, incrementar o ponteiro de leitura, decrementar o indicador de tamanho
clock 2 = escrever o dado do registro temporario, incrementar o ponteiro de escrita, testar o indicador de tamanho para ver se a transferencia acabou
a mesma operacao feita na unha em um processador hipotetico, imaginando que cada operacao em assembler representa um clock:
clock 1: lod *rptr++,rtmp // carrega registro rtmp a partir do ponteiro rptr e incrementa rptr
clock 2: sto rtmp,*wptr++ // armazena registro rtmp na memoria apontada por wptr e incrementa wptr
clock 3: dec size // decrementa contador de tamanho
clock 4: bnz loop // testa e salta se size nao for zero
varia de processador para processador... se o processador usar pipelines, provavelmente tem uma penalidade ali no branch, mas vamos simplificar e imaginar que eh isso apenas. entao nesse exemplo, jah usamos 4 clocks. tem como otimizar mais? depende do processador. tem processadores em que vc nao pode incrementar os ponteiros no proprio acesso, entao vc teria 2 clocks extras com inc rptr e inc wptr. tem processadores que permitem mover *rptr++,*wptr++, mas obviamente a operacao consome pelo menos dois clocks, uma para ler e outra para escrever. e tem processadores com instrucoes magicas que decrementam, testam e saltam na mesma instrucao. mas acho que na melhor das hipoteses ainda usaria 3 clocks no loop principal...entao 200ms de transferencia de DMA transfere muito mais coisa que 200ms de transferencia via processador, pq o overhead eh menor no DMA. isso sem falar no overhead de setup: no caso do controlador de DMA, apenas um unico clock eh necessario para rearmar os ponteiros e o contador de tamanho. enquanto isso, no processador, vc vai ter que configurar registro por registro sequencialmente. e claro, o controlador de DMA estah sempre em espera pronto para comecar a transferir, ou seja, a latencia para inicio eh zero. no caso do processador, provavelmente vc vai disparar uma interrupcao, salvar o contexto corrente, configurar os registros para operar e soh entao comecar a transferencia. finalmente, jah comentei, mas vale enfatizar, se o processador tiver caches, o controlador de DMA opera em paralelo com o processador, ou seja, dobra o bandwidth!
bom, nao sei o que vc conclui, mas eu acho que temos claramente um vencedor aqui: DMA! se vc tiver ele disponivel, vale a pena usar sim.
fabim escreveu:Né zoeira não!
André, como eu nunca mexi com DMA, me perdoe se eu fui sarcástico ao contrário, ou direto, não entendi ainda porque acham que estou brincando.
Eu entendi o André dizendo que:
Se usar DMA, e demorar digamos 200mS para mover os dados. O núcleo fica 200mS parada sem fazer nada, o que teoricamente seria o mesmo tempo gasto pra transferir na unha através de código.
No meu caso, eu vou disparar a DMA, e continuar fazendo outras coisas.
Fiz um teste, e o núcleo não fica preso quando eu disparo a DMA, ela fica cuspindo dados sem parar e o núcleo livre pra fazer qualquer outra coisa.
Quando diz ocupa o barramento, que barramento disse ?
Desculpe novamente se estou com cara de burro, é que hoje é sexta e acordo as 5 pra vir trabalhar, e chego em casa depois das 20:30, ficando 4 horas por dia em busa!