=GM= 0 24 августа, 2007 Опубликовано 24 августа, 2007 · Жалоба Тема открыта по горячим следам недавней острой дискуссии. В ней одним из участников (defunct) была приведена программа, в которой использовался циклический буфер для работы с последовательным портом МК AT90S2313. На взгляд автора программа написана достаточно грамотно, но как-то слишком размашисто, без учёта мизерности ресурсов данного МК. Предлагаю участникам поделиться примерами и приёмами использования циклического буфера в программных разработках. Для затравки предлагаю следующие фрагменты. А. Запись байта из регистра AL в циклический буфер mov xl,qhead ;указатель на запись st x+,al ;запишем байт cp xl,qend ;конец буфера? brne .+2 ;нет, обходим ldi xl,buffer ;да, установим начало Б. Чтение байта из циклического буфера в регистр AL mov xl,qtail ;указатель на чтение ld al,x+ ;прочитаем байт cp xl,qend ;конец буфера? brne .+2 ;нет, обходим ldi xl,buffer ;да, установим начало Если использовать буфер не произвольной длины, а кратный степени 2, и размещать его в памяти не произвольно, а начиная с адресов, кратных длине буфера, то размер кода можно немного сократить. Например. В. Запись байта из регистра AL в циклический буфер длиной 32 mov xl,qhead ;указатель на запись st x+,al ;запишем байт cbr xl,0xE0 ;держим указатель в предписанных рамках Г. Чтение байта из циклического буфера длиной 32 в регистр AL mov xl,qtail ;указатель на чтение ld al,x+ ;прочитаем байт cbr xl,0xE0 ;держим указатель в предписанных рамках Здесь qhead, qtail, qend – регистровые переменные, содержащие адреса-указатели ячеек в озу для записи, чтения и конца буфера соответственно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
defunct 0 24 августа, 2007 Опубликовано 24 августа, 2007 · Жалоба Если использовать буфер не произвольной длины, а кратный степени 2, и размещать его в памяти не произвольно, а начиная с адресов, кратных длине буфера, то размер кода можно немного сократить. Если вы хотели услышать отзыв о вашем способе, то вот он: Хороший способ. Особо хорошо подходит для задач где требуется выделить некий "под-поток" внутри потока. Другими словами для организации "probation" периода. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Гость =AVR= 25 августа, 2007 Опубликовано 25 августа, 2007 (изменено) · Жалоба Такой метод (посредством урезания операцией "AND") организации кольцевых буферов с длиной и начальным адресом, кратными 2^N, весьма удобен и эффективен - недаром он широко применяется аж с 80-х годов. Эффективнее него - только аппаратные кольцевые буфера, реализованные в некоторых DSP, а также в dsPIC. =GM= молодец - очень полезно время от времени напоминать широким массам о том, что Волга впадает именно в Каспийское море, а не в Северное :) Изменено 25 августа, 2007 пользователем =AVR= Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sensor_ua 0 25 августа, 2007 Опубликовано 25 августа, 2007 · Жалоба IMHO, обсуждение циклических буферов в привязке к архитектуре имеет смысл только при использовании ассемблера и всвязи с нюансами соблюдения атомарности операций. Ну и, как заметил =AVR=, при наличии аппаратной реализации в соответствующих камнях. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
mse 0 25 августа, 2007 Опубликовано 25 августа, 2007 · Жалоба mov xl,qhead;указатель на запись st x+,al;запишем байт cp xl,qend;конец буфера? brne .+2;нет, обходим ldi xl,buffer;да, установим начало ... ИМХО, выделять регистровые переменные под хранение начала-конца для тонких АВР весьма тоскливо. Если прально понял, то всё это богацтво хранится вечно, бо чтение ЦБ осусчествляется в одном месте, запись - в другом... Регистр, опять-же, ИМХО, гораздо дороже ячейки в ОЗУ...Хотя... .dseg qhead: .byte 1 buffer: .byte N qend: other_data: ... lds xl,qhead;указатель на запись st x+,al;запишем байт cpi xl,qend;конец буфера? brne no_cycled;нет, обходим ldi xl,buffer;да, установим начало no_cycled: sts qhead,xl в пассиве три такта, два слова и лишний указатель в ОЗУ. Но зато есть лишний регистер и ничего не остаётся в регистрах надолго. Но, как правило, в ЦБ кто-то пишет/читает постепенно и одновремено. Могут столкнуться и перетолкнуться, значит надо есчо и указатели контролировать. .dseg qread: .byte 1 qwrite: .byte 1 buffer: .byte N qend: other_data: ... lds xl,qwrite;указатель на запис lds r0,qread;на чьтение cp xl,r0 brne pointers_ok ; ;ой, мля, чё делать-то?!! ; pointers_ok: st x+,al;запишем байт cpi xl,low(qend);конец буфера? brne no_cycled;нет, обходим ldi xl,low(buffer);да, установим начало no_cycled: sts qwrite,xl ... Вроде нигде не накосячил...А? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 26 августа, 2007 Опубликовано 26 августа, 2007 · Жалоба Такой метод (посредством урезания операцией "AND") организации кольцевых буферов с длиной и начальным адресом, кратными 2^N, весьма удобен и эффективен - недаром он широко применяется аж с 80-х годов. Эффективнее него - только аппаратные кольцевые буфера, реализованные в некоторых DSP, а также в dsPIC. =GM= молодец - очень полезно время от времени напоминать широким массам о том, что Волга впадает именно в Каспийское море, а не в Северное :) 1) К сожалению не всегда применимо. 2) При написании программы - реализация кольцевого буфера - единицы %. Поэтому я за написание данного участка "размашисто". Зато нет необходимости лично контролировать размещение самого буфера. Я тоже применял сначала такой метод. Кстати возможно автоматическое размещение буфера на границу по типу применяемой мной привязки таблицы данных .cseg .org (pc & $ff80)+$80 Приведу пример буфера несколько сложнее организованного ;**************************************************************** ;* Вывод символа (wl) в буфер вывода. При выводе контроли- * ;* руется заполнение буфера. При переполнении буфера вывод тор- * ;* мозится, и подпрограмма не завершится, пока он не закончится.* ;* Две точки входа: outwl и outwlsZ; * ;* Портятся tmph, Z. (для outwl) * ;* Портятся tmph. (для outwlsZ) * ;**************************************************************** outwl: mov tmph, TBH sub tmph, TBE brcc outw1 subi tmph, -lBuf outw1: cpi tmph, 2 breq outwl mov Zl, TBE ldi ZH, high(TxBuf) st Z+, wl cpi Zl, lBuf brne outw2 clr Zl outw2: mov TBE, Zl ret Приём ;**************************************************************** ;* Прерывание на приём данных. * ;* * ;* Принятый байт размещается в кольцевом буфере RxBuf. Размер * ;* кольцевого буфера lBuf байт. В случае когда до заполнения * ;* буфера осталось 16 байт снимается готовность модема. (Аппа- * ;* ратным или програмным способом. При освобождении буфера на * ;* половину готовность опять включается в голове. * ;* Используются регистры RBH и RBE как мл. байт адреса указа- * ;* телей на голову и хвост буфера соответственно. Портятся ре- * ;* гистр wp и регистровая пара X. * ;* Максимальное время выполнения: 31 такт. * ;**************************************************************** RxUART: in tmpsreg, sreg mov Xl, RBE; Поместить его в регистровую пару X clr Xh in wp, udr; Прочитать принятый байт и st X+, wp; поместить его в буфер cpi Xl, RxBuf+lBuf; Конец буфера? brne RxU1 ; если нет, то дальше ldi Xl, RxBuf; а иначе в начало буфера RxU1: mov RBE, Xl; и сохранить mov Xl, RBH; Определить объём свободного места sub Xl, RBE; в буфере brcc RxU2 subi Xl, -lBuf; Откорректировать при перехлёсте RxU2: cpi Xl, 16; Осталось меньше 16 байт? brsh RxUE ; если нет, то выйти sbi portd, CTS; Сбросить готовность модема RxUE: lds Xl, s2 cp wp, Xl brne plclr tst nplusC brne plinc tst ms20 breq plinc plclr: clr nplusC rjmp plset plinc: inc nplusC plset: lds ms20, s12; сбросить задержку out sreg, tmpsreg reti Это реализация старая 2003 года последние изменения. Сейчас вообще буфер большой. В байт не влазит. На мелочи не обращать внимание просто по живому вырезалось. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
adnega 11 27 августа, 2007 Опубликовано 27 августа, 2007 · Жалоба Доброго дня! Мне вот очень интересно применение кольцевых буферов для реализации консоли. Со временем "написались" некоторые участки кода, которые позволяют в общем виде сделать реакцию на команды. Юзаю повсеместно. Хотелось бы услышать отзывы и предложения по данной проблеме. :-) command.rar Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 28 августа, 2007 Опубликовано 28 августа, 2007 · Жалоба Привет всем! Отъезжал ненадолго, тут праздник местный был (summer bank holiday), теперь будем смотреть ответы и отвечать по мере сил-возможностей(:-) 1) To SasaVitebsk. Как всегда, приведен добротный код. Есть только мелкие вопросики. Фрагмент ниже непонятен, вроде бы надо буфер разместить в озу, а у вас стоит пзу. Кстати возможно автоматическое размещение буфера на границу по типу применяемой мной привязки таблицы данных .cseg .org (pc & $ff80)+$80 Трудно разобраться с передачей, метка outwl указана дважды, а метки outwlsZ нет вовсе. ;* Две точки входа: outwl и outwlsZ; * ;* Портятся tmph, Z. (для outwl) * ;* Портятся tmph. (для outwlsZ) * ;**************************************************************** outwl: mov tmph, TBH sub tmph, TBE brcc outw1 subi tmph, -lBuf outw1: cpi tmph, 2 breq outwl ret 2) Как обычно ничем не удивил и не порадовал широкоизвестный в узких кругах эникейщик =AVR=, вроде бы и похвалил, вроде бы и пожурил в одно и то же время, но что такое "аппаратные кольцевые буфера" и чем они отличаются от address mode осталось тайной(:-). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
WHILE 0 28 августа, 2007 Опубликовано 28 августа, 2007 · Жалоба Привет всем! Отъезжал ненадолго, тут праздник местный был (summer bank holiday), теперь будем смотреть ответы и отвечать по мере сил-возможностей(:-) 1) To SasaVitebsk. Как всегда, приведен добротный код. Есть только мелкие вопросики. Фрагмент ниже непонятен, вроде бы надо буфер разместить в озу, а у вас стоит пзу. Трудно разобраться с передачей, метка outwl указана дважды, а метки outwlsZ нет вовсе. 2) Как обычно ничем не удивил и не порадовал широкоизвестный в узких кругах эникейщик =AVR=, вроде бы и похвалил, вроде бы и пожурил в одно и то же время, но что такое "аппаратные кольцевые буфера" и чем они отличаются от address mode осталось тайной(:-). Господин учитель информатики раздает слонов за итоговую работу по теме "кольцевые буферы". Вы бородку клинышком и пенсне не носите случаем?Если нет-подумайте на эту тему,имхо вам должно пойти. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 28 августа, 2007 Опубликовано 28 августа, 2007 · Жалоба 1) To SasaVitebsk. Как всегда, приведен добротный код. Есть только мелкие вопросики. Фрагмент ниже непонятен, вроде бы надо буфер разместить в озу, а у вас стоит пзу. Да. Я так и написал. Просто вырвал кусочек использованный для объявления таблицы автоматически выровненной на границу. Что-нибудь подобное можно и для озу придумать. Чтобы вместо ORG. :) Трудно разобраться с передачей, метка outwl указана дважды, а метки outwlsZ нет вовсе. Метка outwl указана 1 раз и является вызываемой. Второй раз использована метка outw1. Просто на том шрифте этого не видно. Если текст перенесёте, то увидите. Написано это где-то в 1994-95 примерно. Я тогда так принял локальные метки изменять для себя 1,2,3... Короче что-то по типу символа "_" у defunct. Кстати применение символа "_" используется некоторыми компиляторами для организации локальных меток. Иногда при макросах также делается. Так что наезд на defunct некорректен. :) Считаю его подход правильным. Просто когда я писал ещё не сложилось ничего (у меня). Да и вообще человек постоянно меняется оставаясь самим собой. Наверное было бы любопытно поболтать с собой самим лет 20 тому назад. Ну, безусловно избегая фраз типа: "придурок правее бери". А что не хватает, - так ведь выхвачено было по живому. Оно же там всё повязано. :) Там нет ничего любопытного. ;**************************************************************** ;* Вспомогательная. Выводит в буфер вывода цифру согласно би- * ;* ту Т. Потом выводит "пробел". * ;* Портится tmph,wl и Z. * ;**************************************************************** outwlt: clr wl bld wl, 0 ;**************************************************************** ;* Вспомогательная. Выводит в буфер вывода цифру согласно ре- * ;* гистра wl. Потом выводит "пробел". * ;* Портится tmph,wl и Z. * ;**************************************************************** outwlr: andi wl, 3 ori wl, $30 rcall outwl ldi wl, $20 ;**************************************************************** ;* Вывод символа (wl) в буфер вывода. При выводе контроли- * ;* руется заполнение буфера. При переполнении буфера вывод тор- * ;* мозится, и подпрограмма не завершится, пока он не закончится.* ;* Две точки входа: outwl и outwlsZ; * ;* Портятся tmph, Z. (для outwl) * ;* Портятся tmph. (для outwlsZ) * ;**************************************************************** outwl: mov tmph, TBH sub tmph, TBE brcc outw1 subi tmph, -lBuf outw1: cpi tmph, 2 breq outwl mov Zl, TBE ldi ZH, high(TxBuf) st Z+, wl cpi Zl, lBuf brne outw2 clr Zl outw2: mov TBE, Zl ret outwlsZ: push Zl push Zh rcall outwl pop Zh pop Zl ret Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Гость =AVR= 28 августа, 2007 Опубликовано 28 августа, 2007 · Жалоба Аппаратные буфера отличаются от address mode тем же, чем summer bank holiday от аристократической и загадочной команды cbr xl,0xE0. То есть, простите, Sir, от плебейской и понятной команды andi xl,0x1F - ну, Вы, смею надеяться, поняли, а остальным не обязательно, а то опять засмеют Вас, как тогда с этим 24-канальным ШИМом - помните? Ну и славненько. И аппаратные кольцевые буфера, Sir, в DSP не делаются, а имеются - вернее, имеется их поддержка, которая активируется установкой битиков в соответствующих регистриках - размерчик там буферочка, направление заполнения, флажочки разные удобные - если маразм склероз замучил, то прочитайте DS на какой-нибудь DSP или даже, не побоюсь этого слова, dsPIC - там Вам постараются объяснить это два раза и медленно, тщательно проговаривая слова. Нам, эникейщикам, в наших узких кругах такое практически недоступно - все урывками да слухами, никакого, панимаишь, информационного бума - один свист. Кстати, не Вы ли свистели, эсквайр? Ай-я-яй, как некультурно! :) to SasaVitebsk: .org прекрасно и штатно работает и в ОЗУ, просто для этого нужно использовать его в секциях данных - dseg и/или eseg, Position Counter (PC) у каждой секции свой, и считает такой PC те единицы размещения, которые применяются в данной секции - слова для .code, байты для .dseg и .eseg. Выравнивание по кратной границе удобно делать при помощи (моего) макроса align (если директивы align нет в соответствующем ассемблере): ; For AVR Assembler 2 only .macro align .org @0+PC-PC%@0 .endm .dseg align (32+SRAM_START) ringb1: .byte 32; @ 0x0080 ringb2: .byte 32; @ 0x00A0 При размещении буферов в ОЗУ по нужным границам надо не забывать о том, что ОЗУ в разных АВР начинается с разных адресов - где 0x0060, а где и 0x0100. В примере выше адрес начала ОЗУ (SRAM_START, значение определено в .inc-файле) использовано как добавка к параметру align Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 28 августа, 2007 Опубликовано 28 августа, 2007 · Жалоба Господин учитель информатики раздает слонов за итоговую работу по теме "кольцевые буферы". Вы бородку клинышком и пенсне не носите случаем? Если нет-подумайте на эту тему, имхо вам должно пойти. Хорошо бы вам, уважаемый, не шипеть злобно из-за угла, а сказать что-нибудь ближе к теме ветки, не отклоняясь. Если, конечно, есть чем поделиться. На тему пресловутых циклических буферов, конечно, а не на тему пенсне. Аппаратные буфера отличаются от address mode тем же, чем summer bank holiday от аристократической и загадочной команды cbr xl,0xE0. То есть, простите, Sir, от плебейской и понятной команды andi xl,0x1F - ну, Вы, смею надеяться, поняли, а остальным не обязательно, а то опять засмеют Вас, как тогда с этим 24-канальным ШИМом - помните? Режим косвенной циклической адресации (indirect circular addressing mode) именно в дсп я знаю хорошо, поскольку каждый божий день применяю: и такой movl *ar6%++,acc и такой movl *+xar6[ar1%++] А вот аппаратного буфера не нахожу, да, склероз-не склероз, свисти-не свисти...нету такого! Эникейщики, они тем и отличаются от обычных кодеров, что неглубоко копают, помните? А ещё они любят навести тень на плетень, сравнить, например, summer bank holiday с командой cbr. Что касаемо 24-канального программного шима, не надо ля-ля, ваша программа проиграла моей программе по скорости более, чем в ТРИ раза. И никто не смеялся, один вы орали и брызгали слюной, всех задолбали, прямо скажем. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
zltigo 2 28 августа, 2007 Опубликовано 28 августа, 2007 · Жалоба Moderator: Так, оба двое и присоединившийся к ним совcем уж не по делу WHALE - снижаем накал страстей до уровня соответствующего технической теме а не банальной перепалке во freetalk. Если уже начали о софтовых кольцевых буферах отдельную тему, то следует как минимум раскрыть тему пошире: -получении информации о свободном месте в буфере; -различных стратегиях поведения при переполнении буфера; -организации небайтовых буферов; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 29 августа, 2007 Опубликовано 29 августа, 2007 · Жалоба Если уже начали о софтовых кольцевых буферах отдельную тему, то следует как минимум раскрыть тему пошире: -получении информации о свободном месте в буфере; -различных стратегиях поведения при переполнении буфера; -организации небайтовых буферов; Ищу решение, пока красивого нет. Нашёл вот только наиболее короткий способ чтения из буфера и записи в буфер практически ПРОИЗВОЛЬНОГО размера. Скажем для тайни – от 1 до 64 байт. Для старших моделей 1-256. По-моему, довольно симпатично(:-). Идея состоит в том, чтобы адрес конца буфера помещался непосредственно перед границей по модулю 2^N. В то же время длина буфера может быть произвольной в пределах этого модуля 2^N. Например, конец буфера для тайни нужно выбрать равным 0xBF. Тогда начало буфера можно выбирать любое в пределах 0x80-0xBE. Полные фрагменты кода на запись/чтение в/из циклического буфера приведены ниже. Фрагменты похожи на реализацию, показанную mse (см. пост #5), но короче на одно слово. А. Запись байта из регистра data в циклический буфер buffer bwrite: lds xl,head ;указатель clr xh ;на запись st x+,data ;запишем байт sbrc xl,6 ;конец буфера? ldi xl,low(buffer);да, установим начало sts head,xl ;новый указатель Б. Чтение байта из циклического буфера buffer в регистр data bread: lds xl,tail ;указатель clr xh ;на чтение ld data,x+ ;прочитаем байт sbrc xl,6 ;конец буфера? ldi xl,low(buffer);да, установим начало sts tail,xl ;новый указатель Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 29 августа, 2007 Опубликовано 29 августа, 2007 · Жалоба 2 AVR спасибо. До вашего варианта не додумался. Про DSEG, естественно, знаю. Последнее время пишу всё на Си. Думаю что ваш макрос будет полезен многим. Интересные находки всегда любопытны. Я вот всё больше и больше склоняюсь к мысли что необходимо унифицировать некоторые узлы и блоки, процедуры процессоронезависимые и даже переменные и структуры. Прошу прощения за отход от темы может кто посоветует хорошую книгу в данной области. То есть что-то по типу визуализации/структурирования. Даже не знаю как назвать эту область. Короче выработки единого подхода к написанию прог на Си. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться