Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Чт мар 28, 2024 17:29

...
Google Search
Forth-FAQ Spy Grafic

Часовой пояс: UTC + 3 часа [ Летнее время ]




Ответить
Имя пользователя:
Заголовок:
Текст сообщения:
Введите текст вашего сообщения. Длина сообщения в символах не более: 60000

Размер шрифта:
Цвет шрифта
Настройки:
BBCode ВКЛЮЧЕН
[img] ВЫКЛЮЧЕН
[flash] ВЫКЛЮЧЕН
[url] ВКЛЮЧЕН
Смайлики ВЫКЛЮЧЕНЫ
Отключить в этом сообщении BBCode
Не преобразовывать адреса URL в ссылки
Вопрос
Теперь гостю придется вводить здесь пароль. Не от своей учетной записи, а ПАРОЛЬ ДЛЯ ГОСТЯ, получить который можно после регистрации на форуме через ЛС.:
Этот вопрос предназначен для выявления и предотвращения автоматических регистраций.
   

Обзор темы - Стек на встроенной памяти ПЛИС с кэшем в LCELL
Автор Сообщение
  Заголовок сообщения:  Re: Стек на встроенной памяти ПЛИС с кэшем в LCELL  Ответить с цитатой
хм.. квартус мне на циклоне-2 (не самом быстром) с пол пинка выдал 195MHz.

Вот так и подумаешь, а стоит ли выделка овчинки?..

В смысле, надо ли стремиться к тому, чтобы все на vhdl делать с расчетом на Xilinix?

Теперь надо ядро процессора на 195MHz запустить, чтобы по максимуму вышло на Альтере. А то ядро+два вот этих стека - только до 140MHz разводятся.
Сообщение Добавлено: Вт май 18, 2010 04:00
  Заголовок сообщения:  Re: Стек на встроенной памяти ПЛИС с кэшем в LCELL  Ответить с цитатой
WingLion писал(а):
А предельную рабочую частоту ISE показывать не хочет?

Что-то порядка 150 МГц, не помню точно. Это очень предварительная цифра, без сбора всей системы бывает трудно предсказать итоговую частоту.
Сообщение Добавлено: Пн май 17, 2010 23:24
  Заголовок сообщения:  Re: Стек на встроенной памяти ПЛИС с кэшем в LCELL  Ответить с цитатой
Хищник писал(а):
Selected Device : 3s700afg484-4


А предельную рабочую частоту ISE показывать не хочет?
Сообщение Добавлено: Пн май 17, 2010 22:27
  Заголовок сообщения:  Re: Стек на встроенной памяти ПЛИС с кэшем в LCELL  Ответить с цитатой
Device utilization summary:
---------------------------

Selected Device : 3s700afg484-4

Number of Slices: 144 out of 5888 2%
Number of Slice Flip Flops: 126 out of 11776 1%
Number of 4 input LUTs: 270 out of 11776 2%
Number used as logic: 268
Number used as Shift registers: 2
Number of IOs: 36
Number of bonded IOBs: 36 out of 372 9%
Number of BRAMs: 1 out of 20 5%
Number of GCLKs: 1 out of 24 4%
Сообщение Добавлено: Ср май 12, 2010 21:29
  Заголовок сообщения:  Re: Стек на встроенной памяти ПЛИС с кэшем в LCELL  Ответить с цитатой
Сделал я за вчера и сегодня эту схемку на VHDL:

Код:
-- VHDL Lcell Cashe Stack in RAM

LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.std_logic_unsigned.all;

ENTITY   VLCS IS

GENERIC ( widthdat : integer := 16;
      depth : integer := 8
      );
      Port (
         clk   : in std_logic;
         di   : in std_logic_vector (widthdat-1 downto 0);
         doo   : out std_logic_vector (widthdat-1 downto 0);
         
         cmd   : in std_logic_vector (1 downto 0);
         ena   : in std_logic
      );

END VLCS;

ARCHITECTURE RTL OF VLCS IS
   
   subtype words is std_logic_vector (widthdat-1 downto 0);
   type T_memory is array(2**depth-1 downto 0) of words;
   
attribute altera_attribute : string;
attribute altera_attribute of RTL: architecture is "-name AUTO_SHIFT_REGISTER_RECOGNITION OFF";   

constant nop : std_logic_vector (1 downto 0) := "00";
constant push : std_logic_vector (1 downto 0) := "01";
constant pop : std_logic_vector (1 downto 0) := "10";
constant swap : std_logic_vector (1 downto 0) := "11";   

   signal do : std_logic_vector (widthdat-1 downto 0);

   signal TOP : std_logic_vector (widthdat-1 downto 0);
   signal BOT : std_logic_vector (widthdat-1 downto 0);
   
   signal REG0 : std_logic_vector (widthdat-1 downto 0);
   signal REG1 : std_logic_vector (widthdat-1 downto 0);
   signal REG2 : std_logic_vector (widthdat-1 downto 0);
   signal REG3 : std_logic_vector (widthdat-1 downto 0);
   
   signal ADR      : natural range 0 to 2**depth-1;
   signal ADR_WR   : natural range 0 to 2**depth-1;
   signal ADR_RD   : natural range 0 to 2**depth-1;
   signal radr   : natural range 0 to 2**depth-1;
   
   signal ramq      : words;
   
   signal adr_rd0   : std_logic_vector (1 downto 0);
   signal adr_rd1   : std_logic_vector (1 downto 0);
   signal adr_rd2   : std_logic_vector (1 downto 0);
   
   signal push_s   : std_logic;
   
   signal RAM : T_memory;

   signal wr0,wr1,wr2,wr3 : std_logic;
   signal wr0t,wr1t,wr2t,wr3t : std_logic;
   signal wr0x,wr1x,wr2x,wr3x : std_logic;
   
function last2bits (adr : natural)  return natural is
   variable adr_4,tmp : natural;
   
begin
   adr_4 := adr/4;
   tmp := adr - (adr_4)*4;
   return tmp;
end last2bits;

BEGIN

   process (clk,ena,cmd) begin
      if (clk'event and clk='1' and ena='1') then
         case  cmd is
            when nop => TOP <= TOP; BOT <= BOT; ADR <= ADR;
            when push => TOP <= Di; BOT <= TOP; if adr = -1 then adr <= adr; else ADR <= ADR+1; end if;
            when pop => TOP <= BOT; BOT <= Do;  if adr = 0 then adr <= adr; else adr <= adr-1; end if;
            when swap => TOP <= di; BOT <= BOT; ADR <= ADR;
            when others => TOP <= TOP; BOT <= BOT;
         end case;

         case cmd is
            when nop =>    if adr = 2**depth-1 then adr_wr <= 2**depth-1; else adr_wr<=adr+1; end if;
            when push =>   if adr = 2**depth-1 or adr = 2**depth-2 then adr_wr <= 2**depth-1; else adr_wr<=adr+2; end if;
            when pop =>    adr_wr <= adr;
            when swap =>   if adr = 2**depth-1 then adr_wr <= 2**depth-1; else adr_wr<=adr+1; end if;
            when others => if adr = 2**depth-1 then adr_wr <= 2**depth-1; else adr_wr<=adr+1; end if;
         end case;         
         
         adr_rd1 <= "00" + last2bits(adr_rd);
         adr_rd2 <= adr_rd1;
      end if;
   end process;
   
   process (cmd) begin
      case cmd is
         when nop => if adr > 2 then adr_rd <= adr-2; else adr_rd<=0; end if;
         when push => if adr > 1 then adr_rd <= adr-1; else adr_rd<=0; end if;
         when pop => if adr > 3 then adr_rd <= adr-3; else adr_rd<=0; end if;
         when swap => if adr > 2 then adr_rd <= adr-2; else adr_rd<=0; end if;
         when others => if adr > 2 then adr_rd <= adr-2; else adr_rd<=0; end if;
      end case;   

      if cmd = push  then push_s <=ena; else push_s <='0'; end if;
   end process;
   


   doo <= top;
   
   process (adr_wr) begin
      if last2bits(adr_wr) = 0 and push_s ='1' then wr0 <='1'; else wr0<='0'; end if;
      if last2bits(adr_wr) = 1 and push_s ='1' then wr1 <='1'; else wr1<='0'; end if;
      if last2bits(adr_wr) = 2 and push_s ='1' then wr2 <='1'; else wr2<='0'; end if;
      if last2bits(adr_wr) = 3 and push_s ='1' then wr3 <='1'; else wr3<='0'; end if;
   end process;
   
   process (clk,ena) begin
      if (clk'event and clk='1' and ena='1') then
         wr0t <= wr0; if wr0 = '1' then reg0 <= bot; elsif wr0x = '1' and wr0t = '0' then reg0 <= ramq; end if;
         wr1t <= wr1; if wr1 = '1' then reg1 <= bot; elsif wr1x = '1' and wr1t = '0' then reg1 <= ramq; end if;
         wr2t <= wr2; if wr2 = '1' then reg2 <= bot; elsif wr2x = '1' and wr2t = '0' then reg2 <= ramq; end if;
         wr3t <= wr3; if wr3 = '1' then reg3 <= bot; elsif wr3x = '1' and wr3t = '0' then reg3 <= ramq; end if;
      end if;
   end process;
   
   process (adr) begin
   --   adr_rd0 <= "00" + last2bits(adr);
      case last2bits(adr) is
         when 0 => do <= reg0;
         when 1 => do <= reg1;
         when 2 => do <= reg2;
         when 3 => do <= reg3;
         when others => null;
      end case;
   end process;

   process (adr_rd2) begin
      if adr_rd2 = "00" then wr0x <= '1'; else wr0x <= '0'; end if;
      if adr_rd2 = "01" then wr1x <= '1'; else wr1x <= '0'; end if;
      if adr_rd2 = "10" then wr2x <= '1'; else wr2x <= '0'; end if;
      if adr_rd2 = "11" then wr3x <= '1'; else wr3x <= '0'; end if;
   end process;
   
   process(clk)
   begin
   if(rising_edge(clk)) then
      if(push_s = '1') then
         ram(adr_wr) <= bot;
      end if;

      radr <= adr_rd;

      ramq <= ram(radr);
   end if;
   end process;
      

END ARCHITECTURE;


результат по частоте - тот же 195.01MHz на втором циклоне с 7-м спидгрэйдом.

Только по объему схема на VHDL поменьше заняла процентов на 15...

Интересно, получится ли ее для Xilinx откомпилировать?..
И сколько она там займет места?
Сообщение Добавлено: Ср май 12, 2010 20:18
  Заголовок сообщения:  Re: Стек на встроенной памяти ПЛИС с кэшем в LCELL  Ответить с цитатой
Проверить правильность работы этого стека в симуляторе не так просто. Потому что не ясно точно, в каких случаях следует искать возможное неправильное поведение, а отдельная покомандная проверка (для команд PUSH,POP,SWAP,NOP) не дает полной уверенности в правильной работе, так как работа схемы сильно зависит от предыстории команд на входе.

Поэтому, для проверки был выбран следующий план.
1. На VHDL собирается простейший стек чисто на LCELL, такой, который достаточно легко проверить как в симуляторе, так и в реальной работе.
2. Собирается схема из двух стеков, включенных параллельно. Один стек - разрабатываемый согласно идее данного топика, второй - эталонный стек - простейший стек на LCELL, в правильной работе которого сомнений нет.
2.1 входы стеков соединяются параллельно,
2.2. выходы выводятся раздельно и выходы двух стеков подаются на схему сравнения, после этого делается симуляция работы с подачей на входы псевдослучайного потока команд, которым имитируется работа стека в составе процессора. результат сравнения выдается отдельным выводом
3. Производится симуляция работы тестовой схемы, в которой ожидается, что два стека должны вести себя одинаково при одинаковых воздействиях на входах.

Вот, такая работа и была проделана.

В качестве эталонного стека был взят стек на LCELL уже работающий в форт-процессоре и, таким образом, можно сказать, что полностью проверенный.

В качестве "эталонной" была взята вот такая схема (VHDL-исходник)

Код:
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
USE IEEE.std_logic_unsigned.all;

ENTITY   StackOnLCell IS

GENERIC ( widthdat : integer := 16;
      depth : integer := 5
      );
      
      Port (
         
         clk   : in std_logic;
         di   : in std_logic_vector (widthdat-1 downto 0);
         do   : out std_logic_vector (widthdat-1 downto 0);
         cmd   : in std_logic_vector (1 downto 0);
         ena   : in std_logic
      );

END StackOnLCell;

ARCHITECTURE RTL OF StackOnLCell IS
   
TYPE Tstack IS array (depth-1 downto 0) OF std_logic_vector (widthdat-1 downto 0);

constant nop : std_logic_vector (1 downto 0) := "00";
constant push : std_logic_vector (1 downto 0) := "01";
constant pop : std_logic_vector (1 downto 0) := "10";
constant swap : std_logic_vector (1 downto 0) := "11";   
   
   signal st : Tstack;
   signal stage1 : Tstack;
   signal stage2 : Tstack;
   
BEGIN

   st <= stage2;
   process (clk,cmd) begin
      if (clk'event and clk='1' and ena = '1') then
         case cmd is
            when nop => stage2 <= st;
            when pop => stage2(depth-2 downto 0) <= st(depth-1 downto 1); stage2(depth-1) <= (others => '0');
            when push => stage2(depth-1 downto 1) <= st(depth-2 downto 0); stage2(0) <= di;
            when swap => stage2(depth-1 downto 1) <= st(depth-1 downto 1); stage2(0) <= di;
         end case;
      end if;      
   end process;
   do   <= stage2(0);
END;


С эталонным стеком и стеком из этой темы в квартусе была собрана следующая схема:

Изображение

симуляция этой связки стеков показала неадекватность работы стека с кэшем в LCELL, поэтому после некоторого "ковыряния" старой схемы была произведен полный редизайн схемы с кэшем "с нуля".

Получилась следующая схема (на AHDL):
Код:
   TITLE "StackWithRamCashe";

include "ram16x256";

PARAMETERS (
   WIDTH = 16,
   DEPTH = 8
);
   
SUBDESIGN Stack (
   RESET   : input = VCC;
   CLK   : input;
   ENA   : input;
   CMD[1..0]   : input;
   Di[WIDTH-1..0]   : input;
   Do[WIDTH-1..0]   : output;
   TOP[WIDTH-1..0]   : output;
   BOT[WIDTH-1..0]   : output;
   
   test_a_rd[DEPTH-1..0]   : output;
   test_a_wr[DEPTH-1..0]   : output;
   test_ram_q[WIDTH-1..0]    : output;
   test_WR[3..0]   : output;
   test_WRx[3..0]   : output;
   test_a_rd_[1..0]   : output;
   test_a_rd1_[1..0]   : output;
   test_a_rd2_[1..0]   : output;
   test_rd_[3..0]      : output;
   ADR[DEPTH-1..0]      : output;
)
VARIABLE
   TOP[WIDTH-1..0]    : DFFE;
   BOT[WIDTH-1..0]    : DFFE;

   RG0[WIDTH-1..0]    : DFFE;
   RG1[WIDTH-1..0]    : DFFE;
   RG2[WIDTH-1..0]    : DFFE;
   RG3[WIDTH-1..0]    : DFFE;
   
   ADR[DEPTH-1..0]      : DFFE;
   ADR_WR[DEPTH-1..0]   : DFFE;
   ADR_RD[DEPTH-1..0]   : node;
   ADR_RD1_[1..0]      : DFF;
   ADR_RD2_[1..0]      : DFF;
   
   PUSH             : node;
   
   RAM               : ram16x256;
   
   WR[3..0]         : DFF;
   WRx[3..0]         : node;

   test_a_rd[DEPTH-1..0]   : node;
   test_a_wr[DEPTH-1..0]   : node;
   test_ram_q[WIDTH-1..0]    : node;
   test_WR[3..0]      : node;
   test_WRx[3..0]      : node;
   test_a_rd_[1..0]   : node;
   test_a_rd1_[1..0]   : node;
   test_a_rd2_[1..0]   : node;
   test_rd_[3..0]      : node;
   
BEGIN
   DEFAULTS
      WRx[] = GND;
   END DEFAULTS;

   TOP[].clk = CLK; TOP[].ena = ENA;
   BOT[].clk = CLK; BOT[].ena = ENA;
   CASE CMD[] IS
      WHEN 0 => TOP[] = TOP[]; BOT[] = BOT[];
      WHEN 1 => TOP[] = Di[];  BOT[] = TOP[];
      WHEN 2 => TOP[] = BOT[]; BOT[] = Do[];
      WHEN 3 => TOP[] = Di[]; BOT[] = BOT[];
   END CASE;
   
   ADR[].clk = CLK; ADR[].ena = ENA; ADR_WR[].clk = CLK;ADR_WR[].ena = ENA;
   ADR[].clrn = RESET; ADR_WR[].clrn = RESET;
   CASE CMD[] IS
      WHEN 0 => ADR[] = ADR[]; PUSH = GND;
         ADR_RD[] = (ADR[] - 2) and !((ADR[] == 0) and (ADR[] == 1));
         ADR_WR[] = (ADR[] + 1) or (ADR[] == -1);
      WHEN 1 => ADR[] = (ADR[] + 1) or (ADR[] == -1); PUSH = ENA;
         ADR_RD[] = (ADR[] - 1) and !((ADR[] == 0) and (ADR[] == 1));
         ADR_WR[] = (ADR[] + 2) or ((ADR[] == -1 or ADR[] == -2));
      WHEN 2 => ADR[] = (ADR[] - 1) and !(ADR[] == 0); PUSH = GND;
         ADR_RD[] = (ADR[] - 3) and !((ADR[] == 0) and (ADR[] == 1));
         ADR_WR[] = ADR[];
      WHEN 3 => ADR[] = ADR[]; PUSH = GND;
         ADR_RD[] = (ADR[] - 2) and !((ADR[] == 0) and (ADR[] == 1));
         ADR_WR[] = (ADR[] + 1) or (ADR[] == -1);
   END CASE;
--   ADR_WR[] = (ADR[] + 1) or (ADR[] == -1);
--   ADR_RD[] = (ADR[] - 1) and !((ADR[] == 0) and (ADR[] == 1));
   
   test_a_rd_[] = ADR[1..0];
   test_rd_[] = (ADR[1..0] == 3,ADR[1..0] == 2,ADR[1..0] == 1,ADR[1..0] == 0);
   
   test_a_wr[] = ADR_WR[];
   test_a_rd[] = ADR_RD[];
   ADR_RD1_[].clk = CLK;
   ADR_RD1_[] = ADR_RD[1..0];
   ADR_RD2_[].clk = CLK;
   ADR_RD2_[] = ADR_RD1_[];
   
   test_a_rd1_[1..0] = ADR_RD1_[];
   test_a_rd2_[1..0] = ADR_RD2_[];
   
   RG0[].clk = CLK; RG0[].clrn = RESET;
   RG1[].clk = CLK; RG1[].clrn = RESET;
   RG2[].clk = CLK; RG2[].clrn = RESET;
   RG3[].clk = CLK; RG3[].clrn = RESET;

--   CASE ADR_RD[1..0] IS
--      WHEN 0 => Do[] = RG0[];
--      WHEN 1 => Do[] = RG1[];
--      WHEN 2 => Do[] = RG2[];
--      WHEN 3 => Do[] = RG3[];
--   END CASE;
   
   WR[].clk = CLK;
   test_WR[] = WR[];
   test_WRx[] = WRx[];
   
   IF (ADR_WR[1..0] == 0) and PUSH THEN RG0[] = BOT[]; WR0 = VCC; ELSE WR0 = GND; IF (ADR_RD2_[1..0] == 0) and !WR0 THEN RG0[] = RAM.q[]; WRx0 = VCC; ELSE RG0[] = RG0[];  END IF; END IF;
   IF (ADR_WR[1..0] == 1) and PUSH THEN RG1[] = BOT[]; WR1 = VCC; ELSE WR1 = GND; IF (ADR_RD2_[1..0] == 1) and !WR1 THEN RG1[] = RAM.q[]; WRx1 = VCC; ELSE RG1[] = RG1[];  END IF; END IF;
   IF (ADR_WR[1..0] == 2) and PUSH THEN RG2[] = BOT[]; WR2 = VCC; ELSE WR2 = GND; IF (ADR_RD2_[1..0] == 2) and !WR2 THEN RG2[] = RAM.q[]; WRx2 = VCC; ELSE RG2[] = RG2[];  END IF; END IF;
   IF (ADR_WR[1..0] == 3) and PUSH THEN RG3[] = BOT[]; WR3 = VCC; ELSE WR3 = GND; IF (ADR_RD2_[1..0] == 3) and !WR3 THEN RG3[] = RAM.q[]; WRx3 = VCC; ELSE RG3[] = RG3[];  END IF; END IF;

   CASE ADR[1..0] IS
      WHEN 0 => DO[] = RG0[];
      WHEN 1 => DO[] = RG1[];
      WHEN 2 => DO[] = RG2[];
      WHEN 3 => DO[] = RG3[];
   END CASE;

   RAM.clock = CLK;
   RAM.rdaddress[] = ADR_RD[];
   RAM.wraddress[] = ADR_WR[];
   RAM.wren = PUSH;
   RAM.data[] = BOT[];
   test_ram_q[] = RAM.q[];
   
END;


На картинке выше схема проверки именно для этого стека, а не для предыдущей версии. После нескольких итераций "сборка-симуляция-поиск ошибок-исправление"
стек был доведен до рабочего состояния. В котором он был введен в схему форт-процессора и проверен уже там на рабочем железе.
Предельная частота работы стека в симуляторе - 195.01MHz равна предельной скорости работы встроенной памяти ПЛИС EP2C20F484C7, на которой проводились натурные испытания.

Таким образом, техническая задача, задуманная и описанная в первом посте топика - полностью выполнена.

п.с. Тему не закрываю, потому что идея сделать то же самое на VHDL так и осталась нерешенной.
Сообщение Добавлено: Вс май 09, 2010 18:42
  Заголовок сообщения:   Ответить с цитатой
WingLion писал(а):
Для Xilinx - вопрос лишь в том - а надо ли это там при условии наличия встроенной памяти другого типа?

Да, для Xilinx этой проблемы нет. Память отдает данные на следующем такте, и все происходит на системной тактовой частоте.
Сообщение Добавлено: Пт фев 19, 2010 23:24
  Заголовок сообщения:  Стек на встроенной памяти ПЛИС с кэшем в LCELL  Ответить с цитатой
1. Зачем это нужно? Встроенная синхронная память ПЛИС имеет свои нехорошие особенности.

- Во-первых, время выборки данных по заданному адресу составляет два такта, а не один, как хотелось бы.
- Во-вторых, при записи в память ПЛИС и считывании данных из того же адреса, куда ведется запись,
правильные данные на выходе появляются даже не через два, а через три такта (увы - экспериментальный факт для Альтеры).

Тем не менее, при последовательном считывании, даже если адрес меняется каждый такт,
данные на выходе блока памяти, хоть и с опозданием на два такта, но все же считываются с максимальной скоростью.

Подобное поведение встроенной памяти в ПЛИС мешает прямому построению стека на встроенной памяти в ПЛИС.
Прямо построенный стек, работает правильно, но команды стека (PUSH, POP, NOP и SWAP) исполняются только за три(даже не два!) такта.
В то же время, скорость работы встроенной памяти не столь высока, как хотелось бы. Она, как минимум, в два раза ниже скорости работы
логической ячейки ПЛИС (например, для EP2C20F484C7 тригеры LCELL способны работать на частоте 380MHz, а память имеет предельную частоту 195MHz).
Это обстоятельство еще более усугубляет положение со скоростью работы стека на встроенной памяти ПЛИС ф. ALTERA.

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

2. Принцип работы. Следуююий рисунок показывает упрощенную структурную схему стека.

Изображение

Четыре регистра представляют собой тот самый КЭШ вершины стека.
Выбрано именно четыре регистра, а не два, как было в первой реализации,
потому что задержка появления правильных данных на выходе памяти составляет до 3-х тактов.

Запись в память производится каждый раз, при появлении команды PUSH для стека.
Адресный регистр является указателем стека и меняется при появлении соответствующих команд так как указано в тексте на рисунке (язык AHDL).

Данные со входа стека пишутся по команде PUSH как в пямять, так и в регистры RGi.
номер регистра, в который ведется запись выбирается в соответствии с двумя младшими битами регистра адреса.
Эти же два бита записываются вместе с данными в память стека, которая на 3 бита шире, чем данные.
Три вспомогательных бита используются для выбора, в какой из регистров должны быть записаны данные, считанные из памяти.
Два бита выбирают регистр, третий разрешает/запрещает запись.

При работе стека в регистрах оказываются копии данных, сохраненных в памяти, в четырех верхних ячейках, соответствующих указателю стека.

При записи это происходит потому, что данные пишутся и в память и в регистры, при чтении - потому что данные в регистры перезаписываются из памяти. Для того, чтобы данные считывались из стека правильно, чтение из памяти производится не прямо по адресу указателя, а по адресу на 2 меньше указателя.
Так, что при считывании в регистрах оказывается два верхних элемента стека, один из которых передается на выход, а один готов для считывания на следующем такте. третий элемент в этот момент считывается из памяти, и копируется в соответствующий регистр, чтобы его можно было считать в дальнейшем.

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

3. Реализация. Далее представлена реализация данной идеи на языке AHDL. Кроме описанной выше схемы она содержит еще два элемента стека на регистрах, которые являются фактическими верхними элементами, с которыми можно производить действия независимо от остальной части схемы. В частности, команда SWAP выполняется за один такт без каких-либо проблем, связанных с невозможностью за один такт считать/записать в память два значения (если только эта память не двухпортовая).

В данной реализации использована двухпортовая пямять, но в ней один порт используется только на запись, второй только на чтение для того, чтобы эту конструкцию можно было использовать для более старых ПЛИС (таких как ACEX).

Код:
   TITLE "Stack LCELL RAM";

Код затерт, так как последующие тесты показали его неадекватность.
Более правильная схема - ниже в этой же теме   .

END;


Элемент RAM4Stack создается через Quartus MegaWizard с такими параметрами:

Название элемента в MegaWizard - "RAM: 2-PORT",
Ширина данных - 19 бит,
Количество слов в памяти 256 бит.

4. Результат компиляции.

для EP2C20F484C7

занятый объем: 248 LCELL менее 1% от объема ПЛИС
занятая память: 4864 BIT 2% от объема ПЛИС
предельная рабочая частота: 195.01MHz


5. Переход на VHDL. Попытка не удалась (уперлось в отсутствие опыта работы с VHDL).
Для Альтеры оно как бы и не нужно. AHDL достаточно.
Для Xilinx - вопрос лишь в том - а надо ли это там при условии наличия встроенной памяти другого типа?
Сообщение Добавлено: Пт фев 19, 2010 20:11

Часовой пояс: UTC + 3 часа [ Летнее время ]


Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
phpBB сборка от FladeX // Русская поддержка phpBB