Достъпът до паметта се осъществява от модул за управление на паметта (MMU), който съдържа контролер за директен достъп до паметта (DMA), което му позволява да прехвърля блокове от данни между блокове памет. Тези блокове могат да бъдат разпределени към DRAM (динамична памет с произволен достъп), CPU RAM (известен също като кеш от ниво 1, 2 и 3) и периферни устройства между другото - всичко зависи от структурата на вашата таблица с памет.

Тъй като литографията бавно достига своите граници и CMOS токовете на утечка все още са нещо голямо, трябва да търсим повишаване на производителността другаде.

Следният код, ако не е в критичен контекст, ще изчака реда си да бъде изпълнен (помислете за времена на изчакване за превключване на контекста), след което ще изчака своя ред за достъп до MMU, който на свой ред ще има достъп до DRAM, което ще доведе до стотици, ако не и хиляди часовници цикли, само за да прочете един байт наведнъж от мястото в паметта, посочено от src. Същият процес се рестартира, за да се запише обратно в местоположението на паметта, посочено от dest. Този процес се повтаря cntпъти.

Поради тази причина софтуерният програмист ще се опита да зададе възможно най-голям размер на копираните блокове памет. Ето пример в асемблер на PowerPC:

В примера по-горе имаме 4-байтов подравнен източник (контролер за управление на системата) и 8-байтова подравнена дестинация, поради което има 4 четения и 2 записа — това е много режийно! Поради тази причина е по-добре всички страници с памет да са с еднакви размери на подравняване.

Преминете към решение за по-бързо memcpy: DMA. Три регистъра, контролен флаг и флаг за състояние (за по-голяма простота ще пренебрегнем подравняването на паметта за момента), както и незадължително увеличение на адреса на източника и незадължително увеличение на адреса на местоназначението.

библиотека IEEE;

използвайте IEEE.STD_LOGIC_1164.ALL;

използвайте IEEE.STD_LOGIC_ARITH.ALL;

използвайте IEEE.STD_LOGIC_UNSIGNED.ALL;

обект DMAcontroller е

порт (

rst, sys_clk : IN std_logic; — нулиране и системен часовник

reg_addr: IN std_logic_vector(3 downto 0);

reg_data: INOUT std_logic_vector(7 downto 0);

reg_we : в std_logic;

mem_we : OUT std_logic; — разрешение за запис и разрешение за четене за достъп до паметта

mem_addr: ИЗХОД std_logic_vector(31 downto 0); — адресна шина

mem_data: INOUT std_logic_vector(7 downto 0);

mem_req : ИЗХОД std_logic; — заявка за достъп до паметта

mem_ack, mem_rdy : IN std_logic — потвърждение за достъп до паметта и сигнал за готовност на данните

);

край DMA контролер;

architecture architecture_DMAcontroller на DMAcontroller е

тип state_t е (IDLE, REQ_MEM, READ_MEM, WRITE_PREP, WRITE_MEM, DEC_CTR);

състояние на сигнала, n_state : state_t;

атрибут syn_encoding : низ; атрибут syn_encoding на състояние : сигналът е „сив“;

сигнал sar, dar, n_sar, n_dar: std_logic_vector (31 downto 0);

сигнал sctlr, temp: std_logic_vector(7 downto 0);

брояч на сигнали, n_counter: std_logic_vector(15 downto 0);

започвам

процес (първи, sys_clk)

започвам

if rst = ‘0’ тогава — нулирането е по-добре, когато е активно ниско, за да се спестят цикли на POR

състояние ‹= неактивен;

брояч ‹= (други =› ‘0’);

sar ‹= (други =› ‘0’);

dar ‹= (други =› ‘0’);

sctlr(7 downto 2) ‹= (други =› ‘0’);

sctlr(0) ‹= ‘0’;

темп ‹= (други =› ‘0’);

elsif rising_edge(sys_clk) then — активен сигнал с нарастващ фронт

състояние ‹= n_състояние;

reg_data ‹= (други =› ‘Z’); — задаване на регистър в изходяща посока за въвеждане по подразбиране

случай състояние е

когато IDLE =›

ако reg_we = ‘1’ тогава

case reg_addr е

когато “0000” =› — състояние/контролен регистър

sctlr(7 downto 2) ‹= reg_data(7 downto 2);

sctlr(0) ‹= reg_data(0);

когато “0010” =› — адресен регистър на източника

sar(7 downto 0) ‹= reg_data;

когато “0011” =› — адресен регистър на източника

sar(15 downto 8) ‹= reg_data;

когато “0100” =› — адресен регистър на източника

sar(23 downto 16) ‹= reg_data;

когато “0101” =› — адресен регистър на източника

sar(31 downto 24) ‹= reg_data;

когато “0110” =› — адресен регистър на местоназначение

dar(7 downto 0) ‹= reg_data;

когато “0111” =› — адресен регистър на местоназначение

dar(15 downto 8) ‹= reg_data;

когато “1000” =› — адресен регистър на местоназначение

dar(23 downto 16) ‹= reg_data;

когато “1001” =› — адресен регистър на местоназначение

dar(31 downto 24) ‹= reg_data;

когато “1010” =› — регистър на брояча

брояч (7 надолу до 0) ‹= reg_data;

когато “1011” =› — брояч регистър

брояч (15 надолу до 8) ‹= reg_data;

когато другите =›

краен случай;

друго

case reg_addr е

когато „0000“ =›

reg_data ‹= sctlr;

когато „0010“ =›

reg_data ‹= sar(7 downto 0);

когато „0011“ =›

reg_data ‹= sar(15 downto 8);

когато „0100“ =›

reg_data ‹= sar(23 downto 16);

когато „0101“ =›

reg_data ‹= sar(31 downto 24);

когато „0110“ =›

reg_data ‹= dar(7 downto 0);

когато „0111“ =›

reg_data ‹= dar(15 downto 8);

когато „1000“ =›

reg_data ‹= dar(23 downto 16);

когато „1001“ =›

reg_data ‹= dar(31 downto 24);

когато „1010“ =›

reg_data ‹= counter(7 downto 0);

когато „1011“ =›

reg_data ‹= counter(15 downto 8);

когато другите =›

краен случай;

край ако;

когато READ_MEM =›

ако mem_rdy = ‘1’ тогава

temp ‹= mem_data;

край ако;

когато DEC_CTR =›

брояч ‹= n_брояч;

if sctlr(2) = ‘1’ then — разрешаване на увеличаването на адреса на източника

sar ‹= n_sar;

край ако;

if sctlr(3) = ‘1’ then — разрешаване на увеличаването на адреса на дестинацията

dar ‹= n_dar;

край ако;

когато другите =›

краен случай;

край ако;

краен процес;

процес (състояние, sctlr, mem_ack, mem_rdy, temp, брояч, dar, sar)

започвам

n_state ‹= състояние; — по подразбиране задайте следващо състояние = текущо състояние

mem_addr ‹= (други =› ‘Z’);

mem_data ‹= (други =› ‘Z’);

mem_we ‹= 'Z';

случай състояние е

когато IDLE =› — неактивно състояние — чакаме DMA заявка

ако sctlr(0) = '1' тогава

n_state ‹= REQ_MEM;

край ако;

когато REQ_MEM =› — поиска достъп до шината на паметта

if mem_ack = ‘1’ then — заявката е потвърдена, продължете към следващото състояние

n_state ‹= READ_MEM;

край ако;

mem_we ‹= ‘0’; — разрешаване на четене

mem_addr ‹= sar;

когато READ_MEM =› — заключва данни във временен регистър

ако mem_rdy = ‘1’ тогава

n_state ‹= WRITE_MEM;

край ако;

mem_we ‹= ‘0’;

mem_addr ‹= sar;

когато WRITE_PREP =› — подготвя данни от временния регистър към шината на паметта

mem_we ‹= '1';

mem_data ‹= temp;

n_state ‹= WRITE_MEM;

mem_addr ‹= dar;

когато WRITE_MEM =›

mem_we ‹= '1';

mem_addr ‹= dar;

mem_data ‹= temp;

ако mem_rdy = ‘1’ тогава

n_state ‹= DEC_CTR;

край ако;

когато DEC_CTR =›

ако брояч = X”00 тогава

n_state ‹= IDLE;

друго

n_state ‹= REQ_MEM;

край ако;

когато другите =›

n_state ‹= IDLE;

краен случай;

краен процес;

sctlr(1) ‹= ‘0’, когато състояние = IDLE else ‘1’; — сигнал заето

mem_req ‹= ‘0’, когато състояние = IDLE else ‘1’;

n_брояч ‹= (брояч — X”0001) когато (брояч › X”00) иначе брояч; — готовността на сигнала при нарастващ фронт дава печалба в производителността

n_sar ‹= (sar + X”0001);

n_dar ‹= (dar + X”0001);

край architecture_DMAcontroller;

Синтезът в Synplify Pro дава желания резултат, наблюдаван в следния FSM:

Благодаря ви, че отделихте време да прочетете и ще оценя всяка критика.