Перейти к содержанию
    

SystemVerilog always_comb infinite loop

9 hours ago, dxp said:

Тем не менее, ситуация не такая простая. Например, код из стартового поста не зацикливается, а по логике должен! Но нет!! Вопрос: почему?

Да с чего вы взяли, что  должен-то? Переменная a на момент конца always не изменяет своего значения =1, присвоенного на самой первой отработке always блока. От b она не зависит. Так с чего?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

2 часа назад, Raven сказал:

Да с чего вы взяли, что  должен-то? Переменная a на момент конца always не изменяет своего значения =1, присвоенного на самой первой отработке always блока. От b она не зависит. Так с чего?

Зато она меняет его внутри блока, и это уже формально генерирует событие дельта-цикла. Вы перечитайте весь тред внимательнее (ибо ничего нового уже сказать не могу), посмотрите ссылку на тему @Timmy (с чем он столкнулся) и посмотрите ссылку из стартового поста, про опцию симулятора ncsim -delay_trigger - что она делает и зачем её советовали применить.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А я призываю вас обратиться к спецификациям на SystemVerilog и Verilog (в последнем кое-что разъяснено более подробно).

 

Оператор b = a из блока B не увидит промежуточного изменения a (1 => 0 => 1) в любом из 2-х возможных вариантов:

 

1. Наиболее вероятный. Недетерминированность порядка отработки присвоений сигналам/переменным операторами из разных always блоков развязывает руки симулятору в деле оптимизации. И конечно, любой коммерческий симулятор предпочтет вначале отработать все назначения одной и той же переменной внутри одного блока, и только потом переходить к другим процессам. Просто чтобы не создавать себе глупой работы, тупо увеличивающей время симуляции на ровном месте.

 

2. Но и в случае туповатого, но добросовестного симулятора блок always переменной b тоже не увидит промежуточного изменения. Следите за руками (все действия происходят в одном и том же временном слоте):

      а) пусть все начнется с блока A: отрабатывается присвоение a = 0; оно отрабатывается, как ему и положено, во временнОм регионе Active данного слота времени. Результатом же его является update event, запланированный во временнОм регионе Inactive этого же самого слота времени (он идет после Active)

      б) тут по какой-то причине симулятор откладывает дальнейшую работу с always блоком A, и переключается на какие-то другие процессы, имеющие также события к обработке в регионе Active;

      в) среди вышеуказанных событий в регионе Active для блока B ничего пока нет (изменение a назначено в регион Inactive, как мы помним, а до него еще дело не дошло)

      г) в конце концов симулятор возвращается в блок A, чтобы закончить брошенное на пол-пути дело, все еще отрабатывая события региона Active. Тут он отрабатывает второй оператор (a = 1), результатом которого будет снятие с пробега ранее запланированного события (а = 0), т.к. они запланированы на одно и то же время, и конечное присвоение не изменяет значение переменной, унаследованное из предыстории.

     д) результат - отсутствие какого-либо события в регионе Inactive, могущего привести к еще одной итерации через регион Active, и тем самым могущего быть увиденным блоком B.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

12 часов назад, Raven сказал:

А я призываю вас обратиться к спецификациям на SystemVerilog и Verilog (в последнем кое-что разъяснено более подробно).

Не подскажете, в каком пункте спеки это все, что вы ниже изложили, описано? Я вот не нашёл чёткого описания последовательности действий - например, обрабатываются Active регионы разных блоков - последовательно, параллельно, по событиям или "каруселью". Например, если переменная изменила значение, происходит ли переход к обработке Active регионов других блоков, которые зависят от этой переменной, или несмотря на это изменение продолжается обработка Active региона этого блока.

 

Эксперименты с квестой показали, что она не прыгает из середины блока в другой блок, а доходит до конца блока, но это не отменяет планировки - после такого события она один (или два) разок всё же запрыгывает в другой блок. То, что это происходит, указывает на то, что планировка события от локального изменения всё же происходит. А то, что это случается всего лишь разово, указывает на то, что там есть какой-то механизм выявления подобных "пустых" циклов и прерывания их.

 

12 часов назад, Raven сказал:

2. Но и в случае туповатого, но добросовестного симулятора блок always переменной b тоже не увидит промежуточного изменения. Следите за руками (все действия происходят в одном и том же временном слоте):

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

 

12 часов назад, Raven сказал:

Результатом же его является update event, запланированный во временнОм регионе Inactive этого же самого слота времени (он идет после Active)

Про Inactive вы зря сказали. Он тут вообще не причём. Inactive - это обработка событий, помеченных #0. У нас их нет, и вообще применение #0 давно не рекомендуется к использованию, оставлено для совместимости. В приличных дизайнах этого нет, т.ч. этот регион можно вообще не упоминать.

 

Тем не менее, факт остаётся фактом: иногда симулятор залипает в бесконечном цикле на таком коде, хотя значение переменной на входе и на выходе одно и то же, и события вроде тут не должно возникать. Это подтверждается примерами по ссылкам, это случилось у меня в рабочем проекте (из-за чего тема эта и возникла). У вас есть объяснение такому поведению тула?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, dxp said:

Не подскажете, в каком пункте спеки это все, что вы ниже изложили, описано?

Так и знал. что попросите, не стал пока закрывать во вьюере эти странички :)

Начнем от главного, чтобы не возвращаться - Nondeterminism (это SV spec):

4.7 Nondeterminism
One source of nondeterminism is the fact that active events can be taken off the Active or Reactive event
region and processed in any order. Another source of nondeterminism is that statements without timecontrol constructs in procedural blocks do not have to be executed as one event. Time control statements are
the # expression and @ expression constructs (see 9.4). At any time while evaluating a procedural statement,
the simulator may suspend execution and place the partially completed event as a pending event in the event
region. The effect of this is to allow the interleaving of process execution, although the order of interleaved
execution is nondeterministic and not under control of the user.

Далее - Blocking and NonBlocking assignments (последний, кстати, это тот самый NBA на блок-схеме Figure 4.1)
 

4.9.3 Blocking assignment
A blocking assignment statement (see 10.4.1) with an intra-assignment delay computes the right-hand side
value using the current values, then causes the executing process to be suspended and scheduled as a future
event. If the delay is 0, the process is scheduled as an Inactive event for the current time. If a blocking
assignment with zero delay is executed from a Reactive region, the process is scheduled as a Re-Inactive
event.
When the process is returned (or if it returns immediately if no delay is specified), the process performs the
assignment to the left-hand side and enables any events based upon the update of the left-hand side. The
values at the time the process resumes are used to determine the target(s). Execution may then continue with
the next sequential statement or with other Active or Reactive events.


4.9.4 Nonblocking assignment
A nonblocking assignment statement (see 10.4.2) always computes the updated value and schedules the
update as an NBA update event, either in the current time step if the delay is zero or as a future event if the
delay is nonzero. The values in effect when the update is placed in the event region are used to compute both
the right-hand value and the left-hand target.

Как видим, результат evaluation of a blocking statement планируется в Inactive region (что логично - вход и выход одной итерации надо как-то отделять друг от друга). Туда же идет результат обработки операторов с #0 (и это тоже логично). Так что про Inactive - это не зря было сказано.

Quote

Я вот не нашёл чёткого описания последовательности действий - например, обрабатываются Active регионы разных блоков - последовательно, параллельно, по событиям или "каруселью". Например, если переменная изменила значение, происходит ли переход к обработке Active регионов других блоков, которые зависят от этой переменной, или несмотря на это изменение продолжается обработка Active региона этого блока.

В 4.7 выше сказано же - не детерминировано это, причем намеренно - чтобы была свобода реализации и оптимизации у симулятора. А как сказано в 4.9.3, планирование будет осуществлено в Inactive, а не Active, так что обработка Active блоков, зависящих от этой переменной, ничего на этой итерации не даст.

В конце текущей итерации, если обработка событий из Active закончилась, произойдет проверка наличия событий в Inactive, и если там что-то есть, перенос этих событий в Active и последующий заход на следующую итерацию. См. ниже (section 4.5):

execute_simulation {
	T = 0;
	initialize the values of all nets and variables;
	schedule all initialization events into time zero slot;
	while (some time slot is nonempty) {
		move to the first nonempty time slot and set T;
		execute_time_slot (T);
	}
}

execute_time_slot {
	execute_region (Preponed);
	execute_region (Pre-Active);
	while (any region in [Active ... Pre-Postponed] is nonempty) {
		while (any region in [Active ... Post-Observed] is nonempty) {
			execute_region (Active);
			R = first nonempty region in [Active ... Post-Observed];
			if (R is nonempty)
			move events in R to the Active region;
		}
		while (any region in [Reactive ... Post-Re-NBA] is nonempty) {
			execute_region (Reactive);
			R = first nonempty region in [Reactive ... Post-Re-NBA];
			if (R is nonempty)
			move events in R to the Reactive region;
		}
		if (all regions in [Active ... Post-Re-NBA] are empty)
			execute_region (Pre-Postponed);
	}
	execute_region (Postponed);
}

execute_region {
	while (region is nonempty) {
		E = any event from region;
		remove E from the region;
		if (E is an update event) {
			update the modified object;
			schedule evaluation event for any process sensitive to the object;
		} else { /* E is an evaluation event */
			evaluate the process associated with the event and possibly
			schedule further events for execution;
		}
	}
}
Quote

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

Сдается мне, что нормальным симулятором это точно не инорируется (если вообще дойдет до этого, т.к. еще логичнее отработать вначале до конца все присвоения переменной a в блоке A). При наличии события, которое надо вставить (запланировать), просматривается список запланированных событий по хорде a-to-b, и если там что-то есть на тот же планируемый момент времени, то он модифицируется в соответствии с новым, вставляемым, событием. Частный случай такой модификации - изъятие события из списка как ничтожного (если событие аннигилируется вторым изменением). Просто оптимизация производительности, ничего личного :-)

Quote

Тем не менее, факт остаётся фактом: иногда симулятор залипает в бесконечном цикле на таком коде, хотя значение переменной на входе и на выходе одно и то же, и события вроде тут не должно возникать. Это подтверждается примерами по ссылкам, это случилось у меня в рабочем проекте (из-за чего тема эта и возникла). У вас есть объяснение такому поведению тула?

Детали воспроизведения такого поведения я пока не изучал. Могу пока лишь предположить, что вам-таки удается в отдельных случаях так "наклонить" симулятор, что это промежуточное событие все же достигает блока B.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Мне на VCS такое поведение не попадалось.

Вы можете привести точные образцы кода (и опций симулятора, если нужно), необходимые для воспроизведения этого эффекта?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, Raven сказал:

Начнем от главного, чтобы не возвращаться - Nondeterminism (это SV spec):

Все эти фрагменты я видел и внимательно изучал. Поэтому и написал, что нет внятного объяснения, как именно обрабатываются активные регионы: по этим докам - как угодно. Поэтому генерирование события при локальном изменении переменной тут вполне допустимо. Как и немедленный переход в другой блок.

 

1 час назад, Raven сказал:

Как видим, результат evaluation of a blocking statement планируется в Inactive region (что логично - вход и выход одной итерации надо как-то отделять друг от друга). Туда же идет результат обработки операторов с #0 (и это тоже логично). Так что про Inactive - это не зря было сказано.

Нет, не так. Вот из вашей же цитаты:

"A blocking assignment statement (see 10.4.1) with an intra-assignment delay computes the right-hand side
value using the current values, then causes the executing process to be suspended and scheduled as a future
event. If the delay is 0, the process is scheduled as an Inactive event for the current time. If a blocking
assignment with zero delay is executed from a Reactive region, the process is scheduled as a Re-Inactive
event."

 

Т.е. тут речь идёт, во-первых, только о выражениях с внутренними задержками, при которых выполнение откладывается, во-вторых, если и только если задержка #0, выполнение откладывается в Inactive регион. Т.к. ровно так, как я и написал выше - Inactive регион используется только при задержках #0. Которых у нас нет. И которые использовать с современными симуляторами не рекомендуются.

53 минуты назад, Raven сказал:

Вы можете привести точные образцы кода (и опций симулятора, если нужно), необходимые для воспроизведения этого эффекта?

В этом-то и проблема - так просто это не воспроизводится. Например, когда у меня проект заloopился (иначе и не скажешь), я что только не делал, чтобы понять и пофиксить проблему, в т.ч. написал отдельный проектик, который повторяет зацикленный код - там три процесса по кругу ходили, один из них FSM. Так вот несмотря на всю почти одинаковость кода, этот тестовый проект мне загнать в цикл не удалось. В обоих проектах ходил по блокам в симе по шагам, отслеживал, куда он переходит. Внешне все одинаково за исключением того, что в одном случае (тестовом) он после одного (или двух) пустых заходов прекращает ходить по кругу, а в другом (рабочем) продолжает. Общий контекст у рабочего проекта, конечно, гораздо сложнее. Вот отсюда делаю вывод, что события-то от локального изменения генерируются всегда, но есть механизмы анализа и подавления зацикливания от этого. Только иногда сим не справляется.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 hour ago, dxp said:

Все эти фрагменты я видел и внимательно изучал. Поэтому и написал, что нет внятного объяснения, как именно обрабатываются активные регионы: по этим докам - как угодно. Поэтому генерирование события при локальном изменении переменной тут вполне допустимо. Как и немедленный переход в другой блок.

Не совсем уж как угодно. Да, до ОПРЕДЕЛЕННОЙ степени это так. До какой - описано в остальных частях. Да хоть в той же части о блокирующих присваиваниях.
 

Quote

Нет, не так. Вот из вашей же цитаты:

.....

Т.е. тут речь идёт, во-первых, только о выражениях с внутренними задержками, при которых выполнение откладывается, во-вторых, если и только если задержка #0, выполнение откладывается в Inactive регион. Т.к. ровно так, как я и написал выше - Inactive регион используется только при задержках #0. Которых у нас нет. И которые использовать с современными симуляторами не рекомендуются.

Речь здесь идет об обоих случаях. Просто внимательно читайте и не додумывайте. Вот эти вот слова:

Quote

If the delay is 0, the process is scheduled as an Inactive event for the current time.

...  When the process is returned (or if it returns immediately if no delay is specified), the process performs the
assignment to the left-hand side and enables any events based upon the update of the left-hand side. The
values at the time the process resumes are used to determine the target(s). Execution may then continue with
the next sequential statement or with other Active or Reactive events

- с чего вы взяли, что они относятся к частному случаю #0? Они относятся к любому случаю, когда планирование ведется на ТОТ же слот времени - с задержкой 0. Именно потому, что в данном контексте противопоставляются future event (for intra-assignment delay) и delay 0, т.е., current time slot event (а это и #0, и просто отсутствие спецификации задержки). А если посмотреть по остальному тексту, то там совершенно ясным образом различаются конкретно 2 вещи: планирование на текущий временной слот, и планирование на будущий момент. И это логично, понятно и хорошо укладывается в представление о событийном моделировании/симуляции.

Про #0 есть отдельная конкретика -

4.4.2.3 Inactive events region
The Inactive region holds the events to be evaluated after all the Active events are processed.
If events are being executed in the active region set, an explicit #0 delay control requires the process to be
suspended and an event to be scheduled into the Inactive region of the current time slot so that the process
can be resumed in the next Inactive to Active iteration.


Она говорит, что выполнение оператора (с которым связано понятие process для драйвера данной переменной, выполнение которого на время suspended - приостанавливается) СРАЗУ откладывается в Inactive, без evaluation его в регионе Active на ПЕРВОЙ итерации. В отличие от оператора с отсутствием #, который будет отработан в Active, и результаты которого также пойдут в Inactive. Там, в Inactive, накапливаются все результаты всей первой итерации Active.

Кстати, тут рядом еще про неопределенность порядка прямым текстом:

4.4.2.2 Active events region
The Active region holds the current active region set events being evaluated and can be processed in any
order.
Quote

В этом-то и проблема - так просто это не воспроизводится. Например, когда у меня проект заloopился (иначе и не скажешь), я что только не делал, чтобы понять и пофиксить проблему, в т.ч. написал отдельный проектик, который повторяет зацикленный код - там три процесса по кругу ходили, один из них FSM. Так вот несмотря на всю почти одинаковость кода, этот тестовый проект мне загнать в цикл не удалось. В обоих проектах ходил по блокам в симе по шагам, отслеживал, куда он переходит. Внешне все одинаково за исключением того, что в одном случае (тестовом) он после одного (или двух) пустых заходов прекращает ходить по кругу, а в другом (рабочем) продолжает. Общий контекст у рабочего проекта, конечно, гораздо сложнее. Вот отсюда делаю вывод, что события-то от локального изменения генерируются всегда, но есть механизмы анализа и подавления зацикливания от этого. Только иногда сим не справляется.

В том-то и дело, что без воспроизведения мало о чем можно говорить с определенностью. Вплоть до того, что это bug/feature конкретной версии вашего симулятора (NCSim, кажется), да еще проявляющаяся только с определенным набором опций, да еще на очень специфическом RTL. Который мы так и не поисследовали. :-(

 

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

 

В любом случае - как говорится: баг в студию! Тогда и препарируем.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Приветствую!

2 hours ago, Raven said:

Мне на VCS такое поведение не попадалось.

Вы можете привести точные образцы кода (и опций симулятора, если нужно), необходимые для воспроизведения этого эффекта?

Modelsim Intel start edition 2020.1.  Вот пример (ниже) который я приводил. В котором непонятно почему петля возникает только при использовании функций форматирования вывода uvm_info.  Расковыряв цепочку вызовов в uvm_info и сделав выжимку  определил что петля возникает если в тексте присутствует имя функции loop_summary,  а в самой функции расскоментирован блок 1 или блок 3. Странно что наличие блока 2 не создает петли.  Причем  функция loop_summary  реально в коде не вызывается!!! так как вызов print_aa и print_bb идут  с нулевым аргументом. 

Но ясности это не добавило - скорее наоборот. :scratch_one-s_head: 

Удачи! Rob.

Spoiler

module test_loop;

typedef enum {A,B,C} e_SEVERITY_t;

bit  trig, a,a_q,  b,b_q;
int  aa,bb;

int msg_id_count   [string];
int severity_count [e_SEVERITY_t];

//-----------------------------------------------------------------------------
function automatic string loop_summary();
  string str, fmt;
  int max_len;

  // blok 1
  // foreach(msg_id_count[msg_id]) begin
  //   if (msg_id.len()>max_len) begin
  //     max_len = msg_id.len();
  //   end
  // end

  str = "--- Count by message ID ---\n";
  fmt = $sformatf("[%%-%1ds]: %%6d\n", max_len);

  // blok 2
  // foreach(msg_id_count[msg_id]) begin
  //   str = {str, $sformatf(fmt, msg_id, msg_id_count[msg_id])};
  // end

  str = {str, "--- Count by severity ---\n"};

  // blok 3
  // foreach(severity_count[severity]) begin
  //   str = {str, $sformatf(fmt, severity.name(), severity_count[severity])};
  // end
  return str;
endfunction : loop_summary


function automatic void print_summary(input string name);
  int fou;

  // fou = $fopen(name, "w"); ...
  $display(loop_summary());

endfunction


function automatic void print_aa (input bit trig_summary);
  $display($sformatf("[%t] : aa: %4d", $time(), aa++));

  if (trig_summary) begin
    print_summary("summary aa"); // if comment this line - no loop
  end
endfunction


function automatic void print_bb (input bit trig_summary);
  $display($sformatf("[%t] : bb: %4d", $time(), bb++));

  if (trig_summary) begin
    print_summary("summary bb"); // if comment this line - no loop
  end
endfunction


always_comb begin
  a = 0;

  if (trig)
    a = 1;

  // $display($sformatf("[%t] : aa: %4d", $time(), aa++));
  // `uvm_info("AA", $sformatf(">>aa: %4d", aa), UVM_HIGH)
  print_aa(0);

  if (b)
    b_q = b;
end

always_comb begin
  b = ~a;

  // $display($sformatf("[%t] : bb: %4d", $time(), bb++));
  // `uvm_info("BB", $sformatf(">>bb: %4d", bb), UVM_HIGH)
  print_bb(0);

  b = a;
end


initial begin
  #1;
  trig = 1;
end

endmodule : test_loop

 

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не хочу спорить, ибо неконструктивно. Вы считаете, что выражения без intra-assignment delay эквивалентны выражениям с intra-assignment delay #0, а это не так. Остальные ошибочные выводы следуют из этого заблуждения. 

 

Вот некоторые подробности по теме. Надеюсь, авторитет автора не под сомнением.

 

Обратите на п.2.2.

"Regions that are designed to implement correct RTL functionality: • Active regions (Active, Inactive and NBA regions - but avoid Inactive region events)."

 

"Region that should be avoided: • Inactive region."

 

И особенно:

 

"2.2.4 Inactive Events Region

 

The Inactive Events Region, also commonly called the Inactive region, is part of the Active Region Set. This region is where #0 blocking assignments are scheduled and per Sunburst Design Race Avoidance Guideline #8, engineers should not make #0 RTL procedural assignments3 . Most engineers that continue to use #0 assignments are trying to defeat a race condition that might exist in their code due to assignments made to the same variable from more than one always block, which is a violation of Sunburst Design Race Avoidance Guideline #6.

 

Engineers that follow good coding practices will have no need for #0 RTL assignments and hence, the Inactive region is unused in the rest of the event scheduling examples in this paper."

 

Ну, и картинка:

0Ok9yu2.png

 

32 минуты назад, Raven сказал:

Как говорится: баг в студию! Тогда и препарируем.

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

24 minutes ago, dxp said:

Не хочу спорить, ибо неконструктивно. Вы считаете, что выражения без intra-assignment delay эквивалентны выражениям с intra-assignment delay #0, а это не так. Остальные ошибочные выводы следуют из этого заблуждения. 

Вот некоторые подробности по теме. Надеюсь, авторитет автора не под сомнением.

Нет, авторитет никак не под сомнением. Пойду раскурю статью как следует. Пока скажу только, что отмеченные вами места к делу не относятся. Или не исключают пока и приведенную трактовку.

Quote

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

Это-то понятно. Значит, вычленение будет вашим домашним заданием.

35 minutes ago, RobFPGA said:

Modelsim Intel start edition 2020.1.  Вот пример (ниже) который я приводил. В котором непонятно почему петля возникает только при использовании функций форматирования вывода uvm_info.  Расковыряв цепочку вызовов в uvm_info и сделав выжимку  определил что петля возникает если в тексте присутствует имя функции loop_summary,  а в самой функции расскоментирован блок 1 или блок 3. Странно что наличие блока 2 не создает петли.  Причем  функция loop_summary  реально в коде не вызывается!!! так как вызов print_aa и print_bb идут  с нулевым аргументом.

Тут все же ситуация здорово отличается. Хотя бы уже тем, что looping явно происходит через вовлечение других регионов time slot'а, ответственных за тест-бенч и/или PLI (не настолько знаю эти глубины, чтобы сказать точнее). Но она воспроизводится (сам пока не проверял), и это уже интереснее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

20 минут назад, Raven сказал:

Пока скажу только, что отмеченные вами места к делу не относятся.

Это всё про то, что Inactive регион вообще мимо данной темы.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...