Arduino Nano 3.0 - эмулятор компьютера под управлением ОС CP/M

Тема в разделе "Глядите, что я сделал", создана пользователем FoxyLab, 23 мар 2017.

  1. FoxyLab

    FoxyLab Гик

    Добавил индикацию обращения к шине I2C (а так как кроме памяти там сейчас ничего не висит, то фактически обращения к ОЗУ) - светодиод, загорающийся при низком уровне линии SCL. Quick-and-dirty подход повесить светодиод через резистор 2 кОм не проканал совсем - не нашлось не одного модуля памяти на шине - слишком сильный pull-up оказался, через 4,7 кОм хоть и работало, но в 7407 есть свободные ноги, так что через повторитель получилось надежнее.
    Теперь "модуль" ОЗУ выглядит так:
    [​IMG]
     
    Igor68 нравится это.
  2. FoxyLab

    FoxyLab Гик

    Экран начальной загрузки на кинескопном ТВ:
    [​IMG]
     
    Igor68 и Un_ka нравится это.
  3. Un_ka

    Un_ka Гуру

    Интересно, ресурсов esp-8266 хватит, чтобы потянуть эмулятор без дополнений? Правда, там доступно только API.
     
  4. FoxyLab

    FoxyLab Гик

    80 мегагерц, 32 бита, 80 килобайт ОЗУ - с огрооомным запасом, и фрамки не нужны, но на таком железе IMHO нет челенджа в отличии от 8 бит на 16 мегагерцах с парой килобайт ОЗУ. А так то на них Спектрумы и Коммодоры эмулируют (https://zx-pk.ru/threads/31388-esp8266-zx-spectrum-emulator.html, https://github.com/aldolo69/esp8266_zxspectrum_emulator, https://blog.adafruit.com/2019/01/2...modore64-commodore-esp8266-epaper-hacksterio/)
     
    Un_ka нравится это.
  5. FoxyLab

    FoxyLab Гик

    Повозился с кэшами (для меня проектирование кэша - одна из самых увлекательных сторон этого проекта, такой себе косплей проектировщика CPU :) Теперь имеется кэш инструкций в 6 линий по 16 байт и кэш данных в 4 линии по 8 байт, для инструкций кэшируется только чтение, запись напрямую в память, для данных кэшируется и чтение, и запись, "грязный" флаг, все дела:) Кэш - LRU, но реализация похожа на FIFO, если промах - последние данные добавляются в хвост, голова выталкивается, если попадание - нужные данные обмениваются с хвостом. Кэширование заметно ускорило работу, особенно отзывчивость CP/M. Теперь время инициализации ОС от окончания загрузки до появления A> в FAST режиме (без прорисовки картинки) - менее 2 секунд.
    P. S. И недавно снятое (тогда кэш данных еще был однолинейный) видео с экрана кинескопного ТВ в винтажном стиле :)

     
    Последнее редактирование: 13 дек 2020
    Igor68 и Un_ka нравится это.
  6. FoxyLab

    FoxyLab Гик

    Я начал компаньон-проект по расширению графических возможностей своего "нанокомпьютера". Еще одна обычная Arduino Nano выступает в роли видеокарты, обеспечивающей вывод на ТВ монохромной картинки с разрешением 320 x 244 (как у Sega Genesis, формат 240p) ! Причем это не рисование линий в формате демки, это модуль с полноценной пиксельной видеопамятью - в качестве нее я использую SPI RAM 23K256. Как основной вариант я хочу сделать разделенный по времени доступ к этому чипу - во время 244 активных пиксельных линий им владеет видеопроцессор, а остальные 68 линий - память может юзать основной процессор. Ну а сейчас я просто для "proof-of-concept" реализовал управление через UART. Вот какую картинку выдает моя видеокарта после загрузки через UART в видеопамять - я сконвертировал в монохром скриншот из игры FoxyLand для Sega Genesis - картинка снята посредством тв-тюнера (я откопал в закромах свой старенький 609-й Бехолдер):
    [​IMG]
     
    timon и Igor68 нравится это.
  7. FoxyLab

    FoxyLab Гик

    "Нановидеокарта" позволила вывести 64 символа в строке (как у Коммодора), что позволит отказаться от виртуальных экранов (DIR проканает, ну а если уж какая-нибудь программа хочет больше - без переноса никак, сама себе злобная Буратина). Самый мозговыносящий эпизод был сотворить на ассемблере подпрограмму, выводящую символы шириной 5 бит в 40-байтной строке. Но во времена Спектрума-АОНа Байес на ассемблере был не проще :) Ну и проверить и при необходимости раскидать по этапам различные команды, чтобы этап уложился в одну строку - иначе на мгновение срывается синхронизация, некрасиво получается.
     
  8. Igor68

    Igor68 Гуру

    Давай образ "дискеты" обсудим. Вам не кажется, что это выходит за рамки CP/M-80 ?
     
    FoxyLab нравится это.
  9. FoxyLab

    FoxyLab Гик

    64 символа - это как раз для CP/M необходимо, иначе много мороки с переключением виртуальных экранов. И становится возможным эмулировать Dazzler - те же шахматы или "Жизнь" будут рисоваться графикой!
    Я использую стандартный CP/M-овский формат, но только первые дорожки не заняты системой, она грузится из отдельной области на карточке.
    P.S. А так "нановидеокарта" (Nano + 23K256 + 74HC00) - наверно, один из самых дешевых адаптеров, позволяющий выводить информацию с последовательного порта на экран ТВ в формате 64x25 символов или 320x224 точки.
    P.P.S. Освобождение основного процессора от обязаности ТВ-вывода позволит занять кэшами память, которая сейчас используется под видеобуфер.
     
    Последнее редактирование: 24 дек 2020
    Igor68 нравится это.
  10. FoxyLab

    FoxyLab Гик

    Добавил в прошивку "нановидеокарты" рисование линий Брезенхемом (на ассемблере) - так что теперь это поделие, наверно, один из немногих, если не единственный 2D-видеоускоритель на Arduino Nano ;)
    Экран, заполненный символами шрифта (снимок с ТВ-тюнера):
    [​IMG]
     
    Последнее редактирование: 25 дек 2020
    Un_ka и Igor68 нравится это.
  11. FoxyLab

    FoxyLab Гик

    Попиксельный и посимвольный скроллинг вверх и вниз силами моей "нановидеокарты" (снято с помощью ТВ-тюнера) - как оказалось, мой подход аналогичен Roller RAM в 8-битных компьютерах Amstrad PCW:


    P.S. На саму операцию скроллинга (безразлично, на пиксел или на символ) требуется время меньше периода строчной развертки, паузы между операциями добавлены для наглядности.
     
  12. FoxyLab

    FoxyLab Гик

    8-битный МК эмулирует 8-битный компьютер - это увлекательно, но эмуляция 32-битного RISC-V процессора и запуск Linux-программ в user mode на Arduino Nano - еще интереснее.

    riscv4nano project is currently in active development :)

    Пока я ограничился эмуляцией RV32I (прототип готов, осталось тестировать, там заморочек тоже хватает). Но gcc позволяет задать -march=rv32i -mabi=ilp32 и он сам уже будет эмулировать все остальные RISC-V-расширения.

    С памятью сложнее - если не использовать printf/scanf, а использовать варианты попроще, то небольшая C-программка вполне вмещается в 32 Кбайта SPI RAM-ки 23K256. А так - или "SD" RAM как в начале cpm4nano (с кэшированием должно шевелиться, и памяти будет много-много-много) или SRAM через I2C-размножители пинов (на али сейчас продается 256-килобайтная платка с IS62WV12816BLL).

    Линюксовые системные вызовы (syscalls) пока read(stdin)/write(stdout)/sbrk/exit.
     
    Последнее редактирование: 25 янв 2021
    Un_ka нравится это.
  13. Un_ka

    Un_ka Гуру

    Достойно броского заголовока Linux на Arduino.

    То есть работает?
     
  14. ZAZ-965

    ZAZ-965 Гуру

    Вряд ли Linux, скорее слой POSIX совместимости, как, например в NuttX.

    @FoxyLab, исходный код cpm4nano выкладывался\планируется выложить?
     
  15. FoxyLab

    FoxyLab Гик

    Для запуска ядра нужны в том числе атомарные операции, привилегированные регистры, таймер, реализация MMU. Принципиально это возможно, но все-таки слишком замороченно.
    Моя ближайшая цель - запуск скомпилированных gcc программ с обращениями к syscalls. Файловый ввод-вывод - пока консоль. Можно реализовать и обращения к файлам, read/write о файловой системе знать ничего и не должны, можно хоть FAT12 реализовать, когда-то на Спектруме у меня получилось сделать чтение/запись файлов на 720-килобайтные ай-би-эмовские дискеты.
    Ну и так как это все-таки МК - отображенные на память GPIO (пока я сделал гашение/зажигание светодиода при записи по адресу 0XFFFF0000).

    RV32I - я реализовал все команды, теперь буду тестировать, там ведь очень замороченный порядок битов в некоторых командах, по причине экономии мультиплексоров при хардверной реализации.
     
  16. FoxyLab

    FoxyLab Гик

    Есть статьи о запуске Linux на минимальных RISC-ах (в любом случае, RISC-V - это практически единственный способ подобраться к Linux на таком МК - есть еще и ARMv3, он поддерживался древним Дебианом, но там эмуляция посложнее, да и не так интересно, как RISC-V), но как я выше написал, там много нюансов.
    Поэтому, как Вы и написали, пока что - реализация RISC-V эмуляции и операционной прослойки.

    На GitHub была выложена одна из начальных версий (о чем и было расписано - что она начальная - где только можно, но все равно были утомительные вопросы), но я ее убрал. cpm4nano (как впрочем и все мои Arduino-проекты) жестко привязана к Arduino 1.6.6 (один очень интересный момент, который исчез уже в 1.6.13 - в 1.6.6 ассемблерные вставки в разных местах файла видят друг-друга), и код дополнительно увешан volatile __attribute__((used)) , а то компилятор уж шибко умный.
    Я все собирался написать на Хабре о cpm4nano, выложив актуальную версию. Но скорее всего, с risc4nano получится раньше.
     
    Igor68 нравится это.
  17. FoxyLab

    FoxyLab Гик

    Сделал вот такое MMU (теперь процессор может прыгать по 32-битному виртуальному адресному пространству как хочет, пока не закончатся фреймы физической памяти):

    Код (C++):
    //MMU constants
    const uint8_t PAGE_SHIFT = 12; //1^12 (4K) page size
    const uint32_t PAGE_MASK = ~(((uint32_t)(1 << PAGE_SHIFT))-1); //0xFFFFF000 mask to select page
    const uint8_t PAGE_NUM = 8; //pages number = frames number
    const uint8_t FRAME_INVALID_MASK = 0x01; //bit 0 - valid bit (0 - valid, 1 - invalid)

    volatile __attribute__((used)) uint32_t page_table[PAGE_NUM]; //page table (all bits 1 - free)

    //MMU init
    void mmu_init() {
      uint8_t tmp8;
      //page table init
      tmp8 = 0;
      while (tmp8 < PAGE_NUM) {
        page_table[tmp8] = FRAME_INVALID_MASK;  //frame invalid
        tmp8++;
      }
    }

    //translate logical_address to physical_address
    uint16_t mmu_translate(uint32_t logical_address) {
      uint16_t offset;
      uint32_t page;
      uint8_t tmp8;
      uint16_t physical_address;
      //logical address analyze
      offset = (uint16_t)(logical_address & ~(PAGE_MASK));
      page = (uint32_t)(logical_address & PAGE_MASK);
      //search in page table
      tmp8 = 0;
      while (tmp8 < PAGE_NUM) {
        if (page_table[tmp8] == page) break;
        tmp8++;
      }
      //return physical address
      if (tmp8 < PAGE_NUM) {
        physical_address = ((uint16_t)(tmp8) << PAGE_SHIFT) | offset;
        return physical_address;
      } else {
        //search free frame
        tmp8 = 0;
        while (tmp8 < PAGE_NUM) {
          if ((page_table[tmp8] & FRAME_INVALID_MASK)== FRAME_INVALID_MASK) break; //free frame found
          tmp8++;
        }
        if (tmp8 < PAGE_NUM) {
          page_table[tmp8] = page; //create page record
          physical_address = ((uint16_t)(tmp8) << PAGE_SHIFT) | offset;
          return physical_address;
        } else {    
          error_code = ERROR_NOT_ENOUGH_MEMORY; //not enough memory
          return 0; //return dummy address
        }
      }
    }
    P.S. Научное название такого подхода - inverted page table. 32 килобайта SPI RAM разбиты на 8 фреймов по 4 килобайта каждый. 32-битный виртуальный адрес содержит 20 бит номера виртуальной страницы и 12 бит смещения. Page table содержит запись для каждого фрейма - он либо помечен свободным, либо содержит номер соответствующей виртуальной страницы.
     
    Un_ka и Igor68 нравится это.
  18. Igor68

    Igor68 Гуру

    Это похоже уже выходит за рамки CPM, но всё равно интересно.
     
    FoxyLab нравится это.
  19. FoxyLab

    FoxyLab Гик

    Наконец то удалось зафиксировать (на ТВ-тюнере) все этапы прохождения широко известного в узких кругах теста 8080-го - "экзорциста" -
    [​IMG]
    Таким образом, мой эмулятор можно считать полностью верным.
     
    Igor68 нравится это.
  20. G1itchh

    G1itchh Нуб

    Не могли бы вы перезалить код для ардуины на гитхаб? Репозиторий исчез.