76 Отредактировано Voldemar0 (06-12-2022 11:02)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Расписал концепцию, начал реализацию.

Spoiler

Так как под капотом у нас командно-строчные утилиты, нужно как-то их подружить с web-мордой.
  Устроим это следующим образом:

  -- глобальное --
  0) AJAX: читает или сохраняет файлы настроек. Соответствующие процедуры живут main.js и используются также другими модулями.
  Этот модуль /general.js - над которым сейчас сижу/ управляет текущим именем считываемого образа, а также используемым хранилищем образов.
  Файл настроек может быть как статикой (IP-адрес, конфиг имён образов...) так и динамикой (управление накопителями).

  -- локальное --
  1) AJAX: раз в секунду или при нажатии клавиш позволяет узнать состояние утилит (работает/упала),
  запустить утилиту, передать нажатия кнопок.
  2) EventSource: утилита может сообщать свой статус в отдельный файл, который мы забираем as-is
  с утилитой file-alt-monitor в качестве бэка и интерпретируем как произвольный innerHTML.
  Этот файл регулярно меняется и передаётся целиком.
  3) EventSource: позволяет вытаскивать журнал действий утилиты: туда падают как stdout так и stderr.
  Журнал рассматривается как plain text. Это тоже файл, но отдаёт его утилита file-alt-monitor.
  Этот файл мы только дочитываем по мере его роста.

Есть проблема: как через css изобразить таблицу (т.е. без тега table) с некоторыми объединёнными ячейками ?
В инете пишут "никак, только костылями" (rowspan и collspan в css не завезли). Пытаюсь сделать костыль в виде двух таблиц, одна в два, другая три столбца, нужно чтобы первые столбцы были строго совпадающими по размерам.
Дальше нужно в одной из таблиц сделать центральное выравнивание внутри ячеек, инет говорит "Вставляйте внутрь ячейки div и уже его свойствами рулите. Иначе мозг сломаете."
Чтобы было бодрее, на следующую неделю взял отпуск :)
Когда доведу до ума вёрстку первой части (первый раздел самый сложный - там управление утилитами, к тому же всё в двух экземплярах - для 140ки и 840ки) - могу сделать доступ к устройству из инета :)

--

В этом году зима внезапно началась осенью переходом от нуля к -25 за пару суток. Ни велосы не успел подготовить ни мотаки законсервировать. Теперь каждые пару дней в гараж катаюсь, понемногу всё доделывая. Ворток на 1/2'' в руках вообще не согревается :) когда в гараже -10.

77 Отредактировано Voldemar0 (23-12-2022 13:21)

Re: Мост # 3 - специализированный компьютер для чтения дискет

<тут была ссылка>
На ближайшие сутки оставлю, можно посмотреть какой-то результат.

Пока доступна только прога измерения скорости 840ки.

На смартфонах будет, скорее всего, паршиво выглядеть, всё пилилось под более-менее широкий десктопный/ноутовый монитор.

78

Re: Мост # 3 - специализированный компьютер для чтения дискет

У меня заработало нормально (MacOS 10.15, Safari).
Кнопки управления работали хорошо.
Оно прямо к реальному дисководу подключено?

79

Re: Мост # 3 - специализированный компьютер для чтения дискет

класс! сафари у меня нет. тестриую только на фоксе, хроме и едже.
дисковод реальный, только это пока трехдюймовка.

80 Отредактировано avivanov76 (14-12-2022 21:18)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Прикольно. Если двигать головой, то иногда проскакивают странные значения (или не выводится никаких):

The head on the track   9,   -2 turnovers
The head on the track  11,   -2 turnovers
The head on the track  11,   -1 turnovers
The head on the track  11,    0 turnovers
The head on the track  11,    1 turnovers, instant time 199.42 ms, average time 199.4241 ms
The head on the track  11,    2 turnovers, instant time 199.43 ms, average time 199.4261 ms
The head on the track  11,    3 turnovers, instant time 398.86 ms, average time 265.9038 ms
The head on the track  11,    4 turnovers, instant time 398.85 ms, average time 299.1401 ms
The head on the track  11,    5 turnovers, instant time 598.27 ms, average time 358.9661 ms
The head on the track  11,    6 turnovers, instant time 199.44 ms, average time 332.3781 ms

"The head on the track" - тут куда-то сказуемое пропало. "The head is on the track".

Turnover - это, кстати, не тот оборот. Это денежный оборот или пропускная способность. А здесь нужно просто turn(s). Еще можно revolution или rotation.

И вот тут странное написано "The head on the track   0, long time... no the index signal". "No" значит "никакой", "the" значит "этот, конкретный". Уже противоречие. Ну и два артикля у существительного быть не должно.

Кнопка "-" возле поля "номер" забавно себя ведет: переключает значение между 0 и 1.

И еще любопытно: "Package version 0.97 (Trollholmsund)". Это, типа внутреннее имя? Я помню, что программка для снятия дампов тоже пишет что-то по норвежски.

81 Отредактировано Voldemar0 (15-12-2022 08:54)

Re: Мост # 3 - специализированный компьютер для чтения дискет

> Прикольно. Если двигать головой, то иногда проскакивают странные значения (или не выводится никаких)

При сдвиге головки и в начале работы программы делается сброс статистики, пару оборотов она накапливается, в это время цифры не выводятся.

Также в web-интерфейсе есть неудачный момент, когда возможна ситуация кратковременного пустого окна статуса.
Это, скорее, мой косяк. Я догадываюсь как он возникает, но для уверенности мне не хватает ясного понимания, как интерпретатор javascript взаимодействует с окном браузера.
Возможно, рано или поздно поправлю это.

А вот откуда берётся instant time > 250 ms - мне сейчас самому не ясно.
Когда тестировал эту прогу в консоли, там вроде такого не было.
Надо будет ещё поизучать её.
Тут неясность в том, что время выше 250 мс - критерий, по которому должно выводиться сообщение "не дождались индекса". Но этого сообщения нет. Хотя если флопик отключить, оно исправно выводится.
Возможно, это потеря события (время возрастает кратно оборотам). Но тогда это уже секреты линуховых драйверов.

> Кнопка "-" возле поля "номер" забавно себя ведет: переключает значение между 0 и 1.

Это немного ошибка, немного фича.
if (number < 0) number = 1;
Смысл примерно в том, что отрицательные значения недопустимы, но отсчёт предпочительно начинать от единицы. Ноль допустим, но не рекомендуется.
На практике 0 не использовался нами при нумерации дисков обычно, поэтому он так ...немного не правильно обрабатывается.

--

Английские фразы поправлю. По замыслу, основное окно - это состояние, оно на русском будет во всех утилитах. Но его видно только на web-интерфейсе.

Ниже него журнал - это то, что видно при работе без web-интерфейса, в консоли (stdout, фактически). Но там могут быть проблемы со знаками выше 127, поэтому он на английском (+ небольшая языковая практика для меня). Это больше для отладки, там могут быть разные подробности, на которые обычно можно не обращать внимания.

> И еще любопытно: "Package version 0.97 (Trollholmsund)". Это, типа внутреннее имя? Я помню, что программка для снятия дампов тоже пишет что-то по норвежски.

Да, это общая строка-константа, которая встраивается в код всех утилит.
Она будет меняться после того, как этот софт будет использоваться хотя бы в двух экземплярах устройств.

К сожалению, не могу вспомнить, откуда взял это слово. Но вообще, в норвежском много слов, начинающихся на Troll: Trollveggen (Стена Тролей - участок горного массива в Норвегии), Trollkvinne - ведьма (ведьма-тролль). Нередко так и другие слова объединятся в названиях.

"программка для снятия дампов" ??? это о чём речь ?

У какой-то из прошивок ps/2 адаптера было название "полярный медведь" (в норвежском это одно слово - isbjørn) и потом была версия FRAM - название судна, построенного Ф. Нансеном (норвежский исследователь).

82 Отредактировано Voldemar0 (15-12-2022 15:12)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Исправил ошибки в английском, немного подшаманил фронт, теперь вроде бы строчка статуса выводится ещё ровнее (не моргает).

==

Зарегил лог странного сбоя, когда при движении головки первые отсчёты сбиваются.

Явно теряются события фронта/спада. Это странно, надо будет порыться на эту тему в инете.
Но почему именно при движении головки - как раз понятно: при нажатии любой клавиши фронт отсылает беку нажатые клавиши,
а автоповтор у меня - 40 знаков в секунду (Каждое нажатие - новое TCP/HTTP-соединение. У форума такой нагрузки нет :). Проц моста загружается под 80% и, видимо, дальше что-то ломается в логике GPIO-драйверов.

Заодно узнал, что сама прога Скорость грузит проц меньше чем на 1%, ещё 15% жрёт UI-server (он обслуживает экраны и клавиатуру на плате, а заодно и буферизует очередь нажатых кнопок для бэкэнда). Но зачем ему 15% - я догадываюсь: он симулирует через bitbang тот лютый протокол a'la "обгрызанный i2c", который использует контроллер дисплея и клавиатуры tm1637. Загруз, скорее всего, связан с постоянным (каждый оборот) опросом клавиатуры (десяток байт на оборот флопика). Надо будет прореживать его, на будущее... Может быть.

И ещё 15% времени уходит на разное другое общение с web-сервером (если не нажимать кнопки).
Если открыть статические страницы - эта нагрузка пропадает.

==

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

Сделанных разработок по web-интерфейсу на ближашие месяцы хватит, может только чуть подпиливать придётся.
Я теперь займусь плотненько вопросами обмена с семплером.
Там должна начатся самая вкуснятка :)))

83 Отредактировано avivanov76 (15-12-2022 23:41)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Voldemar0 пишет:

"программка для снятия дампов" ??? это о чём речь ?

Я про вот эту:

Spoiler

http://forum.agatcomp.ru//misc.php?action=pun_attachment&amp;item=1209&amp;download=1

Post's attachments

Attachment icon ROM_dump.jpg 96.81 kb, 327 downloads since 2022-12-15 

84 Отредактировано Voldemar0 (19-12-2022 18:50)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Вычёсываю один из нагруженных кодов обработки: код преобразования битовой последовательности от семплера в длительности интервалов между импульсами.

Получая очередное слово (переменная v, 32 бита), его нужно проанализировать побитно в таком цикле:

 

  (в комментариях: приблизительный ARM-ассемблер для случая "-O0" - отключенная оптимизация компилятором)

    for (int bit = 31; bit >= 0; bit--) {

#  ifdef RAISE1
/*
        ldr     r3, [r7, #16]   @ tmp139, pv
        mvns    r2, r3  @ _4, tmp139
        ldr     r3, [r7, #20]   @ tmp140, v
        ands    r3, r3, r2      @, _5, tmp140, _4
        cmp     r3, #0  @ _6,
        bge     .L9             @,
                timedraw(PLT)
L9:
        ldr     r3, [r7, #20]   @ tmp141, v
        str     r3, [r7, #16]   @ tmp141, pv
*/

      if (v & (pv ^ 0xFFFFFFFF) & 0x80000000) {
        timereg((u_int8_t *)buf, bits_interval, out_addr);
      }
      pv = v;
#  else
/*     Raise2
        ldr     r2, [r7, #20]   @ tmp138, v
        ldr     r3, [r7, #16]   @ tmp139, pv
.LVL20:
        eors    r3, r3, r2      @, _4, tmp139, tmp138
        cmp     r3, #0  @ _5,
        bge     .L9             @,
        ldr     r3, [r7, #20]   @ tmp140, v
        cmp     r3, #-2147483648        @ tmp140,
        beq     .L10            @,
                timedraw(PLT)
L10:
        ldr
        str
L9:
*/
      if ((v ^ pv) & 0x80000000) {
        if (v & 0x80000000) {
          timereg((u_int8_t *)buf, bits_interval, out_addr);
        }
        pv = v;
      }
#  endif
      v <<= 1;
      bits_interval++;
    }

Если находим смену потока нулей на поток единиц, процедурой timereg() (макрос фактически)
регистрируем интервал (накапливается в bits_interval) от предыдущего фронта до текущего.

Два варианта алгоритма: Raise1 и Raise2.

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

Какой будет быстрее ? По асму видно, что само количество команд процессора примерно одинаковое.

Сравнил 8 вариантов: для imx6 и PC с процом E5200, для двух вариантов оптимизации кода (-O0 и -O2) и для двух алгоритмов:
Raise1:
PC: -O2 t = 0.19, -O0 t = 0.28;
arm: -O2 t = 0.82, -O0 t = 3.63

Raise2:
PC: -O2 t = 0.21, -O0 t = 0.25;
arm: -O2 t = 0.59, -O0 t = 3.19

Время в секундах ("t = ...") на обработку входного массива 8 Мб (случайные значения, немного похожие на запись 140ки).

Итого:
- Для этой процедуры важно включить оптимизацию кода компилятором (-O2)
-  Вариант с двумя IF почти всегда немного быстрее. Да, ветвление, но компиляция более сложного условия даёт примерно такой же код, но, вероятно, вынос из каждой итерации "pv = v"  (пара комманд ассемблера на -O0 и, вероятно, одна на -O2) всё таки даёт некоторый прирост скорости.

-==-

Этот код должен перемолоть на каждый трек примерно 220 Кб данных примерно в 30 Кб для дальнейших алгоритмов.
Его работа не зависит ни от чего больше (т.е. алгоритм единственный и не выбирается), важен он для любого вида чтения данных
и для любого дисковода.
Можно прикинуть, что на этот шаг уйдёт для Raise2 с -O2  где-то 0.016 секунды, что вполне терпимо.

-==-

А на "AMD Ryzen3 1200" Raise2 явно проигрывает: 0.062с против 0.045с для -O2, и 0.199с против 0.194с на -O0.

85 Отредактировано avivanov76 (19-12-2022 21:13)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Я так понял, надо просто искать паттерн 01 в смежных битах. Что, если вот так:

// цикл до 1
for (int bit = 31; bit > 0; bit--)
{
    if ((v & 0xC0000000) == 0x40000000)
    {
        timereg((u_int8_t *)buf, bits_interval + 1, out_addr);
    }

    v <<= 1;
    bits_interval++;
}

// обработка последнего бита - нужен старший бит из следующего слова
v |= (vnext >> 1);
if ((v & 0xC0000000) == 0x40000000)
{
    timereg((u_int8_t *)buf, bits_interval + 1, out_addr);
}

bits_interval++;
v = vnext;

bits_interval + 1, потому что проверка будет срабатывать на шаг цикла раньше. Хотя, если меряется интервал между проверками, то  может это и лишнее.

86 Отредактировано Voldemar0 (20-12-2022 09:56)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Мысль интересная, работает, но по скорости не дотягивает до Raise2.
Почему - не ясно.

При отключенной оптимизации твой алгоритм опережает мои:
PC: raise1: 0.29; raise2: 0.26; aviv: 0.21.
arm: raise1: 3.61; raise2: 3.18; aviv: 3.00.

Но на включенной оптимизации (в предыдущем сообщении для PC были ошибки):
PC: raise1: 0.13; raise2: 0.13; aviv: 0.11.
arm: raise1: 0.81; raise2: 0.59; aviv: 0.78.  Тут в лидеры выбивается raise2.

Я пытался разобраться в оптимизированном коде, но я плохо понимаю работу команды "IT" (IfThen),
а она там часто встречается. В общем, не хватает знаний по arm'овскому ассемблеру.
А код получается довольно витиеватый. Да и неплохо было бы знать тайминги отдельных команд.

Причем различия в коде касаются не только изменяющихся строк, но и соседних, в т.ч. timereg().
Компилятор явно пытается всякие сложения и инкременты тасовать ( "bits_interval + 1" использует затем в "bits_interval++" ), в то же время некоторые операции он, похоже, начинает дублировать (какой-то reorder операций?).

Твоя версия:

Spoiler

    movs    r2, #31    @ ivtmp_41,
.L49:
.LBB9:
@ sram-rw.c:193:       if ((v & 0xC0000000) == 0x40000000) {    // PC -O2 t = 0.112, -O0 t = 0.213; arm -O2 t = 0.78, -O0 t = 3.00
    .loc 1 193 14
    and    r0, r3, #-1073741824    @ tmp148, v,
@ sram-rw.c:193:       if ((v & 0xC0000000) == 0x40000000) {    // PC -O2 t = 0.112, -O0 t = 0.213; arm -O2 t = 0.78, -O0 t = 3.00
    .loc 1 193 10
    cmp    r0, #1073741824    @ tmp148,
    it    ne
    addne    r1, r1, #1    @ bits_interval, bits_interval,
    bne    .L48        @,
@ sram-rw.c:195:     timereg((u_int8_t *)buf, bits_interval + 1, out_addr);
    .loc 1 195 2
    cmp    r1, #127    @ bits_interval,
    it    cs
    movcs    r1, #127    @ bits_interval,
    mov    r0, r1    @ tmp149, bits_interval
    movs    r1, #1    @ bits_interval,
    strb    r0, [r5, r4]    @ tmp149, *_10
    add    r4, r4, r1    @ out_addr,
.L48:
@ sram-rw.c:197:       v <<= 1;
    .loc 1 197 9 discriminator 2
    lsls    r3, r3, #1    @ v, v,
@ sram-rw.c:191:     for (int bit = 31; bit > 0; bit--)
    .loc 1 191 5 discriminator 2
    subs    r2, r2, #1    @ ivtmp_41, ivtmp_41,
    bne    .L49        @,
.LBE9:
@ sram-rw.c:202:     v |= (buf[in_addr+1] >> 1);
    .loc 1 202 26
    ldr    r2, [r6]    @ MEM[base: _9, offset: 0B], MEM[base: _9, offset: 0B]
@ sram-rw.c:202:     v |= (buf[in_addr+1] >> 1);
    .loc 1 202 7
    orr    r3, r3, r2, lsr #1    @ v, v, MEM[base: _9, offset: 0B],
@ sram-rw.c:203:     if ((v & 0xC0000000) == 0x40000000) {
    .loc 1 203 12
    and    r3, r3, #-1073741824    @ tmp154, v,
@ sram-rw.c:203:     if ((v & 0xC0000000) == 0x40000000) {
    .loc 1 203 8
    cmp    r3, #1073741824    @ tmp154,
    it    ne
    addne    r1, r1, #1    @ bits_interval, bits_interval,
    bne    .L51        @,
@ sram-rw.c:205:       timereg((u_int8_t *)buf, bits_interval + 1, out_addr);
    .loc 1 205 7
    cmp    r1, #127    @ bits_interval,
    mov    r3, r1    @ bits_interval, bits_interval
    it    cs
    movcs    r3, #127    @ bits_interval,
    movs    r1, #1    @ bits_interval,
    strb    r3, [r5, r4]    @ tmp155, *_20
    add    r4, r4, r1    @ out_addr,
.L51:

Raise2:

Spoiler

    movs    r2, #32    @ ivtmp_33,
    b    .L50        @
.L61:
.LBB9:
@ sram-rw.c:209:     for (int bit = 31; bit >= 0; bit--) {
    .loc 1 209 5
    subs    r2, r2, #1    @ ivtmp_33, ivtmp_33,
    add    r1, r1, #1    @ bits_interval, bits_interval,
@ sram-rw.c:262:       v <<= 1;
    .loc 1 262 9
    lsl    r3, r3, #1    @ v, v,
@ sram-rw.c:209:     for (int bit = 31; bit >= 0; bit--) {
    .loc 1 209 5
    beq    .L64        @,
.L50:
@ sram-rw.c:253:       if ((v ^ pv) & 0x80000000) {        // PC -O2 t = 0.126, -O0 t = 0.26; arm -O2 t = 0.59, -O0 t = 3.18
    .loc 1 253 10
    teq    r3, r0    @ v, pv
    bpl    .L61        @,
@ sram-rw.c:254:         if (v & 0x80000000) {
    .loc 1 254 12
    cmp    r3, #0    @ v,
@ sram-rw.c:256:       timereg((u_int8_t *)buf, bits_interval, out_addr);
    .loc 1 256 4
    mov    r0, r3    @ pv, v
@ sram-rw.c:254:         if (v & 0x80000000) {
    .loc 1 254 12
    bge    .L61        @,
@ sram-rw.c:262:       v <<= 1;
    .loc 1 262 9
    lsls    r3, r3, #1    @ v, v,
@ sram-rw.c:256:       timereg((u_int8_t *)buf, bits_interval, out_addr);
    .loc 1 256 4
    cmp    r1, #127    @ bits_interval,
    it    cs
    movcs    r1, #127    @ bits_interval,
@ sram-rw.c:209:     for (int bit = 31; bit >= 0; bit--) {
    .loc 1 209 5
    subs    r2, r2, #1    @ ivtmp_33, ivtmp_33,
@ sram-rw.c:256:       timereg((u_int8_t *)buf, bits_interval, out_addr);
    .loc 1 256 4
    mov    r5, r1    @ tmp146, bits_interval
    mov    r1, #1    @ bits_interval,
    strb    r5, [r6, r4]    @ tmp146, *_12
    add    r4, r4, r1    @ out_addr,
@ sram-rw.c:209:     for (int bit = 31; bit >= 0; bit--) {
    .loc 1 209 5
    bne    .L50        @,
.L64:
.LBE9:

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

87

Re: Мост # 3 - специализированный компьютер для чтения дискет

Voldemar0 пишет:

Да и неплохо было бы знать тайминги отдельных команд.

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

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

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

Я сравнил минимальные циклы (без содержимого if) и вижу, что компилятор переделал в моей версии цикл for:

.L49
// if ((v & 0xC0000000) == 0x40000000) {
    and    r0, r3, #-1073741824
    cmp    r0, #1073741824

// bits_interval++
// условный add, если Z=0, то выполняется, иначе пропускается
    addne    r1, r1, #1
    bne    .L48

// содержимое if пропустим

.L48:
// v <<= 1;
    lsls    r3, r3, #1

// декремент bit от цикла for
    subs    r2, r2, #1

// условие выхода из цикла
// subs выполнялась только что, возможно придется ждать ее результата
    bne    .L49

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

А в твоей версии цикл такой:

L61:
// bit--
    subs    r2, r2, #1

// bits_interval++
    add    r1, r1, #1

// v <<= 1;
    lsl    r3, r3, #1

// условие выхода из цикла
// флаг установлен инструкцией subs, причем после нее прошло не менее 2 тактов
    beq    .L64

// if ((v ^ pv) & 0x80000000) {
// флаг N содержит XOR старших битов
    teq    r3, r0
    bpl    .L61

// содержимое if пропустим

Тут 6 инструкций вместо 7 и всего один выполняющийся переход. Любопытно, что здесь для проверки условия достаточно одной инструкции teq. Я то думал их будет две.

Ну и я дополнительно запутал компилятор, сделав цикл до 1. Если есть возможность, было бы интересно попробовать:

for (int bit = 30; bit >= 0; bit--)

Возможно, тогда выйдет по нулям :) Вообще, любопытно получилось.

88

Re: Мост # 3 - специализированный компьютер для чтения дискет

Попробовал. Вы будете смеятся, но нынешние компиляторы очень умные :)
Он сообразил, что число итераций не изменилось, а переменная цикла нигде не участвует и не стал вообще ничего менять в коде :)
Так-то лишних команд вроде нет: mod r2, #31 / subs    r2, r2, #1 / bne
cmp не нужна. Он счастлив вполне :)
Ожидаемо, скорости тоже нигде не изменились.

89

Re: Мост # 3 - специализированный компьютер для чтения дискет

Вот бы еще компиляторы всегда были такие умные! Я просто вспомнил, что компилятор Delphi по разному циклы компилирует, в зависимости от границ. Думал, может и тут это повлияет.

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

В одном случае он построил цикл так, что первая инструкция bne делает переход если условие if не выполняется, а вторая делает переход, если цикл не закончен. В результате на каждой итерации конвейер очищается два раза.

А в другом случае он сделал цикл с входом в середину, при этом, пока цикл не закончен, beq не выполняется и переход делается только один.

Возможно, причина в том, что компилятор не знает, какие данные будут обрабатываться. Если бы он знал, что условие if выполняется редко, то он бы лучше оптимизировал цикл. Даже в ущерб скорости выполнения условия.
А он не знает и пытается оптимизировать обе ветки.

Вот, кстати, чем хороши суперскалярные процессоры - они могут обработку инструкций менять с учетом обрабатываемых данных.

90 Отредактировано Voldemar0 (22-12-2022 09:26)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Запилил значительно модифицированный драйвер spidev.c, разобрал ряд разных случаев его использования (как модифицированной, так и не модифицированной версии) и пришел к выводу, что есть некий потолок, связанный с архитектурой SPI в линухе, который не позволяет прыгнуть выше примерно 1 МБайт / секунду на моём железе.
Все игры с переносом между ядром и прогой и вылизыванием алгоритмов компрессии на самом деле мало на что влияют. (Да, кстати: модули ядра собираются с оптимизацией -O2, как выяснилось). Для себя составил конспект с цифрами различных скоростей в различных конфигурациях, но здесь его, наверное, нет смысла публиковать.

Самое мощное ускорение принесли пакетные запросы: это когда на уровень драйвера железа запросы на чтение скидываются не по одному (это примерно 64 байта за запрос - потолок железа), а пакетами, штук по 10 (в сумме примерно 600 байт за одно обращение к драйверу железа). И не важно: формировать ли их в драйвере более высокого уровня (уже на универсальном уровне, не связанном с конкретным железом) или же в пользовательской программе. Небольшая разница по скорости есть, но уже где-то в районе десятка процентов.

В то же время отчётливо видно, что ЦПУ не всегда загружен, т.е. пока идёт обмен, нагрузка на проц постоянно прыгает - можно использовать его в других целях. Теоретически, можно попробовать в это время как раз выполнять компрессию очередного блока данных, но оценка показывает, что это вряд ли даст офигенный прирост скорости, а вот сложности в драйвере spidev.c прибавит. Сейчас он строго синхронный, т.е. там нет никакого распараллеливания обработки и у меня нет достаточного скила для перепиливания его в многопоточный вариант.
При этом сейчас получить дорожку из семплера (и сразу сжатую внутри драйвера) стоит 0.255 секунды, из которых, по косвенной оценке:
0.238 секунды на чтение данных и 0.017 секунды на компрессию.
Т.е. выигрыш при распараллеливании составит, максимум, процентов 10. Ни о чём.

Таким образом, работу по этой части я пока считаю завершенной.

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

Фактически, я получил что-то вроде флюксы или SCP, только без PC-шной части софта.

< ....если по отладочному порту подключить Мост3 к ППИ Агата..... но тут фантазия упирается в стенку :) >

-=-=

PS Насчёт предсказания переходов: мне че-то вспоминается, что в ассемблере i386 поздних версий есть некий необязательный префикс команд ветвления, который позволял воткнуть в исходник проги подсказку процессору, куда, скорее всего, сработает ветвление. И вроде бы в манах говорилось, что если подсказки нет, то ветвление назад считается высоко вероятным, а ветвление вперёд - низковыроятным, если эта команда ещё не выполнялась. Если выполнялась и в кеше есть информация о реальном положении дел, то именно оно считается более вероятным.

А вот в выскоуровневых языках как раз как-то вроде нет примеров какого-то синтаксиса, который бы позволял указать более вероятный результат для IF, например.
https://runebook.dev/ru/docs/cpp/langua … tes/likely
? реально работает ?

91 Отредактировано Voldemar0 (22-12-2022 11:20)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Попробовал "likely", на Raise2 это почти никак не повлияло, а вот твой код компилятор немного перетряхнул и он стал чуть быстрее.

Spoiler

    movs    r2, #31    @ ivtmp_41,
    b    .L49        @
.L65:
.LBB9:
@ sram-rw.c:194:     for (int bit = 30; bit >= 0; bit--)    // modif0  PC -O2 t = 0.110, -O0 t = 0.212; arm -O2 t = 0.78, -O0 t = 3.00
    .loc 1 194 5
    subs    r2, r2, #1    @ ivtmp_41, ivtmp_41,
    add    r1, r1, #1    @ bits_interval, bits_interval,
@ sram-rw.c:200:       v <<= 1;
    .loc 1 200 9
    lsl    r3, r3, #1    @ v, v,
@ sram-rw.c:194:     for (int bit = 30; bit >= 0; bit--)    // modif0  PC -O2 t = 0.110, -O0 t = 0.212; arm -O2 t = 0.78, -O0 t = 3.00
    .loc 1 194 5
    beq    .L64        @,
.L49:
@ sram-rw.c:196:       if (unlikely((v & 0xC0000000) == 0x40000000)) {    // PC -O2 t = 0.112, -O0 t = 0.213; arm -O2 t = 0.78, -O0 t = 3.00
    .loc 1 196 11
    and    r0, r3, #-1073741824    @ tmp148, v,
@ sram-rw.c:196:       if (unlikely((v & 0xC0000000) == 0x40000000)) {    // PC -O2 t = 0.112, -O0 t = 0.213; arm -O2 t = 0.78, -O0 t = 3.00
    .loc 1 196 10
    cmp    r0, #1073741824    @ tmp148,
    bne    .L65        @,
@ sram-rw.c:200:       v <<= 1;
    .loc 1 200 9
    lsls    r3, r3, #1    @ v, v,
@ sram-rw.c:198:     timereg((u_int8_t *)buf, bits_interval + 1, out_addr);
    .loc 1 198 2
    cmp    r1, #127    @ bits_interval,
    it    cs
    movcs    r1, #127    @ bits_interval,
@ sram-rw.c:194:     for (int bit = 30; bit >= 0; bit--)    // modif0  PC -O2 t = 0.110, -O0 t = 0.212; arm -O2 t = 0.78, -O0 t = 3.00
    .loc 1 194 5
    subs    r2, r2, #1    @ ivtmp_41, ivtmp_41,
@ sram-rw.c:198:     timereg((u_int8_t *)buf, bits_interval + 1, out_addr);
    .loc 1 198 2
    mov    r0, r1    @ tmp149, bits_interval
    mov    r1, #1    @ bits_interval,
    strb    r0, [r6, r4]    @ tmp149, *_13
    add    r4, r4, r1    @ out_addr,
@ sram-rw.c:194:     for (int bit = 30; bit >= 0; bit--)    // modif0  PC -O2 t = 0.110, -O0 t = 0.212; arm -O2 t = 0.78, -O0 t = 3.00
    .loc 1 194 5
    bne    .L49        @,
.L64:
.LBE9:
@ sram-rw.c:205:     v |= (buf[in_addr+1] >> 1);
    .loc 1 205 26
    ldr    r2, [r5]    @ MEM[base: _8, offset: 0B], MEM[base: _8, offset: 0B]
@ sram-rw.c:205:     v |= (buf[in_addr+1] >> 1);
    .loc 1 205 7
    orr    r3, r3, r2, lsr #1    @ v, v, MEM[base: _8, offset: 0B],
@ sram-rw.c:206:     if (unlikely((v & 0xC0000000) == 0x40000000)) {
    .loc 1 206 9
    and    r3, r3, #-1073741824    @ tmp154, v,
@ sram-rw.c:206:     if (unlikely((v & 0xC0000000) == 0x40000000)) {
    .loc 1 206 8
    cmp    r3, #1073741824    @ tmp154,
    beq    .L50        @,
    adds    r1, r1, #1    @ bits_interval, bits_interval,
.L51:
@ sram-rw.c:165:   while (in_addr < SRAM_SIZE) {
    .loc 1 165 9
    cmp    ip, r5    @ _9, ivtmp.52
    bne    .L52        @,
@ sram-rw.c:272:   printf("No final signatire found :(((\n");
    .loc 1 272 3
    ldr    r0, .L67    @,
.LPIC30:
    add    r0, pc    @
    bl    puts(PLT)    @
@ sram-rw.c:273:   return out_addr;
    .loc 1 273 10
    mov    r0, r4    @ <retval>, out_addr
@ sram-rw.c:274: }
    .loc 1 274 1
    pop    {r3, r4, r5, r6, r8, pc}    @
.L53:
@ sram-rw.c:166:     v = buf[in_addr];
    .loc 1 166 7
    mov    lr, r3    @ final_val, v
@ sram-rw.c:171:     final_cnt++;
    .loc 1 171 11
    mov    r8, #1    @ final_cnt,
    b    .L45        @
.L50:
@ sram-rw.c:208:       timereg((u_int8_t *)buf, bits_interval + 1, out_addr);
    .loc 1 208 7
    cmp    r1, #127    @ bits_interval,
    mov    r3, r1    @ bits_interval, bits_interval
    it    cs
    movcs    r3, #127    @ bits_interval,
    movs    r1, #1    @ bits_interval,
    strb    r3, [r6, r4]    @ tmp155, *_26
    add    r4, r4, r1    @ out_addr,
    b    .L51        @

На PC скорость не изменилась, а на arm теперь 0.65.

Ещё один вид совсем уж хардкорной оптимизации:
https://habr.com/ru/post/138132/

92 Отредактировано Voldemar0 (22-12-2022 14:40)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Ня :) SD-формат (720k), PC

Spoiler

 

Track 9 [49649 byte(s)], spectrum maximum on point  4.00 mks [index = 32, value = 30047]:
15023/30047 -                                 *                                                                                               
 7511/30047 -                                 *                                                                                               
 3755/30047 -                                **               *                                                                               
 1877/30047 -                                ***              *                                                                               
  938/30047 -                                ***             ***                                                                              
  469/30047 -                                ***             ***                                                                              
  234/30047 -                                ***             ***             ***                                                              
  117/30047 -                                ***            ****             ***                                                              
   58/30047 -                                ***            *****           ****                                                              
   29/30047 -   *                            ***            *****           *****                                                             
   14/30047 -   *                           ****            *****           *****                                                             
    7/30047 -   *                           ****            *****          ******                                                             
    3/30047 -   *                        *******            *****          ******                                                             
    1/30047 -   *    *            *  *   ******* *         ******          ******  * *                                        *               
    0/30047 -   **   **           ****************    **   ******* *     ********  * **                               *       *               
_____/_____ - 00 mks  01 mks  02 mks  03 mks  04 mks  05 mks  06 mks  07 mks  08 mks  09 mks  10 mks  11 mks  12 mks  13 mks  14 mks  15 mks  

  Track 10 [51181 byte(s)], spectrum maximum on point  4.00 mks [index = 32, value = 35739]:
17869/35739 -                                 *                                                                                               
 8934/35739 -                                 *                                                                                               
 4467/35739 -                                **                                                                                               
 2233/35739 -                                **               *                                                                               
 1116/35739 -                                ***             ***                                                                              
  558/35739 -                                ***             ***                                                                              
  279/35739 -                                ***             ***                                                                              
  139/35739 -                                ***             ***             **                                                               
   69/35739 -                                ***             ***             ***                                                              
   34/35739 -   *                            ***            *****            ***                                                              
   17/35739 -   *                            ***            *****            ***                                                              
    8/35739 -   *                            ***            *****           ****                                                              
    4/35739 -   *                        ** ****            *****           *****                                                             
    2/35739 -   *    *             *     ** ****            *****        *  *****                                                             
    1/35739 -   *    *             *     *******         *  *****        *  ******   *                                                        
_____/_____ - 00 mks  01 mks  02 mks  03 mks  04 mks  05 mks  06 mks  07 mks  08 mks  09 mks  10 mks  11 mks  12 mks  13 mks  14 mks  15 mks  

Кажется, вертикальная шкала такого типа должна называться "логарифмическая, с основанием 2" ?

93

Re: Мост # 3 - специализированный компьютер для чтения дискет

Voldemar0 пишет:

Попробовал "likely", на Raise2 это почти никак не повлияло, а вот твой код компилятор немного перетряхнул и он стал чуть быстрее.

Класс! Надо запомнить, вдруг пригодится. Да, теперь получился такой же цикл с входом в середину и все переходы работают также как в Raise2. Похоже, что разница в скорости образуется в основном из-за более сложной проверки условия: teq явно работает быстрее, чем пара and и cmp. Ну тут уж извините, кто же знал, что на ARM такое есть :) (Кто-нибудь возьмется утверждать, что у ARM упрощенный набор команд?)

Voldemar0 пишет:

Ня :) SD-формат (720k), PC

Это чего, гистограмма что ли? Свят, свят, свят!

94 Отредактировано Voldemar0 (23-12-2022 06:56)

Re: Мост # 3 - специализированный компьютер для чтения дискет

> Кто-нибудь возьмется утверждать, что у ARM упрощенный набор команд?

Против 6502 - сложный :))

> Класс! Надо запомнить, вдруг пригодится.

Учти, что likely - это макрос. Он определён в исходниках ядра линуха, но не определён в общесистемых /usr/include .
Точнее говоря: определён, но не доступен во всяких stdio.h, stdlib.h....
Причем его определения в /usr/include и в ядре немного отличаются.
Я использовал вариант из ядра:

# define likely(x)      __builtin_expect(!!(x), 1)
# define unlikely(x)    __builtin_expect(!!(x), 0)

И ещё тут интересная статья, в т.ч. комментарии к ней.
https://blog.aaronballman.com/2020/08/d … ttributes/
В комментариях, если я верно понял, говорят о том, что фича стандартная для C++,
но не стандартная для C и у GCC она реализована не так, как рекомендуется для C++.

--

> Это чего, гистограмма что ли? Свят, свят, свят!

Наверное это правильнее назвать "гистограмма спектра сигнала".

Очень легко строится (30 строк исходника) и позволяет сразу выявить некоторые особенности записи. Оценить (в сравнении двух спектров) уровень ошибок, формат записи (140 vs 840), ошибку скоростей между записью и чтением...
Я с неё начинал разработку софта для scp и флюксы.

95

Re: Мост # 3 - специализированный компьютер для чтения дискет

   34/35739 -   *
   17/35739 -   *
    8/35739 -   *
    4/35739 -   *
    2/35739 -   *    *
    1/35739 -   *    *
_____/_____ - 00 mks  01 mks                               

Кстати, а что это за пик в нуле? Вроде как с дисковода не должно приходить импульсов короче 1 мкс.
Какой-то "звон" отсемплировался?

96

Re: Мост # 3 - специализированный компьютер для чтения дискет

> Какой-то "звон" отсемплировался?
Возможно, финальная сигнатура.
Она вводится для обнаружения конца захвата.
В начале дорожки тоже есть нечто подобное; наверное, уберу это позднее.

97 Отредактировано Voldemar0 (31-12-2022 22:15)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Часть 4
https://youtu.be/HGRoxLRAmfQ

А я пока начал заходить строго курсом на софт чтения 840ок, беру свои же исходники для флюксы и переписываю под мост3, стараясь избавиться от float point-времени (imx6 здорово тормозит на этой арифметике). И странно:  то ли ошибки собственные нахожу, то ли чего-то не понимаю.... Для флюксы у меня тесты были на снятых реальных образах, а сейчас пытаюсь всё то же делать на случайных синтезированных данных. Свежести головы не хватает, а увидеть прочитанный каталог дискеты хочется до окончания праздников.

98 Отредактировано Voldemar0 (09-01-2023 09:48)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Выходные закончились, не знаю как пойдёт дальше, но за последнюю неделю успел многое.

==

a) Проработал архитектуру стека декодеров.
Декодеров 4 слоя:

1) Преобразование битового потока в массив интервалов. Сейчас сидит в драйвере spidev.c.

Для тестов также написал простой конвертор из sql3-файлов fluxengine в формат близкий к тому, что даёт spidev.c.
(есть несколько давно снятых образов; чтобы при отладке иметь хорошую повторяемость ошибок важно чтобы и данные были каждый раз одинаковыми). Слоистая структура цепочки декодирования позволяет легко менять слои.

2) Преобразование массива интервалов в массив исходных нулей и единичек MFM/GCR-кодера.
Т.е., например, для GCR: интервалы 2.0-6.0 mks - это "1", 6.0-10.0 mks - "10" и т.д.

Этот слой - самая замысловатая часть. Именно тут происходит компенсация ошибок скоростей дисководов, учёт скоростей (300/360 rpm), фазовые ошибки и всё такое.

У меня есть код для флюксы, написанный год-два назад на pascal, заточенный под offline-обработку образов флюксы на PC, широко использует плавающую точку. Этот код - не слоистый, архитектурно там "всё в одном". Я переписывал его под arm, под слои, стараясь перевести все на целочисленную арифметику.

После первоначальной отладки ещё пару дней ковырялся с финальными косяками.

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

Всё дело в том, что, в зависимости от типа ошибок (джиттер vs систематическая ошибка) алгоритмы коррекции будут противоположными. Джиттер: один импульс сдвинулся, значит, если интервал времени до него уменьшился, то после него увеличился. Если систематическая ошибка, то рост интервала до импульса показывает на то, что нужно ожидать роста интервала и после импульса.

Систематическая ошибка на дисководах довольно незначительная: 1-2%, полная ошибка (если пишущий дисковод имеет ошибку противоположную читающему) - 2-4%. Это почти незаметно и легко компенсируется тем, что, фактически, каждый новый импульс восстанавливает синхронизацию между устройством записи и устройством чтения. Джиттер же гораздо существеннее и именно его должен компенсировать умный алгоритм восстановления интервалов. Но джиттер случаен. А есть ещё фазовые искажения: один импульс "убегает" от другого на коротких интервалах или "притягивается" к другому на длинных. Это должно частично устраняться предкомпенсацией записи, но она работает с 2-3 зонами (у 840ки агата их три, у PC-совместимых - две, вроде бы), внутри зоны каждая соседняя дорожка немного отличается от предыдущей, а значит, если даже какая-то одна дорожка будет идеальной, то соседние всё равно будет иметь более или менее заметные фазовые искажения.

В погоне за объёмом хранимых данных пара дисковод+дискета проектируются так, чтобы сократить интервалы между импульсами. Но фазовая ошибка при этом становится существенной по сравнению с интервалом между импульсами. И тут как раз становится понятным, почему некоторые алгоритмы восстановления интервалов хорошо работают с 140кой, а другие - с 840кой.

140ка имеет бОльшие интервалы, чем 840ка, и большее окно захвата очередного бита. В результате, она практически нечувствительна к фазовым искажениям (они заметно меньше окна захвата), не требует предкомпенсации записи, но отказ от последних 5 дорожек (35-40) в 140ке, вероятно, как раз и вызван тем, что там уже проще было не хранить данные, чем накручивать сложности для борьбы с фазовыми искажениями. Соответственно, она требует только борьбы с джиттером. Всё в угоду снижению ценника. Итог: 4.00 кб / дорожку.

840ка наоборот: тут пытались вытащить всё, что можно получить от механники и физики, пусть ценой усложнения схем. Интервалы сокращены, окна захвата в два (!!!) раза меньше, фазовые ошибки становятся заметны и их коррекциях играет большую роль как при записи (предкомпенсация записи), так и при чтении. Итог: 5.25 кб / дорожку.

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

Но сейчас я хотя бы понял, почему вообще к 140ке и 840ке лучше подходят разные алгоритмы коррекции ошибок.

Вторая проблема отладки слоя 2 была в отказе (точнее, вынесении "за скобки") арифметики с плавающей точкой. Там тоже пришлось повозится, чтобы выловить все потери точностей. В pascal-версии все интервалы времени считались в mks, теперь же все характерные времена заранее пересчитываются в тики задающего генератора семплера
и дальше вся математика работает с ними.

3) Слой 3 уже проще: тут из нулей и единиц, полученных от слоя 2 собирается изначальный байтовый поток дорожки. Если в слоях 1 и 2 алгоритмы не отличаются для различных форматов записи (140/840/PC-совместимые), меняются только настройки для слоя 2, то слой 3 - это уже разные алгоритмы, в зависимости от формата записи.
840 и PC похожи, различие в синхросимволах и их интерпретации. 140ка - сама по себе.
В этом слое и кода меньше и он устроен однозначнее, чем в слое 2.
Слой 3 может на выходе синтезировать старый eim-формат, использовавшийся в Мостах 2.
Для PC-формата слой 3 тоже выдаёт что-то вроде старого eim, но, вряд ли имеет смысл сохранять его в таком виде файлах, он будет использоваться только для передачи данных слою 4.

4) Слой 4 - это уже формирование DSK-образа для любого из форматов. Алгоритмы разные для разных форматов, но тоже однозначные. Можно как синтезировать DSK, так и только получить отчёт о корректности CRC или более развёрнутый отчёт (сколько раз встречались сектора, насколько успешно их удалось прочитать, были ли расхождения (многократные успешные чтения с совпадением CRC, но при этом с разными данным - такое бывает на 140ках)).
Отчёт о корректности без создания dsk важен для читалки: мы можем снимать образ в Eim3 (массивы интервалов времени - то, что снимают и флюкса и supercardpro), но при этом уже зная, что данные прочитались успешно.

Фактически, я тут честно тырил собственный код из RawEdit - программы для Мостов2, которые интерактивно работают со старыми eim. Тырить очень приятно, потому что rawedit - штука старая и хорошо вылизанная. Формально, читать образцовую дискету не сложно, но, в случае ошибок, этим алгоритмам есть где запутаться (Например: нашли поле адреса, за ним поле данных успешно прочиталось. Всё хорошо ? Нет. Возможно, нужное поле данных имеет повреждённый пролог, также повреждено и следующее поле адреса. А мы успешно прочитали поле данных другого сектора. Нужно было проверять расстояния между полями). Так что готовый код - это много готовых подсказок.

Для тестов сохранял из слоя 3 образы Eim, потом прогонял их через rawedit и через свеженаписанный 4 слой декодеров и сравнивал финальные dsk. Наловил несколько хитрых багов в новом коде (что-то вроде: что будет если аппартный индекс пройдёт строго между синхросимволом и прологом поля адреса или поля данных), но это всё быстро исправлялось. В самом rawedit ошибок вроде не нашлось :)

Код rawedit и "слоя4" не совпадают 1:1. RawEdit немного более сложен. Например, он очень подробно учитывает сигнал индекса (рисует его прямо над дампом дорожки), который для "слоя4" пока вообще не нужен. О некоторых особенностях дорожки "слой4" сообщает в лог и не хранит затем эту информацию, в то время как rawedit собирает подобную информацию и может, например, быстро гонять курсор между разными полями, экземплярами дорожки и т.д.

Слой 4 пока не закончен, есть только 840ка. Нужно ещё 140ку и PC-формат.

==

b) Собрал на плате RTC; всё таки убедился, что на плате неправильно подключено посадочное место для holder'а  батарейки (+/- перепутал). Вроде часики отзываются, надо будет батарейку воткнуть и погонять.

Собрал индикаторор читаемого трека: двухцветные светодиоды. Чтобы ровно запаять их все, привлёк супругу: у неё глазомер отличный и руки не дрожжат. Она смотрит сверху на диод и позиционирует его, я смотрю сбоку. Ей хорошо видно положение диода, а мне хорошо видна точка пайки. Так вдвоём всю линейку собрали довольно быстро.

Написал прикольную короткую демку и поддержку линейки в ui-server'е.
/*
Когда только начинал осваивать электронику, мечтал о переключателе гирлян для ёлки.
Первая конструкция в школьном радиокружке - простые бегущие (перемигивающиеся) огни.
Я мало понимал, как это работает, но увидел весь стек разработки: от простой схемы мультивибратора на бумаге
до законченного устройства. Две печатные платы: диодный мост+кондёр и сам мультивибратор с релюшкой на выходе. До сих пор люблю всякие бегающие огоньки :))
*/

Собрал интерфейс 140: семплер и силовые части. Но пока не проверял.

==

Дальше надо закончить слой 4 для 140ки и PC.

Проверить интерфейс 140ки и дописать управление этим приводом, включая всякие хитрые алгоритмы управления его головой.

И самое-самое: процедуру/библиотку автоопределения формата записи.
Декодеры L4 могут сообщать о том, похожа ли дорожка на известный им формат.
Также они сообщают, сколько секторов удалось вытащить при данном запросе и кумулятивно по всем попыткам.

Теперь нужно продумать decoders suites, как -то их описать в виде массива и вокруг этого выстроить перебор вариантов.
Комбинаций немало: (форматы 140+840+PC) x (скорости флопика 300/360) x (битрейты SD/HD для PC) x (таблицы ФАПЧ слоя2 - 5 штук) x (мелкая подстройка под скорость флопа: 0.96, 0.97, 0.98, 1.0, 1.02, 1.03, 1.04 - иногда внезапно это помогает, причём перебирать нужно не по порядку, выгоднее как-то так: 1.0, 0.97, 0.98, 0.96, 1.03, 1.02, 1.04...).

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

Можно накапливать долговременную статистику внутри устройства: какие suit'ы чаще всего успешно читали разные дорожки на разных приводах. И исходить из неё. Такой себе ИИ.

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

Данные не обязательно прогонять через весь стек для каждого формата: сперва слой 1 - универсальный для всех форматов. Потом слой 2 - отдельные настройки для 140кб, отдельные настройки для 840кб и PC/SD (т.е. можно для этих двух форматов не повторять вызов слоя 2, но это не всегда прокатит: небольшая поправка на то, что у 840ки битрейт немного сдвинут из-за вариантов кварцев, иногда заметно улучшает результат чтения), отдельные настройки для PC/HD. Но отдельные обращения к слою 2 в зависимости от скорости вращения флопика.

Кроме того у PC-совместимых может быть разное количество секторов даже в рамках одной плотности записи.
И разный размер сектора.

Также список должен будет как-то учитывать возможные расширения поддерживаемых форматов.

Поскольку, софт пишется как набор отдельных библиотек-слоёв, то где-то как-то это должно позволять заменой самого нижнего слоя (т.е. источника массива интервалов) использовать весь стек не только для декодирования данных с Моста 3, но и для офлайновой работы, в т.ч. с другими устройствами захвата.

99 Отредактировано Voldemar0 (14-01-2023 20:10)

Re: Мост # 3 - специализированный компьютер для чтения дискет

Тестирую 140ку, попутно вылизывая спектроанализатор и весь процесс работы с семплерами (много там всякого под водой).
Заодно заинтересовало время :

1) Только прогон 840ки (спектр по всем 160 трекам):
real    1m 29.62s
user    0m 1.14s
sys     0m 21.80s

2) Только прогон 140ки (спектр по всем 70 трекам (т.е. включая промежуточные фазы привода головы)):
real    0m 42.38s
user    0m 0.49s
sys     0m 9.58s

3) Прогоны обеих дисководов одновременно:
840:
real    1m 39.99s
user    0m 1.19s
sys     0m 20.82s

140:
real    0m 48.75s
user    0m 0.38s
sys     0m 8.36s


real - реальное время работы проги
user - время ЦПУ для работы программы
sys - время ЦПУ для работы операционки на нужды данной программы

Видно, что при параллельной работе прог время их работы только немного
возрастает, т.е. если прогнать тесты по отдельности, это потребует 2минуты 10секунд,
а в параллель - 1 минута 40секунд.

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

==

На 140ке прижим головки придавливаю немного пальцами - спектр прям на глазах стройнее становится :)
Любит у меня флопик это дело.

100

Re: Мост # 3 - специализированный компьютер для чтения дискет

А в чем смысл одновременной работы с двумя дисководами для снятия образов? Что это за ситуация, когда каждая секунда дорога? ;)
Я понимаю, это круто с технической точки зрения, но практическая польза близка к нулю, а устройство усложняет и удорожает.
Кстати а канал записи в нем вообще реализован?