Оглавление
- Дополнение пинов
- Инструкции RET ccc, RET
- Инструкция POP
- Инструкции PCHL, SPHL, DI и EI
- Инструкция JMP ccc
- Инструкции OUT, IN: работа с портами
- Инструкция XTHL
- Инструкция XCHG
- Инструкция CALL ccc
- Инструкция PUSH
- Инструкции АЛУ с непосредственным операндом
- Инструкция RST
§ Дополнение пинов
В этой главе потребуется писать и читать в порты, поэтому мне потребуется добавить некоторые новые пины.1module KR580VM80ALite 2( 3 input clock, 4 input reset_n, 5 input ce, 6 output m0, 7 output [15:0] address, 8 output reg [ 7:0] port, // Добавлено: Номер порта от 0 до 255 9 input [ 7:0] in, 10 input [ 7:0] port_in, // Добавлено: Входящие данные от порта 11 output reg [ 7:0] out, // Используется также для записи в порт 12 output reg we, 13 output reg port_we, // Добавлено: Разрешение записи в порт 14 output reg iff1 // Добавлено: Разрешение или отключение прерываний 15);В Радио86 не реализованы прерывания как таковые, потому DI/EI инструкции выведены на пищалку и управляют звуком. Ввиду невозможности точно рассчитать такты из-за постоянной остановки процессора видеоконтроллером, звук получается "не очень", и постоянно хрипит.
§ Инструкции RET ccc, RET
Возврат из подпрограммы. С вершины стека берется значение и записывается в PC в том случае, если выполнено условие, выполняется за 11Т. В другом случае, пропуск инструкции, выполняется за 5Т. Это выход из подпрограммы по условию. Всего условий в процессоре предусмотрено восемь: NZ, Z, NC, C, PO, PE, P, M. В самом деле, условий всего лишь 4, просто на каждое дается либо положительный, либо отрицательный ответ.Например, условие JNZ означает, что выполняться будет тогда, когда ZF=0, условие JZ значит, что выполняться будет только если ZF=1. Всего проверяются флаги: ZF, CF, PF и SF. К примеру, условие "JP" значит что если SF=0, то выполнить переход к метке. Для "JM" означает что если SF=1, то выполнить.
Создам провод на 4 бита, где в каждом бите будет проверяемый флаг.
1wire [3:0] cond = {psw[SF], psw[PF], psw[CF], psw[ZF]};Здесь бит 0 проверяет флаг ZF, бит 3 — флаг SF. Рассмотрим подробнее код микрооперации.
18'b11xx_x000, 28'b1100_1001: case (t) 3 4 0: begin d <= sp + 2; w <= ccc; n <= 3; sw <= 1; cp <= sp; end 5 1: begin d[ 7:0] <= in; cp <= cpn; end 6 2: begin d[15:8] <= in; sw <= 0; end 7 4: begin t <= ccc ? 5 : 0; end 8 10: begin t <= 0; pc <= d; end 9 10endcaseЗдесь объединены два вида RET, условный (
11xx_x000
) и безусловный опкод (1100_1001
), то есть просто RET. Видно, что появился некий провод ccc
:1wire ccc = (cond[ opc[5:4] ] == opc[3]) || (opc == 8'hC9) || (opc == 8'hCD);В зависимости от кода условий, которое хранится в op[5:3], будет выбрано решение. Сначала выбираем проверяемый флаг из
opc[5:4]
, через мультиплексор cond[opc[5:4]]
смотрим его значение и сравниваем с условием opc[3]
. Если совпадает, то ccc=1
. Помимо условного перехода, здесь ccc=1
может быть на некоторых инструкциях, это C9=RET
и CD=CALL
.Алгоритм.
- Такт 0. В d записываем новое значение SP+2, сдвиг стека (n=3 это SP), выбираем память cp, указатель на вершину стека и если условие выполняется, то тогда в регистр SP будет записано SP+2, но в противном случае, ничего не будет сделано
- Такт 1. Читается младший байт из стека (адрес возврата)
- Такт 2. Читается старший байт из стека
- Такт 4. Если условие выполнено, то на 10-м такте в регистр PC будет записано прочтенное значение из стека, а иначе просто перейдет к следующей инструкции.
§ Инструкция POP
Чтение слова из вершины стека. Время исполнения 11Т.Из стека можно прочесть только в 4 регистра, а именно
BC, DE, HL, AF
. Последний обрабатывается особым образом. Дело в том, что регистровая пара AF
состоит из двух регистров: в старшей части записан аккумулятор A, в младшей регистр PSW, или регистр флагов.18'b11xx_0001: case (t) 2 3 0: begin d <= sp + 2; w <= 1; n <= 3; sw <= 1; cp <= sp; end 4 1: begin d[ 7:0] <= in; cp <= cpn; end 5 2: begin d[15:8] <= in; sw <= 0; n <= opc[5:4]; w <= opc[5:4] != 3; end 6 3: begin if (opc[5:4] == 3) begin d[7:0] <= d[15:8]; psw <= d[7:0]; b <= 1; n <= 7; end end 7 10: begin t <= 0; end 8 9endcaseАлгоритм.
- Такт 0. Запись в SP нового значения SP+2, сигналы аналогичны тем же, что и в RET
- Такт 1. Чтение младшего байта
- Такт 2. Чтение старшего байта. Отключаем указатель памяти cp (sw=0), и пишется результат в 16-битный регистр (n) только в том случае, если это не AF
- Такт 3. Если регистровая пара является AF, то в этом случае из старшего байта d переносится в младший для того, чтобы была возможность оттуда записать в регистр A (b=1, n=7), а в PSW записывается то, что было в младшем байте d.
§ Инструкции PCHL, SPHL, DI и EI
Это довольно простые инструкции, поэтому я объединил их в одном параграфе. PCHL записывает HL в программный счетчик PC (PC = HL), SPHL записывает в SP (SP = HL), DI и EI отключают и включают прерывания. Ранее я упоминал, что прерывания в процессоре не реализованы, потому они тут используются для "бипера", генератора звуковых сигналов.Реализация инструкции PCHL (5 тактов):
18'b1110_1001: case (t) 2 4: begin pc <= hl; t <= 0; end 3endcaseРеализация инструкции SPHL (5 тактов):
18'b1111_1001: case (t) 2 0: begin d <= hl; w <= 1; n <= 3; end 3 4: begin t <= 0; end 4endcaseИ реализация инструкции DI и EI (4 такта):
18'b1111_x011: case (t) 2 3: begin t <= 0; iff1 <= opc[3]; end 3endcaseДумаю, что код достаточно очевиден и в данном случае комментарии излишни.
§ Инструкция JMP ccc
Выполняется условный или безусловный переход по абсолютному адресу (16 бит). Вне зависимости, выполнилось ли условие или нет, эта инструкция всегда выполняется за 10 тактов.18'b11xx_x010, 28'b1100_0011: case (t) 3 4 1: begin cp[ 7:0] <= in; pc <= pcn; end 5 2: begin cp[15:8] <= in; pc <= pcn; end 6 9: begin t <= 0; if (ccc || opc[0]) pc <= cp; end 7 8endcaseВначале в регистр
cp
считывается 16-битный адрес, в любом случае он считывается, и на такте #9 выполняется загрузка cp в pc либо по условию, либо безусловно (опкод C3).§ Инструкции OUT, IN: работа с портами
На самом деле, в Радио86 портов тоже нет, но процессор все-таки умеет с ними работать, так что можно и добавить такую возможность. OUT отправляет в порт значение из аккумулятора, IN же наоборот, читает из порта в аккумулятор. При этом, флаги никак не меняются. Инструкции выполняются за 10Т.Реализация OUT.
18'b1101_0011: case (t) 2 3 1: begin port <= in; port_we <= 1; out <= a; pc <= pcn; end 4 9: begin t <= 0; end 5 6endcaseПишется номер порта из непосредственного операнда, а также пишутся данные (out) и устанавливается сигнал port_we=1. Следует обязательно добавить сброс port_we на каждом такте.
1port_we <= 0;Я этот код занес вне области исполнения микрокодов. С реализацией IN все так же несложно.
18'b1101_1011: case (t) 2 3 1: begin port <= in; pc <= pcn; end 4 2: begin b <= 1; n <= 7; d <= port_in; end 5 9: begin t <= 0; end 6 7endcaseТочно так же устанавливается номер порта, после чего считывается оттуда значение и записывается в регистр A (n=7). Определенного стробирующего такта не отсылается, то есть, предполагаем что при чтении из порта, ничего не защелкивается.
§ Инструкция XTHL
Обменивает вершину стека с регистровой парой HL. Выполняется за 18Т. По праву, можно назвать эту инструкцию самой медленно выполняющейся из всех. Она и достаточно сложна и требует 2 чтения и 2 записи в память.18'b1110_0011: case (t) 2 3 0: begin sw <= 1; cp <= sp; end 4 1: begin d[ 7:0] <= in; cp <= cpn; end 5 2: begin d[15:8] <= in; w <= 1; n <= 2; cp <= hl; end 6 3: begin we <= 1; out <= cp[7:0]; d[7:0] <= cp[15:8]; cp <= sp; end 7 4: begin we <= 1; out <= d[7:0]; cp <= cpn; end 8 17: begin sw <= 0; t <= 0; end 9 10endcaseАлгоритм.
- Такт 0. Ставится указатель в памяти на вершину стека
- Такт 1. Читается младший байт из стека
- Такт 2. Читается старший байт из стека и пишется результат в регистр HL, и старый HL временно сохраняется в CP
- Такт 3. Пишется в вершину стека младший байт бывшего ранее HL, а старший байт сохраняется временно в регистр d, восстанавливается указатель вершины стека в CP
- Такт 4. Пишется старший байт в вершину стека
§ Инструкция XCHG
Обмен регистровых пар DE и HL. Время выполнения — 4Т.18'b1110_1011: case (t) 2 3 0: begin d <= de; n <= 2; w <= 1; cp <= hl; end 4 1: begin d <= cp; n <= 1; w <= 1; end 5 3: begin t <= 0; end 6 7endcaseКак и в случае с XTHL, я использую для временного хранения регистр CP. На такте #0 в регистр HL пишется значение DE, на такте #1 в регистр DE пишется то, что ранее было в HL.
§ Инструкция CALL ccc
Условный вызов процедуры. Время выполнения либо 11Т, если вызов не произошел, или 17Т, если переход был выполнен. У инструкции есть два варианта исполнения — условный и безусловный. Безусловный вариант имеет опкод CDh и выполняется всегда, то есть в ccc=1, если opc=CDh.18'b11xx_x100, 28'b1100_1101: case (t) 3 4 1: begin d[ 7:0] <= in; pc <= pcn; end 5 2: begin d[15:8] <= in; pc <= pcn; end 6 3: begin we <= ccc; out <= pc[ 7:0]; sw <= 1; cp <= sp - 2; end 7 4: begin we <= ccc; out <= pc[15:8]; cp <= cpn; end 8 5: begin if (ccc) pc <= d[15:0]; end 9 6: begin w <= ccc; d <= sp - 2; n <= 3; end 10 10: begin t <= ccc ? 11 : 0; end 11 16: begin t <= 0; end 12 13endcaseАлгоритм.
- Такт 1. Считывание младшего байта адреса перехода
- Такт 2. Считывание старшего байта адреса перехода
- Такт 3. Запись в память младшей части PC (или PCL) в стек, но только если условие выполнилось, иначе ничего не пишется
- Такт 4. Аналогично, запись PCH (старшей части PC) в стек, при выполнении условия
- Такт 5. Если условие выполнилось, то тогда занести в PC прочитанное значение адреса
- Такт 6. Запись в регистр SP (n=3) нового значения SP-2, но только если условие выполнено
- Такт 10. Если переход в процедуру был, то продолжить отсчитывать такты, иначе перейти к следующей инструкции (это вариант выполнения инструкции за 11Т)
§ Инструкция PUSH
Запись в стек регистровой пары BC, DE, HL или AF. Выполнение за 11Т.18'b11xx_0101: case (t) 2 3 0: begin d <= sp - 2; w <= 1; n <= 3; sw <= 1; cp <= sp - 2; end 4 1: begin d <= opc[5:4] == 2'b11 ? {a, (psw & 8'b11010101) | 2'b10} : r16; end 5 2: begin we <= 1; out <= d[ 7:0]; end 6 3: begin we <= 1; out <= d[15:8]; cp <= cpn; end 7 10: begin sw <= 0; t <= 0; end 8 9endcaseАлгоритм.
- Такт 0. В регистр SP (n=3) пишется (w=1) новое значение SP-2, и также устанавливается адрес памяти тоже CP = SP-2. Туда будут писаться данные.
- Такт 1. Выбор тех данных которые будут писаться в стек. Если в opc[5:4] указана 3-я регистровая пара, то это AF, иначе регистры BC, DE или HL
- Такт 2. Запись в память младшего байта регистровой пары
- Такт 3. Запись в память старшего байта регистровой пары
- Такт 10. Отключение от указателя памяти CP и переход к исполнению следующей инструкции
(psw & 8'b11010101) | 2'b10
, что позволяет удалить из PSW биты номер 3,5 и установить бит 1 в единицу, поскольку что бы ни было там записано, но в память в этих битах должны писаться именно эти значения.§ Инструкции АЛУ с непосредственным операндом
Аналогично предыдущим АЛУ инструкциям, они работают с двумя операндами, с операндом А (слева) и непосредственным операндом (справа), который идет сразу за опкодом. Расположение этих инструкции не случайно так сделано, что младшие три бита опкода равны110b
, поскольку позволяет сделать чтение из памяти без всяких дополнительных мультиплексоров.18'b11xx_x110: case (t) 2 3 1: begin d <= alur; pc <= pcn; b <= (opc[5:3] != CMP); n <= 7; psw <= aluf; end 4 6: begin t <= 0; end 5 6endcaseВместо выбора из памяти по адресу HL, из памяти теперь выбирается операнд по адресу PC. Соответственно, добавляется PC+1, и результат пишется в регистр A (кроме CMP инструкции), и в PSW регистр.
§ Инструкция RST
Вызов прерывания, который работает как вызов процедуры по заранее определенному адресу. Например RST 7 вызывает процедуру по адресу 7*8 = 56 в памяти. RST 1 вызывает по адресу 8 и так далее. Всего таких адресов восемь. Выполняется за 11Т.18'b11xx_x111: case (t) 2 3 1: begin we <= 1; d <= sp - 2; n <= 3; w <= 1; cp <= sp - 2; sw <= 1; out <= pc[7:0]; end 4 2: begin we <= 1; out <= pc[15:8]; cp <= cpn; pc <= {opc[5:3], 3'b000}; end 5 10: begin sw <= 0; t <= 0; end 6 7endcaseАлгоритм.
- Такт 0. Уменьшение SP=SP-2, выбор CP=SP-2 для записи туда адреса возврата и тут же, сохранение туда младшего байта PCL
- Такт 1. Сохранение в стек старшего байта PCH и запись в PC вычисленного адреса из номера опкода
Материалы к статье. Код процессора