Урок 4. Своя память в процессоре — и первая ошибка
В картинкахВ машине процессорного набора вся память — один примитив ram на 256 слов. В этом уроке на его место встаёт ваша RAM256x4. Игра запустится… и начнёт ошибаться: часть кнопок сработает не так, кристаллы будут гаснуть, не докатившись. Это не ошибка сборки — так и задумано. Причину найдём встроенным осциллографом, а починим в уроке 5.
4.1. Что стоит в машине сейчас и чем наша память отличается
Внутри GW-CPU память подключена так: адрес — младшие 8 бит команды ir0–ir7, данные для записи — аккумулятор acc0–acc3, прочитанное mq0–mq3 идёт в АЛУ, «пиши» WE = oST (команда ST), такт CPUCLK.
Примитив ram пишет в момент фронта такта, как триггер. У нашей памяти такта нет: она пишет, пока WE = 1 — это окно, а не мгновение. Значит, на WE нужно подать окно, когда адрес и данные уже спокойны. Сразу после фронта CPUCLK 0→1 процессор переходит к следующей команде — адрес меняется. Ко второй половине такта всё устоялось. Окно:
weRAM = oST · НЕ CPUCLK— «сейчас командаST, и идёт вторая половина такта».
4.2. Память при включении — «что попало»
Примитив ram при включении содержит нули. Защёлки — нет: каждая встаёт как придётся (в REAL — «ничего», оранжевое; в Fast — единицы). Так ведёт себя и настоящая память: компьютер при старте сам приводит в порядок то, что собирается читать.
Программа игры процессорного набора читает две ячейки раньше, чем записывает: LASTB и LASTK — какие кнопки были нажаты в прошлый раз. Остальные она сначала пишет. Поэтому в начало программы добавлены две команды:
reset: LD #0 ST LASTB ; своя память: ячейки, которые читаются до записи, — обнулить ST LASTKПрограмма целиком — файл game-myram.rom.json (311 команд).
4.3. Сборка
Шаг 1. Перенести чип в проект с машиной
Уроки 1–3 вы собирали в отдельном проекте. Чип переезжает файлом:
- В проекте уроков 1–3: в библиотеке в строке
RAM256x4— значок ⬇ (сохранить чип в файл). В файл попадут и все его детали:RAM16x4,WORD4,DLatchи вентили. - Открыть проект с машиной процессорного набора.
- В шапке библиотеки — значок ⬆ (загрузить чип) → выбрать файл.
- Если появится окно «built differently» — у вас эти вентили уже есть, только собраны иначе. Оставить предложенное Use mine → Import.
Шаг 2. Убрать примитив памяти
Внутри GW-CPU («Редактировать»):
| Элемент | Действие |
|---|---|
| Memory (RAM) RAM, выход которого = mq0 | удалить |
Метки на его ногах (ir0–ir7, acc0–acc3, mq0–mq3) удалять не нужно — на них встанет новая память.
Шаг 3. Своя память и окно записи
Что собираем. Инвертор такта, окно weRAM и RAM256x4 на тех же метках.
| Элемент | Нога | Направление | Метка |
|---|---|---|---|
| NOT | I0 | вход | CPUCLK |
| NOT | O0 | выход | nCLK |
| AND | I0 | вход | oST |
| AND | I1 | вход | nCLK |
| AND | O0 | выход | weRAM |
| RAM256x4 | A0 | вход | ir0 |
| RAM256x4 | A1 | вход | ir1 |
| RAM256x4 | A2 | вход | ir2 |
| RAM256x4 | A3 | вход | ir3 |
| RAM256x4 | A4 | вход | ir4 |
| RAM256x4 | A5 | вход | ir5 |
| RAM256x4 | A6 | вход | ir6 |
| RAM256x4 | A7 | вход | ir7 |
| RAM256x4 | D0 | вход | acc0 |
| RAM256x4 | D1 | вход | acc1 |
| RAM256x4 | D2 | вход | acc2 |
| RAM256x4 | D3 | вход | acc3 |
| RAM256x4 | WE | вход | weRAM |
| RAM256x4 | Q0 | выход | mq0 |
| RAM256x4 | Q1 | выход | mq1 |
| RAM256x4 | Q2 | выход | mq2 |
| RAM256x4 | Q3 | выход | mq3 |
Выйти из редактирования чипа с сохранением.
Шаг 4. Программа
ПЗУ (снаружи GW-CPU): ⚙ → ⬆ → файл game-myram.rom.json.
4.4. Запуск — и ошибка
Движок Fast, такт CPUCLK — MAX.
| Что делаешь | Что видишь |
|---|---|
| включить | часы 12:00 идут — процессор работает на своей памяти |
| держать A, потом P | нижняя левая рука, верхняя правая — верно |
| держать Q | ✗ нижняя левая рука вместо верхней левой |
| держать L | ✗ верхняя правая вместо нижней правой |
| START | ✗ кристалл появляется в начале трубы и гаснет |
Так и должно быть в этом уроке. Память собрана правильно, окно записи по смыслу правильное — а запись иногда уходит не в ту ячейку. Q портит ячейку позы, кристаллы — ячейки труб.
4.5. Ищем причину осциллографом
Осциллограф показывает сигналы по времени. Открыть — клавиша w.
- В поле add ввести и нажать
Enterпосле каждого:CPUCLK,ir0-7(шина адреса одной строкой),GW-CPU.oST,GW-CPU.weRAM. - В поле trig —
GW-CPU.weRAM=1,Enter. Как только окно записи откроется, картинка замрёт (FROZEN), событие — посередине. - Снова ловить — LIVE.
Как читать. Один столбик — один срез: одно вычисление симулятора на фронте такта. Это самая маленькая единица времени, какая у симулятора есть: всё, что попало в один срез, для него происходит одновременно, без «раньше» и «позже».
В подсвеченном срезе адрес только что сменился (13) — и в этот же срез открылось окно weRAM. В настоящем железе между этими событиями было бы мгновение: сначала новая команда устаканивается, потом открывается окно. В симуляторе они совпали. А на следующем фронте адрес уже перескакивает на следующую команду (02), и пока дешифратор гасит oST, окно ещё не закрыто — значение успевает записаться и туда.
Вывод: окно записи не должно открываться и закрываться на том же фронте, где меняется адрес. Как этого добиться, не замедляя процессор до бесконечности, — урок 5.
Вставка урока 4 (Cmd+I)
В режиме редактирования GW-CPU, после шагов 1–2.
# Урок 4 — своя память в процессоре (простое окно записи).# Вставка: Cmd+I В РЕЖИМЕ РЕДАКТИРОВАНИЯ чипа GW-CPU, после того как удалён примитив ram RAM (256×4).# Адрес — младшие 8 бит команды, данные — аккумулятор, прочитанное — в АЛУ, как у прежней памяти. # ---------- окно записи: команда ST, вторая половина такта ----------NOT(CPUCLK, nCLK)AND(oST, nCLK, weRAM) # ---------- память ----------RAM256x4(A0=ir0, A1=ir1, A2=ir2, A3=ir3, A4=ir4, A5=ir5, A6=ir6, A7=ir7, D0=acc0, D1=acc1, D2=acc2, D3=acc3, WE=weRAM, Q0=mq0, Q1=mq1, Q2=mq2, Q3=mq3)Не получается? Что-то не работает →