Задачка на сообразительность(про таймер

Тема в разделе "WASM.A&O", создана пользователем Black_mirror, 27 июн 2006.

  1. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Есть 16 разрядный процессор, который имеет 16-разрядный счетчик C, увеличивающийся на 1 каждый такт. Этот счетчик можно программно считать. Когда счётчик переполняется, возникает прерывание, обработчик которого увеличивает на единицу(не элементарная операция) 32-разрядное значение, занимающее ячейки A(старшая часть) и B(младшая часть). Кроме обработчика прерываний от таймера есть еще несколько источников прерываний. Пока обрабатывается одно прерывание, другие прерывания запрещены, пока не будет выполнена команда возврата, после чего если есть еще не обработанные прерывания, произойдёт вызов их обработчиков. Если основной программе необходимо прочитать 32 разряда AB(2 операции), она может просто запретить прерывания, чтобы обработчик не изменил эти ячейки между операциями чтения. Но если программе требуется получить все 48 разрядов, включая C(3 операции), сможет ли она это сделать не запрещая прерывания?
     
  2. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine


    Крайне отстойное решение. Лучше читать ничего не запрещая и потом, если процесс прерван, скорректировать прочитанные данные (прибавить единицу, если было прерывание). О том, что прерывание было / будет можно косвенно узнать по значению С. Код должен быть безбранчевым, чтобы можно было точно посчитать сколько тактов уйдёт на весь этот процесс и потом прибавить это количество к С.
     
  3. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Quantum

    Можно считать что основные арифметические(включая adc и sbb) и логические операции у нас есть, и выполняются они за 1 такт(переходы тоже). Проблема здесь не в прибавлении 1, а в том, что например если A=1, а B=FFFFh, допустим мы сначала прочитали A=1, после чего возникло прерывание и обработчик увеличил AB, и мы читаем B=0, и думаем что таймер насчитал 10000h, а это очень далеко от истины. Здесь не обязательно выдать значение с точностью до такта, нужно сделать чтобы операция чтения была "атомарной", то есть чтобы программа не получала часть данных старыми(до обработки прерывания), а часть новыми(после обработки прерывания).
     
  4. Chingachguk

    Chingachguk New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2002
    Сообщения:
    340
    Есть 16 разрядный процессор, который имеет 16-разрядный счетчик C, увеличивающийся на 1 каждый такт.



    Если я верно понял, прерывание будет выполнено 1 / 10000h тактов ? Ну пусть я прочел C-> 0ABCDh, значит прерывание будет через (10000h-0ABCDh) тактов ? Мне их вполне хватит, чтобы прочесть A+B, причем раз прерывания не будет - я могу быть уверен, что ничего с ними страшного не случицца.



    Второй вариант:



    Пока обрабатывается одно прерывание, другие прерывания запрещены, пока не будет выполнена команда возврата



    Встроицца в обработчик прерывания типа int 76h, позвать дисковый сервис :derisive: Там и прочесть ABC...



    :derisive:
     
  5. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    Black_mirror

    Исправлено:

    Может заставить обработчик вместо инкремента 32-битного счетчика, инкрементировать 16-битную переменную, а сложением ее и собственно счетчика, займеться собственно сам код, попутно обнуляя?
     
  6. Quantum

    Quantum Паладин дзена

    Публикаций:
    0
    Регистрация:
    6 янв 2003
    Сообщения:
    3.143
    Адрес:
    Ukraine
    Black_mirror



    Первым делом нужно читать C, а потом уже B и A, чтоб точно знать, что процесс чтения может или не может быть прерван.
     
  7. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Chingachguk

    Quantum

    Предположим что обработчики прерываний у нас злые, вызываются в случайное время(даже обработчик прерывания от таймера, так как ему иногда приходится ждать другие обработчики) и могут иногда занимать процессор на 4001h тактов подряд, но прерывания никогда не теряются, и не менее 50% времени между прерываниями от таймера выполняется основная программа(для нашей задачи хватит). Кроме того гарантируется что если произошло переполнение счётчика, то основная программа не сможет его прочитать раньше, чем будет увеличено значение в AB.



    Читаем C=0C001h, что будем дальше делать? Ждать 4000h тактов? Если мы прочитали некоторое значение С, то это не значит, что прерывание от таймера будет через 10000h-С тактов, может быть обработчику прерывания от таймера придётся ждать почти 4000h тактов своей очереди, или между командами которые вычитали из 10000h прочитанное значение вклинятся другие обработчики, и тогда прерывание от таймера наступит "раньше" (допустим программа вычислила, что до прерывания осталось 5000 тактов, но пока она производила эти не сложные вычисления, 3000 тактов заняла обработка других прерываний, и реально, на момент получения результата, до прерывания осталось 2000 тактов).



    alpet

    То что в памяти две ячейки а не одна не принципиально, ситуация которую я описывал в предыдущем сообщении возможна и между чтением AB(или только B если хочется обойтись одной переменной) и С.
     
  8. alpet

    alpet Александр

    Публикаций:
    0
    Регистрация:
    21 сен 2004
    Сообщения:
    1.221
    Адрес:
    Russia
    Black_mirror



    В моем случае получается, что операция чтения счетчика переполнений, включает в себя прибавление к нему значения переменной, инкрементируемой при самом переполнении. Т.е. измениться во время всего набора операций может лишь C - и переменная свидетельствующая о переполнении, что в результате даст всего лишь устаревший результат.



    Псевдо код:
    Код (Text):
    1.  
    2. uint16 ovf = 0;
    3. uint16 cntr = 0;
    4. uint16 oh = 0;
    5. uint16 ol = 0;
    6.  
    7. onTimer()
    8. {
    9.   cntr ++;
    10.   adc ovf, 0;
    11. }
    12.  
    13. read (&ovfL, &ovfH, &cntr16)
    14. {  
    15.    cntr16 = cntr;
    16.    if (ovf)
    17.    {
    18.      ovf = 0;  // reset overflow flag
    19.      ol ++;
    20.      adc  oh, 0;    
    21.      cntr16 = cntr; // timer maybe ticks before if
    22.    }    
    23.    ovfL = ol;
    24.    ovfH = oh;  
    25. }
    26.  
     
  9. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    alpet

    Моё решение было таким(AB увеличивает обработчик прерывания):
    Код (Text):
    1. do{
    2.   resC=C;
    3.   resA=A;
    4.   resB=B;
    5. }while(resC>=8000h && C<8000h);


    Но твой вариант лучше, а этот не работает если обработчики прерываний захватят процессор более чем на 8000h тактов.
     
  10. bsl_zcs

    bsl_zcs New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2003
    Сообщения:
    17
    Адрес:
    Karaganda, Kazakhstan
    можно читать все три ячейки несколько раз подряд, пока разность между последними отсчётами больше нормы.
     
  11. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    bsl_zcs





    Можно всё это записать ввиде псевдокода, а то не совсем понятно какая разность считается?!
     
  12. bsl_zcs

    bsl_zcs New Member

    Публикаций:
    0
    Регистрация:
    5 июл 2003
    Сообщения:
    17
    Адрес:
    Karaganda, Kazakhstan
    Black_mirror



    упрощённо: прочитать весь счётчик два раза. если между этими значениями разница больше нормы, значит процесс считывания прерывался.



    алгоритм примерно такой:



    1. выделить область памяти для хранения предыдущего значения трёх ячеек счётчика тактов. проинициализировать нулями.

    2. прочитать все три ячейки в другое место.

    3. от нового 48-битного значения отнять старое.

    4. записать новое значение из пункта 2 вместо старого.

    5. если количество прошедших между старым и новым считыванием тактов (полученая в пункте 3 разность) больше нормального значения (реального количества тактов, которое занимает выполнение пункта 2), то перейти на пункт 2.

    6. использовать сохранённое в памяти из пункта 1 значение.





    дополнительные соображения:



    чтобы сократить количество оборотов, можно пункт 1 выполнить только один раз, а все последующие разы начинать с пункта 2.

    пункты 3 и 4 можно объединить, если отнимать ячейки с переносом по одной.

    сравнение в пункте пять должно быть беззнаковым (если на целевом процессоре отрицательные числа в дополнительном коде).

    предполагается, что количество тактов, за которое нормально считываются три ячейки, существенно меньше чем 64к.
     
  13. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    bsl_zcs

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