Использование C ++ для генерации байтового кода для файла ПЗУ для управления семисегментными дисплеями в Logisim - PullRequest
0 голосов
/ 07 марта 2020

Я слежу за сериалом Бена Итера на YouTube на Создание 8-битного макета компьютера. Я пытаюсь смоделировать его схему в Logisim , так как у меня нет ни макета, ни Arduino. В настоящее время я работаю над 8-разрядным десятичным дисплеем. Вот ссылка на текущее видео: BenEater :: Youtube

Я нахожусь в том месте, где он программирует свою EEPROM с помощью байт-кода через Arduino . Я использую его исходный код в качестве ссылки, которую можно найти здесь: BenEater :: Github


У меня возникла проблема с генерированием правильных байт-кодов для вождение набора 7-сегментных дисплеев в их правильные адреса для файла ПЗУ Logisim. Я использую C ++ для генерации байтовых кодов и печати шестнадцатеричных значений в текстовый файл.

Я не уверен, откуда возникла проблема, но я хотел бы знать, генерирует ли мой C ++ ту же последовательность байтов, что и код Бена Итера, для его Arduino для программирования его EEPROM? Я пытаюсь сузить эту ошибку настолько, насколько смогу. Сначала я хочу проверить, связано ли это с C ++! Поэтому основное внимание здесь уделяется сравнению с кодом Бена на его github и моей реализацией его на C ++.

Некоторые другие связанные вопросы и проблемы: Если мой код C ++ генерирует ту же последовательность байтов, то где еще я могу искать, чтобы устранить эту проблему? Может ли быть так, что я пишу это в текстовый файл вместо двоичного? Может ли это быть кодировка текстовых редакторов и возврат строк и т. Д. c? Может ли это быть проблемой с Logisim? Если я копирую байты из текстового файла, возвращает ли строка или eol играет роль в смещении байтовых адресов?


Вот мой код C ++, который эмулирует 11-битную адресуемую EEPROM размером 2 КБ, и алгоритмы для генерации байтового кода для 7-сегментного дисплея. Я записываю его в текстовый файл и пытаюсь скопировать шестнадцатеричные значения в модуль ROM Logisim. В Logisim модуль ПЗУ имеет ширину бита адреса 11 и ширину бита данных 8.
#include <array>
#include <bitset>
#include <iostream>
#include <iomanip>
#include <fstream>

constexpr unsigned ROWS = 128;
constexpr unsigned COLS = 16;

std::array<std::bitset<8>, ROWS*COLS> rom_file = {0x00};

// Show Rom File on the console
void showRomFile() {
    for (int row = 0; row < ROWS; row++) {
        std::cout << std::setw(2) << std::setfill('0') << row << "0: ";
        for (int col = 0; col < COLS; col++) {
            if (col % 4 == 0) std::cout << " ";
            std::cout << std::setw(2) << std::setfill('0') << std::hex 
                      << rom_file[COLS*row + col].to_ulong() << " ";
        }
        std::cout << std::endl;
    }
}

// Print Rom File to a Text File in single byte format.
void printRomFile() {
    std::fstream file;
    file.open("display.txt", std::ios::out);

    for (auto b : rom_file)
        file << std::setw(2) << std::setfill('0') << std::hex << b.to_ulong() << " ";
    /*for (int row = 0; row < ROWS; row++) {
        for (int col = 0; col < COLS; col++) {
            //if (col % 4 == 0) file << " ";
            file << std::setw(2) << std::setfill('0') << std::hex
                << rom_file[COLS*row + col].to_ulong() << " ";
        }
        //file << std::endl;
    }*/
    file.close();
}

int main() {
   // Bit patterns for 7 segment display of the digits 0...9
   std::bitset<8> digits[] = { 0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b };

   // unsigned
   for (int val = 0; val <= 255; val++) {
       rom_file[val] = digits[val % 10];
       rom_file[val + 256] = digits[(val / 10) % 10];
       rom_file[val + 512] = digits[(val / 100) % 10];
       rom_file[val + 768] = 0;
   }

   // signed twos complement
   for (int val = -128; val <= 127; val++) {
       rom_file[(unsigned)val + 1024] = digits[abs(val) % 10];
       rom_file[(unsigned)val + 1280] = digits[abs(val / 10) % 10];
       rom_file[(unsigned)val + 1536] = digits[abs(val / 100) % 10];

       if (val < 0)
           rom_file[(unsigned)val + 1792] = 0x01;
       else
           rom_file[(unsigned)val + 1792] = 0x00;
   }

   showRomFile();
   printRomFile();

   /* 
   // unsigned
   for (int val = 0; val <= 255; val++)
       rom_file[val] = digits[val % 10];

   for (int val = 0; val <= 255; val++)
       rom_file[val+256] = digits[(val / 10) % 10];

   for (int val = 0; val <= 255; val++)
       rom_file[val+512] = digits[(val / 100) % 10];

   for (int val = 0; val <= 255; val++)
       rom_file[val+768] = 0;
   */

   // signed twos complement
   /*for (int val = -128; val <= 127; val++)
       rom_file[static_cast<unsigned>(val) + 1024] = digits[std::abs(val) % 10];

   for (int val = -128; val <= 127; val++)
       rom_file[static_cast<unsigned>(val) + 1280] = digits[std::abs(val/10) % 10];

   for (int val = -128; val <= 127; val++)
       rom_file[static_cast<unsigned>(val) + 1536] = digits[std::abs(val/100) % 10];

   for (int val = -128; val <= 127; val++) {
       if (val < 0)
           rom_file[static_cast<unsigned>(val) + 1792] = 0x01;
       else
           rom_file[static_cast<unsigned>(val) + 1792] = 0;
   }

   showRomFile()
   printRomFile()

   */

    return 0;
}

Если вы посмотрите мой код и даже закомментированные разделы, вы увидите что я попытался изменить интервал, и новые строки и т. д. c, чтобы увидеть, если они вызывают проблемы ... Первоначально я проходил для l oop для каждого случая, но для этого вопроса я объединил все 4 раздела в их соответствующие циклы для подписанных и неподписанных разделов. Идея состоит в том, что байтовые коды без знака должны быть в нижней половине или 1 st 1 КБ файла ПЗУ, где байтовые коды со знаком должны быть в верхней половине или 2 nd 1 КБ.


Вот соответствующая часть его кода для программирования EEPROM через его Arduino :

Код Бена Эотера:

void setup() {
  // put your setup code here, to run once:
  pinMode(SHIFT_DATA, OUTPUT);
  pinMode(SHIFT_CLK, OUTPUT);
  pinMode(SHIFT_LATCH, OUTPUT);
  digitalWrite(WRITE_EN, HIGH);
  pinMode(WRITE_EN, OUTPUT);
  Serial.begin(57600);

  // Bit patterns for the digits 0..9
  byte digits[] = { 0x7e, 0x30, 0x6d, 0x79, 0x33, 0x5b, 0x5f, 0x70, 0x7f, 0x7b };

  Serial.println("Programming ones place");
  for (int value = 0; value <= 255; value += 1) {
    writeEEPROM(value, digits[value % 10]);
  }
  Serial.println("Programming tens place");
  for (int value = 0; value <= 255; value += 1) {
    writeEEPROM(value + 256, digits[(value / 10) % 10]);
  }
  Serial.println("Programming hundreds place");
  for (int value = 0; value <= 255; value += 1) {
    writeEEPROM(value + 512, digits[(value / 100) % 10]);
  }
  Serial.println("Programming sign");
  for (int value = 0; value <= 255; value += 1) {
    writeEEPROM(value + 768, 0);
  }

  Serial.println("Programming ones place (twos complement)");
  for (int value = -128; value <= 127; value += 1) {
    writeEEPROM((byte)value + 1024, digits[abs(value) % 10]);
  }
  Serial.println("Programming tens place (twos complement)");
  for (int value = -128; value <= 127; value += 1) {
    writeEEPROM((byte)value + 1280, digits[abs(value / 10) % 10]);
  }
  Serial.println("Programming hundreds place (twos complement)");
  for (int value = -128; value <= 127; value += 1) {
    writeEEPROM((byte)value + 1536, digits[abs(value / 100) % 10]);
  }
  Serial.println("Programming sign (twos complement)");
  for (int value = -128; value <= 127; value += 1) {
    if (value < 0) {
      writeEEPROM((byte)value + 1792, 0x01);
    } else {
      writeEEPROM((byte)value + 1792, 0);
    }
  }

  // Read and print out the contents of the EERPROM
  Serial.println("Reading EEPROM");
  printContents();
}

Это то, что он использует для создания битовых комбинаций для установки определенных c сегментов дисплея на основе 11-битного адреса, который будет передан в EEPROM . Структура его 11-битного адреса выглядит следующим образом:

Нижние восемь битов адреса будут иметь значения [0,255] в режиме unsigned или [-128,127] если в режиме signed используется twos дополнить .

bits [0..7] = value part of the address
bits [8..9] = digit placement
bit  [10]   = signed/unsigned flag 

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

Например:

Если мы передадим 101 в качестве адреса в EEPROM , он получит значение 01011011 в двоичном формате, где значение (0x5b) было написано по этому адресу. Относительно его схемы эта битовая комбинация будет подсвечивать 5 на 7-сегментном дисплее его макета.


У него четыре из этих дисплеев подключены параллельно, и он использует 555-Timer для генерации тактового импульса, который будет запускать 2-бит флип-флоп счетчик . Этот 2-битный счетчик используется слева на два бита после восьмибитной части адреса. Эти два бита будут определять, какой из четырех 7-сегментных дисплеев будет активным, в зависимости от расположения di git в пределах значения. Он также использует двухбитный декодер для управления, когда каждый указанный сегмент c должен работать. Он связывает это с анодами своих 7-сегментных дисплеев. Теперь в Logisim есть все сегментирующие выводы, но нет анода или диода для active-high или active-low поскольку они есть как часть страницы свойств объектов. В проекте My Logisim я не могу подключить ie линейный декодер 2-4 к анодам из 7 сегментов, поэтому я использовал разделители проводов, чтобы установить 8 сохраненных битов, затем я использовал ВОСЕМЬ 2-4 демультиплексоров для имитации того же самого process.


Ниже приведен пример генерации кратного значения di git:

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

Value Address[0..8]: `01111011` - `0x07B`              
// signed[0]
Stages:       Stored Byte-Output:   Display Array:   Full Address
Counter[00]:  01111001 - 0x79       [ ][ ][ ][3]     0 00 01111011 - 0x07B
Counter[01]:  01101101 - 0x6D       [ ][ ][2][ ]     0 01 01111011 - 0x17B
Counter[10]:  00110000 - 0x30       [ ][1][ ][ ]     0 10 01111011 - 0x27B
Counter[11]:  00000000 - 0x00       [ ][ ][ ][ ]     0 11 01111011 - 0x37B
// signed[1] 
Counter[00]:  01111001 - 0x79       [ ][ ][ ][3]     1 00 01111011 - 0x47B
Counter[01]:  01101101 - 0x6D       [ ][ ][2][ ]     1 01 01111011 - 0x57B
Counter[10]:  00110000 - 0x30       [ ][1][ ][ ]     1 10 01111011 - 0x67B
Counter[11]:  00000000 - 0x00       [ ][ ][ ][ ]     1 11 01111011 - 0x77B

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

7-Bit Segment:Logisim

Это нижняя и правая часть схемы это не связано с cpu-bus частью.


Это прекрасно работает и должно делать то же самое для всех значений без знака из [0-255]. Когда в адресе включен бит signed, если значение равно [0,127], все должно работать так же, как счетчики unsigned. Когда значение равно [-128,-1], расположение di git должно быть таким же, однако в крайнем левом углу di git должно отображаться [-], которое является средним сегментом, и его двоичное кодирование равно 0x01.

Теперь, прежде чем я начну работать со значениями signed. У меня проблема в unsigned. Если я введу десятичное значение 127 или 01111111, все будет работать как надо, но как только я запускаю бит 128 со значением адреса 10000000, я начинаю сталкиваться с проблемами. Я получаю 128 от первых трех тактовых импульсов, но на четвертом, где это идет не так! Я дам таблицу, чтобы показать, что происходит в Logisim:

Value Address[0..8]: `10000000` - `0x080`              
// signed[0]
Stages:       Stored Byte-Output:   Display Array:   Full Address
Counter[00]:  01111111 - 0x80       [ ][ ][ ][8]     0 00 10000000 - 0x080
Counter[01]:  01101101 - 0x6D       [ ][ ][2][ ]     0 01 10000000 - 0x180
Counter[10]:  00110000 - 0x30       [ ][1][ ][ ]     0 10 10000000 - 0x280
Counter[11]:  01111111 - 0x7f       [8][ ][ ][ ]     0 11 10000000 - 0x380
// the above should be:
Counter[11]:  00000000 - 0x00       [ ][ ][ ][ ]     0 11 10000000 - 0x380

// signed[1]  should be -1
Counter[00]:  01101101 - 0x6D       [ ][ ][ ][2]     1 00 10000000 - 0x480
// should be:
Counter[00]:  00110000 - 0x30       [ ][ ][ ][1]     1 00 10000000 - 0x480

Counter[01]:  00110000 - 0x30       [ ][ ][1][ ]     1 01 10000000 - 0x580
// should be:
Counter[01]:  00000001 - 0x01       [ ][ ][-][ ]     1 01 10000000 - 0x580

Counter[10]:  00000001 - 0x01       [ ][-][ ][ ]     1 10 10000000 - 0x680
// should be:
Counter[10]:  00000000 - 0x00       [ ][ ][ ][ ]     1 10 10000000 - 0x680

Counter[11]:  01111111 - 0x7f       [8][ ][ ][ ]     1 11 10000000 - 0x780
// the above should be:
Counter[11]:  00000000 - 0x00       [ ][ ][ ][ ]     1 11 10000000 - 0x780

Как вы видите, мне кажется, что почему-то я отключен на один байт-адрес и я даже не знаю, является ли это единственной проблемой или ошибкой.

Я не знаю, что является причиной этой ошибки. Я не уверен, находится ли это в коде C ++ или нет, если у меня есть неуместное соединение на проводке, которое не появляется так, потому что я могу генерировать каждую ди git [0,9] ... Я не Не знаю, относится ли это к тому, как текстовые файлы сохраняются, копируются и вставляются, я даже не уверен, является ли это One Off Bug или нет, но это мое текущее подозрение ...

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

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

...