Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Модуль RTC.
Форум разработчиков электроники ELECTRONIX.ru > Программируемая логика ПЛИС (FPGA,CPLD, PLD) > Языки проектирования на ПЛИС (FPGA)
Jenya7
Сделал модуль RTC
Код
entity RTC is
port(
     RST      : in    Std_logic;
     CLK      : in    Std_logic;
      
    SECONDS   : out    Std_logic_vector(5 downto 0);
    MINUTES   : out    Std_logic_vector(5 downto 0);
    HOURS     : out     Std_logic_vector(4 downto 0);
    
     DAY       : out    Std_logic_vector(5 downto 0);
    MONTH     : out     Std_logic_vector(3 downto 0);
    YEAR      : out    Std_logic_vector(11 downto 0)
  );
end RTC;

и вычисляю часы, минуты, дни и так далее.
Но модуль надо инициализировать реальным временем. Получается надо сделать что то вроде такого
Код
entity RTC is
port(
     RST      : in    Std_logic;
     CLK      : in    Std_logic;
      
    SECONDS_IN   : in    Std_logic_vector(5 downto 0);
    MINUTES_IN   : in    Std_logic_vector(5 downto 0);
    HOURS_IN     : in     Std_logic_vector(4 downto 0);
    DAY_IN       : in     Std_logic_vector(5 downto 0);
    MONTH_IN    : in Std_logic_vector(3 downto 0);
    YEAR_IN      : in Std_logic_vector(11 downto 0);

        SET  : in Std_logic;

    SECONDS_OUT   : out    Std_logic_vector(5 downto 0);
    MINUTES_OUT   : out    Std_logic_vector(5 downto 0);
    HOURS_OUT     : out    Std_logic_vector(4 downto 0);
    DAY_OUT       : out    Std_logic_vector(5 downto 0);
    MONTH_OUT    : out    Std_logic_vector(3 downto 0);
    YEAR_OUT      : out    Std_logic_vector(11 downto 0)
  );
end RTC;

набор для ввода и набор для вывода. А по другому никак?
Flip-fl0p
Цитата(Jenya7 @ Sep 4 2017, 14:44) *
Сделал модуль RTC

Можно и по-другому.
Один вход для загрузки данных назовём его DATA_LOAD : Std_logic_vector(N-1 downto 0);
И загружаете по нему последовательно данные. Разрядность выбираете в зависимости от придуманного Вами алгоритма.
Загружать данные можно последовательно сначала секунды, потом минуты, потом часы, потом дни, месяцы, года.
Jenya7
Цитата(Flip-fl0p @ Sep 4 2017, 16:53) *
Можно и по-другому.
Один вход для загрузки данных назовём его DATA_LOAD : Std_logic_vector(N-1 downto 0);
И загружаете по нему последовательно данные. Разрядность выбираете в зависимости от придуманного Вами алгоритма.
Загружать данные можно последовательно сначала секунды, потом минуты, потом часы, потом дни, месяцы, года.

последовательно не очень удобно. у меня связь с DSP паралельная шина данных и шина адреса.
Flip-fl0p
Цитата(Jenya7 @ Sep 4 2017, 14:57) *
последовательно не очень удобно. у меня связь с DSP паралельная шина данных и шина адреса.

Тогда не пойму Вашего вопроса. Что вы хотите получить в итоге ?
Jenya7
Цитата(Flip-fl0p @ Sep 4 2017, 17:02) *
Тогда не пойму Вашего вопроса. Что вы хотите получить в итоге ?

хочу получить способ настраивать часы реального времени.
хотя..по сигналу SET я могу собрать все данные и передать сериально.
Tausinov
Цитата(Jenya7 @ Sep 4 2017, 14:44) *
Сделал модуль RTC и вычисляю часы, минуты, дни и так далее.
Но модуль надо инициализировать реальным временем. Получается надо сделать что то вроде такого
...
набор для ввода и набор для вывода. А по другому никак?


Способов можно придумать, наверное, немало, но не будут ли они при этом более неудачными? Что не устраивает в этом варианте?
Jenya7
Цитата(Tausinov @ Sep 4 2017, 17:42) *
Способов можно придумать, наверное, немало, но не будут ли они при этом более неудачными? Что не устраивает в этом варианте?

хотелось послушать более опытных товарищей. я не очень искушен в написании под FPGA.
Maverick
Цитата(Jenya7 @ Sep 4 2017, 16:27) *
хотелось послушать более опытных товарищей. я не очень искушен в написании под FPGA.

чем не устраивает внешняя микросхема
например

вот тут можете под свои нужды выбрать(параметрический поиск)
Jenya7
Цитата(Maverick @ Sep 4 2017, 19:01) *
чем не устраивает внешняя микросхема
например

железо уже разработано. это старый проект. я только модули добавляю.
Inanity
Цитата(Jenya7 @ Sep 4 2017, 17:10) *
железо уже разработано. это старый проект. я только модули добавляю.


Будьте готовы к тому, что такие часы будут не так точны, как специализированная RTC микросхема.
Jenya7
Цитата(Inanity @ Sep 4 2017, 19:43) *
Будьте готовы к тому, что такие часы будут не так точны, как специализированная RTC микросхема.

ну это да. но периодически происходит корекция.

а как мне высчитать високосный год? в Си делал
Код
uint32_t IsLeapYear(uint32_t year)
{
    if(((year%4==0)&&(year%100!=0))||(year%400==0))
        return 1;
    else
       return 0;
}

а тут
Код
function IsLeapYear(year : integer) return std_logic_vector is
variable ret : std_logic_vector;
begin
    if( (year mod 4)= 0 and (year mod 100) /= 0 or (year mod 400) = 0) then
        ret := 1;
     else
        ret := 0;
    end if;    
return ret;        
end function IsLeapYear;

ругается
Error (10500): VHDL syntax error at RTC.vhd(41) near text "or"; expecting ")", or ","
Error (10500): VHDL syntax error at RTC.vhd(41) near text ")"; expecting "then"
вроде со скобками все в порядке
Tausinov
Цитата(Jenya7 @ Sep 4 2017, 17:51) *
Код
function IsLeapYear(year : integer) return std_logic_vector is
variable ret : std_logic_vector;
begin
    if( (year mod 4)= 0 and (year mod 100) /= 0 or (year mod 400) = 0) then
        ret := 1;
     else
        ret := 0;
    end if;    
return ret;        
end function IsLeapYear;

ругается
Error (10500): VHDL syntax error at RTC.vhd(41) near text "or"; expecting ")", or ","
Error (10500): VHDL syntax error at RTC.vhd(41) near text ")"; expecting "then"
вроде со скобками все в порядке


Возьмите в скобки операцию "И" вместе с операндами. Видимо, что-то с приоритетами операций. Ну и ret нужно все-таки значения std_logic_vector'а присваивать, а не целые числа.
Jenya7
Цитата(Tausinov @ Sep 4 2017, 20:19) *
Возьмите в скобки операцию "И" вместе с операндами. Видимо, что-то с приоритетами операций. Ну и ret нужно все-таки значения std_logic_vector'а присваивать, а не целые числа.

так тоже ругается
Код
function IsLeapYear(year : integer) return std_logic_vector is
variable ret : std_logic_vector;
begin
    if ( ((year mod 4) = 0) and ((year mod 100) /= 0) or ((year mod 400) = 0) ) then
        ret <= '1';
     else
        ret <= '0';
    end if;    
return ret;        
end function IsLeapYear;
Tausinov
Цитата(Jenya7 @ Sep 4 2017, 18:29) *
так тоже ругается
Код
function IsLeapYear(year : integer) return std_logic_vector is
variable ret : std_logic_vector;
begin
    if ( ((year mod 4) = 0) and ((year mod 100) /= 0) or ((year mod 400) = 0) ) then
        ret <= '1';
     else
        ret <= '0';
    end if;    
return ret;        
end function IsLeapYear;


Ага, еще не заметил:
variable ret : std_logic_vector(0 downto 0);
вместо
variable ret : std_logic_vector;
и значения в двойных кавычках должны быть вместо одинарных.

Код
library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

entity isLeapYear is
end isLeapYear;

architecture behav of isLeapYear is

    signal testYear : integer := 2008;

    function IsLeapYear(year : integer) return std_logic_vector is
        variable ret : std_logic_vector(0 downto 0);
    begin
        if ((year mod 4 = 0 and year mod 100 /= 0) or (year mod 400 = 0)) then
        ret := "1";
      else
        ret := "0";
      end if;    

        return ret;        
    end function IsLeapYear;
begin

    process
        variable temp : std_logic_vector(0 downto 0);
    begin
        temp := IsLeapYear(testYear);
        report "function result is " & integer'image(to_integer(unsigned(temp)));
        wait;
    end process;

end behav;
Jenya7
Цитата(Tausinov @ Sep 4 2017, 20:31) *
Ага, еще не заметил:
variable ret : std_logic_vector(0 downto 0);
вместо
variable ret : std_logic_vector;
и значения в двойных кавычках должны быть вместо одинарных.

Код
library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;

entity isLeapYear is
end isLeapYear;

architecture behav of isLeapYear is

    signal testYear : integer := 2008;

    function IsLeapYear(year : integer) return std_logic_vector is
        variable ret : std_logic_vector(0 downto 0);
    begin
        if ((year mod 4 = 0 and year mod 100 /= 0) or (year mod 400 = 0)) then
        ret := "1";
      else
        ret := "0";
      end if;    

        return ret;        
    end function IsLeapYear;
begin

    process
        variable temp : std_logic_vector(0 downto 0);
    begin
        temp := IsLeapYear(testYear);
        report "function result is " & integer'image(to_integer(unsigned(temp)));
        wait;
    end process;

end behav;

да. спасибо. так компилируется.

в конце концов вот такая петрушка получилась.
CODE

library IEEE;
use IEEE.std_logic_1164.all;
use ieee.numeric_std.all;
use IEEE.STD_LOGIC_UNSIGNED.ALL;

entity RTC is
port(
RST : in Std_logic;
CLK : in Std_logic;

SET :In Std_logic;

SECONDS_SET : in Std_logic_vector(5 downto 0);
MINUTES_SET : in Std_logic_vector(5 downto 0);
HOURS_SET : in Std_logic_vector(4 downto 0);
DAY_SET : in Std_logic_vector(5 downto 0);
MONTH_SET : in Std_logic_vector(3 downto 0);
YEAR_SET : in Std_logic_vector(11 downto 0);

MILISECONDS : out Std_logic_vector(9 downto 0);
SECONDS : out Std_logic_vector(5 downto 0);
MINUTES : out Std_logic_vector(5 downto 0);
HOURS : out Std_logic_vector(4 downto 0);
DAY : out Std_logic_vector(5 downto 0);
MONTH : out Std_logic_vector(3 downto 0);
YEAR : out Std_logic_vector(11 downto 0)

--DAY_OF_WEEK :in Std_logic_vector(3 downto 0)
);
end RTC;



architecture STRUCTURE of RTC is

function IsLeapYear(year : integer) return std_logic_vector is
variable ret : std_logic_vector(0 downto 0);
begin
if ((year mod 4 = 0 and year mod 100 /= 0) or (year mod 400 = 0)) then
ret := "1";
else
ret := "0";
end if;
return ret;
end function IsLeapYear;

type arr_type1 is array (0 to 12) of integer range 0 to 32; -- := (0,31,28,31,30,31,30,31,31,30,31,30,31);
signal days_in_month : arr_type1 := (0,31,28,31,30,31,30,31,31,30,31,30,31);

signal count : integer := 1;
signal tick_1ms : std_logic := '0';

signal milisec : integer range 0 to 1000 := 0;
signal sec,min,hour : integer range 0 to 60 := 0;
signal days : integer range 0 to 31 := 1;
signal months : integer range 0 to 12 := 1;
signal years : integer := 0;

signal days_per_month : integer range 0 to 31 := 0;

begin

MILISECONDS <= std_logic_vector(to_unsigned(milisec,10));
SECONDS <= std_logic_vector(to_unsigned(sec,6));
MINUTES <= std_logic_vector(to_unsigned(min,6));
HOURS <= std_logic_vector(to_unsigned(hour,5));

DAY <= std_logic_vector(to_unsigned(days,6));
MONTH <= std_logic_vector(to_unsigned(months,4));
YEAR <= std_logic_vector(to_unsigned(years, 12));


--clk generation. For 30 MHz clock this generates 1 milisec clock.
process (CLK,RST)

begin

if (RST='1') then
count <= 1;
elsif (rising_edge(CLK) ) then
count <= count + 1;
if(count = 15000) then --15000000
tick_1ms <= not tick_1ms;
count <= 1;
end if;
end if;

end process;


process (CLK,RST)
begin

if (SET='1') then
sec <= to_integer(unsigned(SECONDS_SET));
min <= to_integer(unsigned(MINUTES_SET));
hour <= to_integer(unsigned(HOURS_SET));
days <= to_integer(unsigned(DAY_SET));
months <= to_integer(unsigned(MONTH_SET));
years <= to_integer(unsigned(YEAR_SET));
elsif (rising_edge(tick_1ms) ) then
milisec <= milisec + 1;
if (milisec = 999) then
milisec <= 0;
sec <= sec+ 1;
end if;
if(sec = 59) then
sec <= 0;
min <= min + 1;
end if;
if(min = 59) then
min <= 0;
hour <= hour + 1;
end if;
if(hour = 23) then
hour <= 0;
days <= days + 1;
if (months = 2) then --calculate days for february
if (IsLeapYear(years) = 1) then
days_per_month <= 29;
else
days_per_month <= 28;
end if;
else
days_per_month <= days_in_month(months);
end if;
end if;
if(days = days_per_month) then
days <= 0;
months <= months + 1;
end if;
if (months = 12) then
months <= 0;
years <= years + 1;
end if;

end if;

end process;

end STRUCTURE;

Flip-fl0p
Код
use IEEE.STD_LOGIC_UNSIGNED.ALL;

Уберите её, она лишняя. И не является стандартом.
andrew_b
Цитата(Jenya7 @ Sep 4 2017, 18:42) *
Код
(year mod 100 /= 0) or (year mod 400 = 0)
Хотелось бы узнать, во что это вылилось.
Jenya7
Цитата(andrew_b @ Sep 5 2017, 11:26) *
Хотелось бы узнать, во что это вылилось.

не знаю. еще не тестировал.
_Anatoliy
Цитата(Flip-fl0p @ Sep 4 2017, 19:41) *
Код
use IEEE.STD_LOGIC_UNSIGNED.ALL;

Уберите её, она лишняя. И не является стандартом.

Без неё у меня векторы не складываются.
Код
library ieee;
use ieee.std_logic_1164.all;
--use ieee.STD_LOGIC_UNSIGNED.all;
use ieee.NUMERIC_STD.all;
...................................
    signal cnt    : STD_LOGIC_VECTOR(7 downto 0);
begin
process(Clk,rst) is
    if (RISING_EDGE(Clk)) then
        cnt <= cnt+1;
...................
# Error: COMP96_0071: TestBench/modulator_TB.vhd : (182, 42): Operator "+" is not defined for such operands.

А с ней всё o`k.
Flip-fl0p

Так а вы счетчик объявите как тип UNSIGNED и тогда можно будет записать так:

Код
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
--...................................
    SIGNAL CNT    : UNSIGNED(7 DOWNTO 0);
BEGIN
PROCESS(CLK,RST) IS
    IF (RISING_EDGE(CLK)) THEN
        CNT <= CNT + "1";
--...................

Или сразу преобразовывайте типы :
Код
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
--...................................
    SIGNAL CNT    : STD_LOGIC_VECTOR(7 DOWNTO 0);
BEGIN
PROCESS(CLK,RST) IS
    IF (RISING_EDGE(CLK)) THEN
        CNT := STD_LOGIC_VECTOR(UNSIGNED(CNT) + 1);

А потом конвертируйте тип UNSIGNED в STD_LOGIC_VECTOR. Но это можно делать не всегда.
Или объявите счетчик как INTEGER а потом преобразуйте INTEGER в STD_LOGIC_VECTOR средствами библиотеки NUMERIC_STD.
_Anatoliy
Цитата(Flip-fl0p @ Sep 5 2017, 11:43) *
Но это можно делать не всегда.

В том то и дело...
Цитата(Flip-fl0p @ Sep 5 2017, 11:43) *
Или объявите счетчик как INTEGER а потом преобразуйте INTEGER в STD_LOGIC_VECTOR средствами библиотеки NUMERIC_STD.

А смысл? Имхо, проще подключить библиотеку и не париться.
Flip-fl0p
Цитата(_Anatoliy @ Sep 5 2017, 11:50) *
В том то и дело...

А смысл? Имхо, проще подключить библиотеку и не париться.

Смысл в том, что библиотека NUMERIC_STD является стандартизированной библиотекой.
А библиотека STD_LOGIC_UNSIGNED -это не стандартизированная библиотека.
Я например не могу дать гарантию того что это библиотека будет работать всегда одинаково в любой версии САПР, в следствии чего я не могу дать гарантии того, что мои ранее написанные проекты будут работать так, как они задумывались. Если САПР не менять и не обновлять (фиг его знает, что поменяют обновления), то вроде и не страшно...
Но поскольку я начал изучать VHDL когда уже была разработана библиотека NUMERIC_STD то я сразу начал применять только её.
Я всегда за строгое соблюдение стандарта, были прецеденты на прошлой работе когда отклонения от ГОСТ приводили к достаточно дорогим ошибкам....

_Anatoliy
Цитата(Flip-fl0p @ Sep 5 2017, 12:03) *
Смысл в том, что библиотека NUMERIC_STD является стандартизированной библиотекой.

Да знаю я об этом. Просто за 20 лет работы с FPGA указанная выше тройка библиотек успешно применялась во всех моих проектах. Следовательно, та ситуация о которой Вы говорите имеет очень низкую вероятность возникновения. Я не навязываю своего мнения, что ,мол, все должны так делать, но когда речь идёт о больших проектах у меня не дрогнет рука применить эту библиотеку, позволяющую избавиться от лишних преобразований типов.
Flip-fl0p
Цитата(_Anatoliy @ Sep 5 2017, 12:25) *

То-же верно.
Я уже привык к NUMERIC_STD и не особо чувствую дискомфорта.
Я считаю что главное понимать когда и зачем нужно применять ту или иную библиотеку.
andrew_b
Цитата(Flip-fl0p @ Sep 5 2017, 11:43) *
А потом конвертируйте тип UNSIGNED в STD_LOGIC_VECTOR. Но это можно делать не всегда.
Когда нельзя?
_Anatoliy
Цитата(andrew_b @ Sep 5 2017, 12:55) *
Когда нельзя?

Например, когда лень в каждой строчке лепить преобразование...

Цитата(Flip-fl0p @ Sep 5 2017, 12:42) *
Я считаю что главное понимать когда и зачем нужно применять ту или иную библиотеку.

Спорить с этим невозможно.
Flip-fl0p
Цитата(andrew_b @ Sep 5 2017, 12:55) *
Когда нельзя?

Один из вариантов когда значение выводится на выходной порт. И для модуля создается шапка Testbench средствами Quartus. Тогда в модуле к примеру выходной порт будет типом UNSIGNED, а Quartus создаст в Testbench порт как STD_LOGIC_VECTOR. И придётся где-то вносить изменения, чтобы заработало.
Так-же если придется выдать значения типа UNSIGNED типу STD_LOGIC_VECTOR
Tausinov
А зачем преобразования делать в каждой строке? Делаем все необходимые внутренние сигналы - signed/unsigned, а порты - std_logic_vector. Остается лишь в конце сделать out_port <= std_logic_vector(internal_signed);. Единственное, что иногда раздражает - то, что вместо коротеньких SXT/EXT надо лепить resize с кучей преобразований, но это дело привычки.
_Anatoliy
Цитата(Tausinov @ Sep 5 2017, 13:13) *
А зачем преобразования делать в каждой строке? Делаем все необходимые внутренние сигналы - signed/unsigned, а порты - std_logic_vector. Остается лишь в конце сделать out_port <= std_logic_vector(internal_signed);.

Ну да, так и делаю когда имею дело с шиной данных в блоках DSP. Но для банального счётчика считаю это лишним.
Flip-fl0p
Цитата(_Anatoliy @ Sep 5 2017, 15:46) *
Ну да, так и делаю когда имею дело с шиной данных в блоках DSP. Но для банального счётчика считаю это лишним.

А я вообще счетчики в отдельных модулях держу. Один раз описал его, отладил и больше к нему не возвращаюсь. Только в параметрах указываю значение максимального счета. Лично я так меньше ошибаюсь при написании проектов
CODE
Код
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;

ENTITY COUNTER_ENA IS
    GENERIC
    (
        MAX_VALUE      : INTEGER := 126                    -- До скольки считает счетчик(от нуля до MAX_VALUE)
    );
    PORT
    (
        CLK                     : IN  STD_LOGIC;
        ENA                     : IN  STD_LOGIC;
        DATA_OUT                : OUT INTEGER RANGE 0 TO MAX_VALUE
    );
END ENTITY;

ARCHITECTURE RTL OF COUNTER_ENA IS
    FUNCTION LOG2 (MAX_VALUE : INTEGER) RETURN INTEGER IS -- Функция вычесления логарифма по основанию 2 для определения разрядности
        VARIABLE CNT    : INTEGER := 0;                   -- Счетчик для подсчета количества делений на 2
        VARIABLE TEMP   : INTEGER := MAX_VALUE + 1;       -- Делимое -  максимальное количество состояний счетчика
    BEGIN
        WHILE (TEMP > 1) LOOP                             -- Пока делимое больше 1 совершаем цикл деления на 2
            CNT  := CNT + 1;                             -- Считаем количество циклов деления
            TEMP := TEMP/2;                               -- Делим число на 2 каждый цикл
        END LOOP;
        RETURN CNT;                                       -- Значение счетчика и есть логарифм
    END LOG2;
  
    SIGNAL COUNTER_INTEGER  : INTEGER RANGE 0 TO MAX_VALUE        := 0;                  -- Счетчик обнуляемый условием максимального счета
    SIGNAL COUNTER_UNSIGNED : UNSIGNED(LOG2(MAX_VALUE)-1 DOWNTO 0)  := (OTHERS => '0');  -- Счетчик с автоматическом обнулени при переполнении
BEGIN

    --================================================================================
==========================
    -- Если максимальное значение счетчика переведенное в двоичное число не состоит из одних только единиц
    -- Значит у нас счетчик обнуляется значением максимального счета т.е до наступления переполнения разрядов
    --================================================================================
==========================
    GEN_RST_COND :  IF ( TO_UNSIGNED(MAX_VALUE,LOG2(MAX_VALUE) ) /= ( LOG2(MAX_VALUE)-1 DOWNTO 0 => '1' ) ) GENERATE
        CNT_PROC : PROCESS
        (
            CLK
        )
        BEGIN
            IF (RISING_EDGE(CLK)) THEN          
                IF (ENA = '1') THEN                                -- Сигнал разрешения работы счетчика
                    IF (COUNTER_INTEGER = MAX_VALUE) THEN          -- При наступлении максимального значения счетчика
                        COUNTER_INTEGER <= 0;                      -- Обнулим его
                    ELSE
                        COUNTER_INTEGER <= COUNTER_INTEGER + 1;    -- Иначе будем его инкрементировать
                    END IF;
                END IF;
            END IF;
        END PROCESS;              
        DATA_OUT <= COUNTER_INTEGER;
    END GENERATE;
    
    --================================================================================
==========================
    -- Если максимальное значение счетчика это (2**N - 1)
    -- Значит у нас полный счетчик, который обнуляется переполнением разрядов
    --================================================================================
==========================
    GEN : FOR I IN 0 TO 30 GENERATE
        OVERFLOW :  IF (2**I-1 = MAX_VALUE) GENERATE  
            CNT_PROC : PROCESS
            (
                CLK
            )
            BEGIN    
                IF (RISING_EDGE(CLK)) THEN      
                    IF (ENA = '1') THEN                               -- Сигнал разрешения работы счетчика
                        COUNTER_UNSIGNED <= COUNTER_UNSIGNED + "1";   -- Инкрементируем его каждый такт
                    END IF;
                END IF;
            END PROCESS;  
            DATA_OUT <= TO_INTEGER(COUNTER_UNSIGNED);
        END GENERATE;
    END GENERATE;
END ARCHITECTURE;
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.