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

Jozef

На чем писать  

595 проголосовавших

  1. 1. Что чаще используете в разработках?

    • Assembler
      165
    • C
      303
    • Что-то еще
      66


Рекомендуемые сообщения

Асм - по сути, машинный язык, записанный английскими буквами. Одна команда ассемблера соответствует одной команде контроллера (не беря в расчет макросы и тому подобное). Именно в этом его особенность. И именно поэтому начинать обучение лучше с ассемблера, сразу понятно, почему контроллер поступает так а не иначе. Ну и некоторые ограничения камня так видны лучше. Попробовав реализовать на асме деление или операции с дробными числами, уже задумаешься, а так ли они нужны.

И могу еще раз подчеркнуть, что на практике область применения ассемблера не так уж велика. Это обучение, отладка и код, критичный к размеру и скорости работы. Отдельно стоит всякая мелочь типа ATtiny10, для которой практически невозможно использовать Си. Не буду говорить, что это принципиально невозможно, но обычный avr-gcc их не берет.

А вот для рядовых задач автоматизации ЯВУ предпочтительнее. Обычно ресурсов камня хватает с запасом, да и, если что, можно взять камень побольше. Зато больше готовых библиотек и меньше возни на низком уровне.

Знать надо оба языка, ассемблер и какой-нибудь ЯВУ. Лучше Си, но не обязательно.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

хм... выходит спорили то об одном и том же

:friends:

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

не каждый новичок к примеру поймет почему это выполнится не так как задумано

uint8_t x=0;

бла бла

if(x-1<0) x=0;

примитивно, но встречается часто

Изменено пользователем mail_robot

Нужно делать то, что нужно. А то, что не нужно, делать не нужно. (С) Винни Пух

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

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Есть примеры и менее очевидные.

Особенности использования переменных в прерывании

int x=0;
ISR(){x++}
int func(){
if(x){...} //"почему-то" не изменяется
}

volatile int y=0;
ISR(...){y++;}
int func(){
if(y==0x0202)y=0; //"почему-то" y может оказаться 0x0003, 0x0200 или сравнение может не сработать вовсе (в зависимости от компилятора с фазы Луны)
}

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

Выбираем схему BMS для заряда литий-железофосфатных (LiFePO4) аккумуляторов

Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ очень важен контроль процесса заряда и разряда для избегания воздействия внешнего зарядного напряжения после достижения 100% заряда. Инженеры КОМПЭЛ подготовили список таких решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

...
if(y==0x0202)y=0; //"почему-то" y может оказаться 0x0003, 0x0200 или сравнение может не сработать вовсе (в зависимости от компилятора с фазы Луны)
}

В принципе ничего удивительного нет, ибо undefined behaviour ...

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

Если прерывания запрещены, все должно работать нормально. Что тут неопределенного?

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

При чем тут запрещены? В вашем примере как раз упор на инкремент в прерывании. Непосредственно к прерываниям относится использование квалификатора volatile. Во втором случае прерывания не при чем - неопределенность в переполнении знакового числа.

Изменено пользователем Goodefine

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

Какое еще переполнение? signed int вмещает аж до 0x7FFF, а сравнение всего на 0x2020 (32767 против 8224). Если прерывание возникает достаточно редко по сравнению с if'ом (счет секунд, например), никакого переполнения не будет. Нет, речь шла всего лишь о возникновении прерывания между обработками младшего и старшего байтов числа и необходимости организации атомарного доступа к нему.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

Атомарность доступа это совершенно другая другая сторона медали, безусловно, о ней нужно помнить. А насчет signed x ... x++; - это и есть неопределенность, с возможными необъяснимыми глюками, например

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

Да нет тут неопределенности! То, что при переполнениии знаковое целое может стать -32768, это нормальное поведение, но к данному случаю это не имеет отношения. А "неопределенность" - зависимость результата от конкретной реализации компилятора. Знаменитое ++i+++i к примеру. В моем примере "неопределенность" может возникато только при неатомарном доступе и изменении переменной в прерывании, о котором я писал.

Нет, можно было, конечно, в обработчике прерывания написать if(x<32767)x++; но в данном случае на работу программы это не влияет, особенно если прерывание возникает намного реже, чем if(x==0x0202).

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

Да нет тут неопределенности! То, что при переполнениии знаковое целое может стать -32768, это нормальное поведение,

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

Изменено пользователем Goodefine

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

Оно не может стать чем угодно. Вы так говорите, как будто любое использование знаковых переменных приводит к "неопределенному поведению". В примере по ссылке, вероятно, компилятор, забывает о возможности переполнения (и, в то же время, помнит, что int8_t не може тбыть больше 0x7F), вот и оптимизирует. Без оптимизации сравнение идет честно. Но в моем примере переполнение не возникает и даже близко к нему не подходит.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

Но в моем примере переполнение не возникает и даже близко к нему не подходит.

Но компилятор не знает что оно не происходит. Квалификатор volatile ему говорит, что переменная может изменится в любой момент без его ведома, т.е. условие на проверку и обнуление ничего не дает, с точки зрения видения компилятором переполнения знаковой переменной. А как вы видели из примера выше, важно не то, что переполнение наступает, а то что об этом думает компилятор.

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

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

Даже человек в состоянии проанализировать итог подобного переполнения. Переполнение знаковой переменной - переменная становится минимально отрицательного значения. Где тут неопределённости ?

Не вижу никакой логики правильной работы оптимизатора. Только пакости...

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

По стандарту это неопределенность, и как видно из примера, не только по нему но и в реальной ситуации.

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

Квалификатор volatile ему говорит, что переменная может изменится в любой момент без его ведома, т.е. условие на проверку и обнуление ничего не дает
Что это за бред? Volatile говорит, что переменная хранится в ОЗУ и может измениться в любой момент. Поэтому компилятор проводит честное сравнение и не оптимизирует попусту. Ведь оптимизатор не может знать, не занулит ли какое-нибудь прерывание переменную явным образом. Могу повторить свой вопрос: если вы считаете, что любое сравнение знаковых переменных является "неопределенным действием", зачем они введены в языке?

Между прочим, проверил дизассемблерный код обоих вариантов

int x;
for(x=1;x;x++)PORTB=x;
 3a:    88 bb	       out    0x18, r24    ; 24
 3c:    8f 5f	       subi    r24, 0xFF    ; 255
 3e:    fd cf	       rjmp    .-6	      ; 0x3a <main+0x2>

Но

volatile int x;
for(x=1;x;x++)PORTB=x;
 42:    81 e0	       ldi    r24, 0x01    ; 1
 44:    90 e0	       ldi    r25, 0x00    ; 0
 46:    06 c0	       rjmp    .+12         ; 0x54 <__SREG__+0x15>
 48:    89 81	       ldd    r24, Y+1    ; 0x01
 4a:    9a 81	       ldd    r25, Y+2    ; 0x02
 4c:    88 bb	       out    0x18, r24    ; 24
 4e:    89 81	       ldd    r24, Y+1    ; 0x01
 50:    9a 81	       ldd    r25, Y+2    ; 0x02
 52:    01 96	       adiw    r24, 0x01    ; 1
 54:    9a 83	       std    Y+2, r25    ; 0x02
 56:    89 83	       std    Y+1, r24    ; 0x01
 58:    89 81	       ldd    r24, Y+1    ; 0x01
 5a:    9a 81	       ldd    r25, Y+2    ; 0x02
 5c:    89 2b	       or    r24, r25
 5e:    a1 f7	       brne    .-24         ; 0x48 <__SREG__+0x9>

То есть во втором случае (volatile int x) мало того, что переменная проверяется, так перед проверкой явным образом загружается из ОЗУ.

с какой стати компилятору считать переполнение переменной - неопределённым состоянием ?

Даже человек в состоянии проанализировать итог подобного переполнения. Переполнение знаковой переменной - переменная становится минимально отрицательного значения. Где тут неопределённости ?

В коде for(int x=1;x!=0;x++) оптимизатор знает, что начальное значение х равно 1 и в цикле оно только растет, значит сравнение с нулем не имеет смысла. А может быть, принцип "максимизации ошибки": размер типа int не определен компилятором, значит количество итераций до переполнения зависит от компилятора. Чтобы обратить на это внимание программиста, компилятор вырезает сравнение. На мой взгляд первый вариант вероятнее.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

В коде for(int x=1;x!=0;x++) оптимизатор знает, что начальное значение х равно 1 и в цикле оно только растет, значит сравнение с нулем не имеет смысла.
C этим то всё понятно. Но этот код никак не относится к "неопределённому состянию из-за переполнения", что и в выше приведённых примерах.
По стандарту это неопределенность
Я это понимаю. Я не понимаю почему ? Какая же это неопределённость, если итог известен и его вариант единственный ?

Или есть и другие варианты, которых я не вижу ?

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

Что это за бред? Volatile говорит, что переменная хранится в ОЗУ и может измениться в любой момент.

А это не одно и то же?

Между прочим, проверил дизассемблерный код обоих вариантов

Конкретный код, конкретного компилятора.... Я вам указал потенциальный баг, дальше как хотите. На светофоре тоже на красный иногда получается проскочить

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

Или есть и другие варианты, которых я не вижу ?

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

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

А это не одно и то же?

"Бред" было про сделанные вами выводы. Что компилятор может опустить проверку. На самом деле, именно потому что переменная в любой момент может принять любое значение, пропускать проверки он не имеет права.

Конкретный код, конкретного компилятора.... Я вам указал потенциальный баг, дальше как хотите. На светофоре тоже на красный иногда получается проскочить

Конкретный код, конечно, этого не доказывает. Но логику работы volatile и оптимизатора продемонстрировать может. Так что именно в этом месте бага нет. Так что можете натыкать светофоров посреди густого леса и старательно ждать зеленого сигнала.

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

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

Проверку на что? На if? Так пусть проверяет. Я говорил о том, что с точки зрения компилятора переполнение возможно, а как он в этом случае себя поведет - стандарт не оговаривает, вернее оговаривает - неизвестно.

Но логику работы volatile и оптимизатора продемонстрировать может. Так что именно в этом месте бага нет.

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

Любой, заслуживающий внимания, опыт приобретается себе в убыток...

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

Это вопрос к ним
Понятно что не к Вам.

Но подобные "оптимизации" скорее вызовут недовольство, чем удивление его "ума". Медвежья услуга, одним словом. Вмешался, натворил дел и промолчал. За такие дела, у людей, в морду бьют...

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

О переполнении можно было бы говорить, если бы оно возникало, а в моем примере этого нет, так что вообще непонятно, что именно вы опровергаете.

Даже в примере с for(int i=1;i;i++) объявление i как volatile обязывает проводить все описанные операции с переменной, кроме, возможно, бесполезных вроде i*=1.

Еще один вариант, откуда возникает неопределенность - различие аппаратной реализации знаковых чисел. Например, на некоторых архитектурах переполнение просто отсутствует, или реализуется неоправданно сложно. А может, for не различает типы данных, а для float такая оптимизация вполне логична, потому что досчитает только до 8388607, а дальше увеличиваться не будет. Тут уже и правда зависит от конкретной реализации цикла и оптимизации.

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

Ругался на отсутствие форматирования исходного кода (включая отсутствие осмысленных комментариев и наличие неубранного после конфигуратора мусора) не менее 15 раз.

Часть моих наработок.

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

Уважаемые знатоки, не подскажете ли, каков должен быть формат inc-файла для avr-as в Linux?

Я обнаружил, что не получается так, как у людей, например, как здесь:

https://zhevak.wordp...-gnu-assembler/

У меня ATmega1284P. Например, оказалось, что вместо знаков равенства должна быть запятая.

В то же время объявление регистров должно быть таким:

.def XH = r27

а не как в примере по ссылке.

Не воспринимается директива

.device ATmega1284P

М.б., она и не нужна?

В программе не воспринимается директива

.cseg

должно быть либо, как в примере,

.section .text

либо

.section .code

а как правильно?

Ещё почему-то считаются неизвестными low и high в операторах вида

ldi r16,low(RAMEND)

а почему?

Пётр.

Виноват, ошибся,

.def XH = r27

не воспринимается, .def - unknown pseudo-op.

Ещё одно дополнение:

по-видимому, этот avr-as не имеет встроенных функций low() и high(), возможно, и других.

Так что это надо реализовывать командами, так компилируется, но я ещё не проверял,

правильно ли это работает.

Ещё одно допонение:

Если в inc-файле написать

.equ XH , 0x1B

или

.set XH , 0x1B

где 0x1B - адрес r27, а в программу вставить оператор

ldi XH,0x11

то это комлилируется, как если бы было написано

ldi r27,0x11

т.е. код операции в листинге во всех трёх вариантах одинаковый - B1E1.

Но я не знаю, для чего предназначена операция .set

Пётр.

Изменено пользователем Peter_I
Ссылка на комментарий
Поделиться на другие сайты

Оказалось, что можно компилировать ассемблерную ппрограмму через вызов avr-gcc,

если в её начало помесить строки

#define __SFR_OFFSET 0
.nolist
#include <avr/io.h>
.list

Не знаю, обязательна ли 1-я.

Если файл с программой называется light.S, то компилировать можно командой

avr-gcc -c -Wall -Xassembler -als=light.lst -mmcu=atmega1284p -o light.o lightS

Единственное преимущество перед прямым вызовом avr-as - что не нужен inc-файл.

avr-as не принимает также директиву .db, надо использовать .byte.

Как инициализировать многобайтовые переменные и возможно ли это, пока не понял.

Чтобы отвести под переменную столько места, сколько надо, после неё надо

использовать директиву .org, а сами переменные, конечно, должны быть в .section .data.

Пётр.

Дополнение:

Оказалось, что вместо low() и high() есть lo8() и hi8().

Изменено пользователем Peter_I
Ссылка на комментарий
Поделиться на другие сайты

Чтобы инициализировать многобайтовые переменные, надо перечислить значения байтов через запятую,

аналогично для .word, но сейчас вопрос в другом.

Я начал делать программу для ATmega1284P и вот сейчас обнаружил, что получается громадный hex и он даже

больше elf, почти втрое. elf - 66545, hex - 174659. Опция "-S" в вызове avr-objcopy на размер не влияет.

Что я делаю не так или чего не хватает?

Ниже скрипт, у меня shell - tcsh.

#

rm -f lighting_c.o lighting_c.lst lighting_c.hex lighting_c.elf
avr-gcc -Wall -mmcu=atmega1284p -Xassembler -als=lighting_c.lst -Xassembler -warn -o lighting_c.elf lighting_c.S
set stts = $?
/bin/echo "status="$stts
if ( $stts == 0 ) then
#avr-objcopy -j .text -j .data -O ihex lighting_c.elf lighting_c.hex
avr-objcopy -S -O ihex lighting_c.elf lighting_c.hex
set stts = $?
/bin/echo "status="$stts
endif

Сама программа вот:

#define __SFR_OFFSET 0
.nolist
#include <avr/io.h>
.list
;#define c1 0x11
; Test program for ATmega8.
BODLEVEL1 = 0
BODLEVEL0 = 0
BOOTRST = 0
CKSEL3 = 0
CKSEL2 = 0
CKSEL2 = 0
CKSEL1 = 0
CKDIV8 = 1

.section .data
.org 0x100
bufrx: .byte 0,0,0,0,0,0,0,0 ;RX buffer
cntrx: .byte 0,0 ;RX counter
buftx: .byte 0,0,0,0,0,0,0,0 ;TX buffer
cnttx: .byte 0,0 ;TX counter

.section .text
.org 0
.global main
jmp btldr ;to bootloader
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
jmp u0rx
jmp u0udre
jmp u0tx
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti


;.org 0x46
main:
ldi r16,SE ;enable sleep mode
out SMCR,r16
sei
sleep
jmp main

u0rx:
cli
push r16
push r17
clr r16 ;disable sleep mode
out SMCR,r16
lds r16,UDR0 ;received byte
push r16
ldi XH,hi8(bufrx)
ldi r16,lo8(bufrx)
lds r17,cntrx
add r16,r17
mov XL,r16 ;next byte's address in X
pop r16
st X,r16 ;next byte to (bufrx+cntrx)
inc r17 ;increasing counter

sts cntrx,r17


sei
pop r17
pop r16
reti

u0udre:
cli
push r16
clr r16 ;disable sleep mode
out SMCR,r16

sei
pop r16
reti

u0tx:
cli
push r16
clr r16 ;disable sleep mode
out SMCR,r16

sei
pop r16
reti

.org 0xF000
reset:
jmp btldr
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
jmp u0rxb
jmp u0udreb
jmp u0txb
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti
reti

btldr:
cli
in r16,MCUCR ;IV -> bootloader
mov r17,r16
ori r16,(1<<IVCE)
out MCUCR,r16
ori r17,(1<<IVSEL)
out MCUCR,r17

ldi r16,lo8(RAMEND)
out SPL,r16
ldi r16,hi8(RAMEND)
out SPH,r16

ldi r16,0x80 ;turn of comparator
out ACSR,r16

clr r16 ;11059200, 57600, 8,N,1
sts UBRR0H,r16
ldi r16,11
sts UBRR0L,r16
clr r16
sbr r16,TXC0 ;resetting
sts UCSR0A,r16
clr r16 ;enable all interupts
ori r16,(1<<RXCIE0)|(1<<TXCIE0)|(1<<UDRIE0)|(1<<RXEN0)|(1<<TXEN0)
sts UCSR0B,r16
clr r16
ori r16,(1<<UCSZ01)|(1<<UCSZ00) ;default
sts UCSR0C,r16
sei
clr r16
sts cntrx,r16


in r16,MCUCR ;IV -> program
mov r17,r16
ori r16,(1<<IVCE)
out MCUCR,r16
cbr r17,IVSEL
out MCUCR,r17
jmp main


u0rxb:
cli
push r16
clr r16 ;disable sleep mode
out SMCR,r16


sei
pop r16
reti

u0udreb:
cli
push r16
clr r16 ;disable sleep mode
out SMCR,r16

sei
pop r16
reti

u0txb:
cli
push r16
clr r16 ;disable sleep mode
out SMCR,r16

sei
pop r16
reti


.end

Пётр.

Изменено пользователем Peter_I
Ссылка на комментарий
Поделиться на другие сайты

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

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

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

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

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

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

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

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу

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