Есть 16 разрядный процессор, который имеет 16-разрядный счетчик C, увеличивающийся на 1 каждый такт. Этот счетчик можно программно считать. Когда счётчик переполняется, возникает прерывание, обработчик которого увеличивает на единицу(не элементарная операция) 32-разрядное значение, занимающее ячейки A(старшая часть) и B(младшая часть). Кроме обработчика прерываний от таймера есть еще несколько источников прерываний. Пока обрабатывается одно прерывание, другие прерывания запрещены, пока не будет выполнена команда возврата, после чего если есть еще не обработанные прерывания, произойдёт вызов их обработчиков. Если основной программе необходимо прочитать 32 разряда AB(2 операции), она может просто запретить прерывания, чтобы обработчик не изменил эти ячейки между операциями чтения. Но если программе требуется получить все 48 разрядов, включая C(3 операции), сможет ли она это сделать не запрещая прерывания?
Крайне отстойное решение. Лучше читать ничего не запрещая и потом, если процесс прерван, скорректировать прочитанные данные (прибавить единицу, если было прерывание). О том, что прерывание было / будет можно косвенно узнать по значению С. Код должен быть безбранчевым, чтобы можно было точно посчитать сколько тактов уйдёт на весь этот процесс и потом прибавить это количество к С.
Quantum Можно считать что основные арифметические(включая adc и sbb) и логические операции у нас есть, и выполняются они за 1 такт(переходы тоже). Проблема здесь не в прибавлении 1, а в том, что например если A=1, а B=FFFFh, допустим мы сначала прочитали A=1, после чего возникло прерывание и обработчик увеличил AB, и мы читаем B=0, и думаем что таймер насчитал 10000h, а это очень далеко от истины. Здесь не обязательно выдать значение с точностью до такта, нужно сделать чтобы операция чтения была "атомарной", то есть чтобы программа не получала часть данных старыми(до обработки прерывания), а часть новыми(после обработки прерывания).
Есть 16 разрядный процессор, который имеет 16-разрядный счетчик C, увеличивающийся на 1 каждый такт. Если я верно понял, прерывание будет выполнено 1 / 10000h тактов ? Ну пусть я прочел C-> 0ABCDh, значит прерывание будет через (10000h-0ABCDh) тактов ? Мне их вполне хватит, чтобы прочесть A+B, причем раз прерывания не будет - я могу быть уверен, что ничего с ними страшного не случицца. Второй вариант: Пока обрабатывается одно прерывание, другие прерывания запрещены, пока не будет выполнена команда возврата Встроицца в обработчик прерывания типа int 76h, позвать дисковый сервис Там и прочесть ABC...
Black_mirror Исправлено: Может заставить обработчик вместо инкремента 32-битного счетчика, инкрементировать 16-битную переменную, а сложением ее и собственно счетчика, займеться собственно сам код, попутно обнуляя?
Black_mirror Первым делом нужно читать C, а потом уже B и A, чтоб точно знать, что процесс чтения может или не может быть прерван.
Chingachguk Quantum Предположим что обработчики прерываний у нас злые, вызываются в случайное время(даже обработчик прерывания от таймера, так как ему иногда приходится ждать другие обработчики) и могут иногда занимать процессор на 4001h тактов подряд, но прерывания никогда не теряются, и не менее 50% времени между прерываниями от таймера выполняется основная программа(для нашей задачи хватит). Кроме того гарантируется что если произошло переполнение счётчика, то основная программа не сможет его прочитать раньше, чем будет увеличено значение в AB. Читаем C=0C001h, что будем дальше делать? Ждать 4000h тактов? Если мы прочитали некоторое значение С, то это не значит, что прерывание от таймера будет через 10000h-С тактов, может быть обработчику прерывания от таймера придётся ждать почти 4000h тактов своей очереди, или между командами которые вычитали из 10000h прочитанное значение вклинятся другие обработчики, и тогда прерывание от таймера наступит "раньше" (допустим программа вычислила, что до прерывания осталось 5000 тактов, но пока она производила эти не сложные вычисления, 3000 тактов заняла обработка других прерываний, и реально, на момент получения результата, до прерывания осталось 2000 тактов). alpet То что в памяти две ячейки а не одна не принципиально, ситуация которую я описывал в предыдущем сообщении возможна и между чтением AB(или только B если хочется обойтись одной переменной) и С.
Black_mirror В моем случае получается, что операция чтения счетчика переполнений, включает в себя прибавление к нему значения переменной, инкрементируемой при самом переполнении. Т.е. измениться во время всего набора операций может лишь C - и переменная свидетельствующая о переполнении, что в результате даст всего лишь устаревший результат. Псевдо код: Код (Text): uint16 ovf = 0; uint16 cntr = 0; uint16 oh = 0; uint16 ol = 0; onTimer() { cntr ++; adc ovf, 0; } read (&ovfL, &ovfH, &cntr16) { cntr16 = cntr; if (ovf) { ovf = 0; // reset overflow flag ol ++; adc oh, 0; cntr16 = cntr; // timer maybe ticks before if } ovfL = ol; ovfH = oh; }
alpet Моё решение было таким(AB увеличивает обработчик прерывания): Код (Text): do{ resC=C; resA=A; resB=B; }while(resC>=8000h && C<8000h); Но твой вариант лучше, а этот не работает если обработчики прерываний захватят процессор более чем на 8000h тактов.
можно читать все три ячейки несколько раз подряд, пока разность между последними отсчётами больше нормы.
Black_mirror упрощённо: прочитать весь счётчик два раза. если между этими значениями разница больше нормы, значит процесс считывания прерывался. алгоритм примерно такой: 1. выделить область памяти для хранения предыдущего значения трёх ячеек счётчика тактов. проинициализировать нулями. 2. прочитать все три ячейки в другое место. 3. от нового 48-битного значения отнять старое. 4. записать новое значение из пункта 2 вместо старого. 5. если количество прошедших между старым и новым считыванием тактов (полученая в пункте 3 разность) больше нормального значения (реального количества тактов, которое занимает выполнение пункта 2), то перейти на пункт 2. 6. использовать сохранённое в памяти из пункта 1 значение. дополнительные соображения: чтобы сократить количество оборотов, можно пункт 1 выполнить только один раз, а все последующие разы начинать с пункта 2. пункты 3 и 4 можно объединить, если отнимать ячейки с переносом по одной. сравнение в пункте пять должно быть беззнаковым (если на целевом процессоре отрицательные числа в дополнительном коде). предполагается, что количество тактов, за которое нормально считываются три ячейки, существенно меньше чем 64к.
bsl_zcs Я вижу только один случай когда есть смысл вычитать все 48 бит - когда всё время между двумя прерываниями от таймера могут занять обработчики других прерываний, а в других случаев вполне хватит 16 младших бит.