Ну а CPC обновляется на аппаратном уровне, в зависимости от состояния разрядов 7 и 8 PSW. Также обновляется и CPSW.
Вид для печати
Да, все так PC и CPSW обновляются всегда, кроме случаев когда:
1. PSW[8]=1, PSW[7]=1
2. Кроме случаев работы с константой (сделано специально для удержания PC и CPSW в обработчике прерывания HALT).
3. Также есть отдельный случай влияющий на копирование PC1->PC, но я с ним пока не разбирался.
- - - Добавлено - - -
Продолжение банкета:
RSEL:
Код://======================================================================
//
// Команда RSEL (000020) (HALT)
//
//======================================================================
0x05: ACC=ACC IO_RD, IO_IN, IO_SEL // Инициировать цикл чтения безадресного регистра в регистр BRD
//---------------------------------------------------------------------- (совмещено с MFUS, и частично с RTI, RTT)
0x27: WAIT_BRD // Ожидание готовности чтения BRD
R0=BRD PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
MFUS:
Код://======================================================================
//
// Команда MFUS (000021) (HALT)
//
//======================================================================
0x05: RA=R5 IO_RD, IO_IN, IO_ALT // Инициировать альтернативный цикл чтения шины в регистр BRD
// Отличие от обычного цикла в том, что вывoд SEL=~PSW[8]
R5=R5+2
//---------------------------------------------------------------------- (совмещено с RSEL, и частично с RTI, RTT)
0x27: WAIT_BRD // Ожидание готовности чтения BRD
R0=BRD PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
MTUS:
Код://======================================================================
//
// Команда MTUS (000031) (HALT)
//
//======================================================================
0x05: RA=R5=R5-2 IO_WR, IO_ALT // Инициировать альтернативный цикл записи BRD на шину (SEL=~PSW[8])
//----------------------------------------------------------------------
0x27: BRD=R0 PLI_REQ // Инициилизировать BRD и продолжить цикл записи
// Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
WCPC:
Код://======================================================================
//
// Команда WCPC (000032-000033) (HALT)
//
//======================================================================
0x05: PC=R0 PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
WCPS:
- - - Добавлено - - -Код://======================================================================
//
// Команда WCPS (000034-000037) (HALT)
//
//======================================================================
0x05: CPSW=R0 PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
RCPC:
Код://======================================================================
//
// Команда RCPC (000022-000023) (HALT)
//
//======================================================================
0x05: R0=PC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
RCPS:
- - - Добавлено - - -Код://======================================================================
//
// Команда RCPS (000024-000027) (HALT)
//
//======================================================================
0x05: R0=CPSW PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
MARK:
- - - Добавлено - - -Код://======================================================================
//
// Команда MARK (0063NN)
//
//======================================================================
0x05: ACC=PC1+((IR&0x003F)*2)
//----------------------------------------------------------------------
0x35: R6=ACC
//----------------------------------------------------------------------
0x09: PC1=PC2=R5
//----------------------------------------------------------------------
0x31: RA=R6 IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
R6=R6+2
//----------------------------------------------------------------------
0x19: WAIT_BRD // Ожидание готовности чтения BRD
R5=BRD PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
CLx:
Код://======================================================================
//
// Команда CLx (000240-000257)
//
//======================================================================
0x05: ACC=IR&0x000F // Совмещено с SEx
//----------------------------------------------------------------------
0x27: PSW=PSW&~ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
SEx:
- - - Добавлено - - -Код://======================================================================
//
// Команда SEx (000260-000277)
//
//======================================================================
0x05: ACC=IR&0x000F // Совмещено с CLx
//----------------------------------------------------------------------
0x27: PSW=PSW|ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
BRA, Bcc:
Код://======================================================================
//
// Команда BRA, Bcc (000400-003777)
// (100000-103777)
//
//======================================================================
0x04: // На входе уже проверенные условия (BRA), сделанные во время команды выборки кода инструкции (0x01)
if (BRA=1) // Если BRA=1 (условия совпали)
PC1=PC2=PC1+SIGNEXT((IR&0x00FF)<<1) PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
else // Иначе
ACC=ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
Одно из самых таинственных действий процессора 1801ВМ2, скрытое под покровами микрокода - это выборка инструкции и обработка прерываний.
Выборка иструкции:
Код://======================================================================
//
// Пустая команда (не используется?)
//
//======================================================================
0x00: ACC=ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
//======================================================================
//
// Команда выборки некэшированной инструкции
//
// Входные данные: PC1 - указывает на адрес инструкции
//
//======================================================================
0x21: if (RI=001) // Если нет запроса на прерывание, то
RA=PC1 IO_RD, IO_CMD // Инициировать цикл чтения шины в регистр BRI (инициализация кэширования инструкции)
PC1=PC2=PC1+2
GOTO 0x01 // Перейти на команду выборки следующей инструкции
if (RI=000) // Если режим WAIT, то
ACC=ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
if (RI2=1) // Если есть запрос на прерывание, то
ACC=ACC IO_RD, IO_IN, IO_SEL // Инициировать цикл чтения безадресного регистра в регистр BRD
GOTO 0x11 // Перейти на команду обработки прерывания
//======================================================================
//
// Команда выборки кэшированной инструкции
//
// Входные данные: PC2 - указывает на адрес инструкции + 2
// PC1 - указывает на адрес инструкции
// или на адрес инструкции + 2
//
//======================================================================
0x01: if ((RI=001) & IX1=0) // Если нет запроса на прерывание, и BIR действительный, то
SET_CEND // Если в BIR еще нет слова текущей инструкции, то ждать готовности BIR,
// затем преддекодер декодирует инструкцию и устанавливает начальные параметры для микропрограммы
BRA_REQ // Запросить проверку условий по значениям BIR и PSW, которые могут быть
// использованы, если следующей командой будет условный переход
IO_RCD1 // Особое управление блоком таймаута
RA=PC2 IO_RCD // Инициировать цикл чтения шины в регистр BIR и BRD одновременно (кеширование следующей команды/данных)
PC1=PC2 // Фактически имитация PC1=PC+2
PC2=PC2+2
GOTO 0x00 // На самом деле переход осуществляется на первую команду новой инструкции
if ((RI=001) & IX1=1) // Если нет запроса на прерывание, и BIR недействительный, то
PC1=PC2=PC1-2
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
if (RI=000) // Если режим WAIT, то
ACC=ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
if (RI2=1) // Если есть запрос на прерывание, то
ACC=ACC IO_RD, IO_IN, IO_SEL // Инициировать цикл чтения безадресного регистра в регистр BRD
GOTO 0x11 // Перейти на команду обработки прерывания
Обработка прерывания:
Код://======================================================================
//
// Обработка запроса на прерывание
//
//======================================================================
0x11: if (RI1=0) // Если запрос на прерывание в режиме USER, то
WAIT_BRD // Ожидание готовности чтения BRD
PSW=0
GOTO 0x3E // Перейти на обработку прерывания в режиме USER
if (RI1=1) // Если запрос на прерывание в режиме HALT
WAIT_BRD // Ожидание готовности чтения BRD
PSW=0xFFEF
//----------------------------------------------------------------------
0x3C: // Обработка прерывания HALT. В регистре BRD находится считанный безадресный регистр
BRD.L=0
//----------------------------------------------------------------------
0x1D: ACC=BRD+вектор // Вектор прерывания устанавливается блоком запроса прерываний
RA=ACC IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
GOTO 0x20 // Перейти на продолжение обработки прерываний
//----------------------------------------------------------------------
0x3Е: // Обработка прерываний USER
RA=R6=R6-2 IO_WR, IO_CMD // Инициировать цикл записи BRD на шину
//----------------------------------------------------------------------
0x1C: BRD=CPSW // Инициилизировать BRD и продолжить цикл записи
//----------------------------------------------------------------------
0x2E: RA=R6=R6-2 IO_WR, IO_CMD // Инициировать цикл записи BRD на шину
//----------------------------------------------------------------------
0x36: BRD=PC // Инициилизировать BRD и продолжить цикл записи
//----------------------------------------------------------------------
0x34: if (RI0=0) // Если не векторное прерывание (VIRQ), то
ACC=вектор // Вектор прерывания устанавливается блоком запроса прерываний
RA=ACC IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
GOTO 0x20 // Перейти на продолжение обработки прерываний
else // Иначе векторное прерывание (VIRQ)
ACC=ACC IO_RD, IO_IN, IO_IAK // Инициировать цикл чтения вектора прерывания IAK в регистр BRD
//----------------------------------------------------------------------
0x2F: WAIT_BRD // Ожидание готовности чтения BRD
RA=ACC=BRD IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
//----------------------------------------------------------------------
0x20: // Продолжение обработки прерывания общее для всех
WAIT_BRD // Ожидание готовности чтения BRD
PC1=PC2=BRD
//----------------------------------------------------------------------
0x3D: ACC=ACC+2 // ACC - вектор прерывания + 2
RA=ACC IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
//----------------------------------------------------------------------
0x26: // Ожидание готовности чтения BRD
if (RI=11x) // Если прерывание в режиме HALT/начальный пуск, то
PSW=BRD
else // Иначе прерывание в режиме USER
PSW.B=BRD
//----------------------------------------------------------------------
0x39: NO ALU PI_STB CLR_WAIT RI=000 // Управление: отменить режим WAIT (влияет на режим флага Т?)
//---------------------------------------------------------------------- (Общий шаг для многих команд)
0x25: ACC=ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
Следующая часть Мерлезонского балета.
Очень увлекательное, хотя, и требующее времени и внимательности, занятие - восстанавливать микрокод.
Но, тут как с кошечкой в пылесосе, главное втянуться :v2_dizzy_write:
RTS:
Код://======================================================================
//
// Команда RTS (000200-000207)
//
//======================================================================
0x37: PC1=PC2=Rn
//----------------------------------------------------------------------
0x28,0x38: RA=R6 IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
R6=R6+2
//----------------------------------------------------------------------
0x1F: WAIT_BRD // Ожидание готовности чтения BRD
Rn=BRD PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
FIS:
Код://======================================================================
//
// Команда FIS (075000-075037)
//
//======================================================================
0x05: ACC=ACC IO_RD, IO_IN, IO_SEL // Инициировать цикл чтения безадресного регистра в регистр BRD
//----------------------------------------------------------------------
0x27: WAIT_BRD // Ожидание готовности чтения BRD
ACC.B=BRD GET_STATE N=0 // Если N=0, то BRA=1, иначе BRA=0
//----------------------------------------------------------------------
0x35: if (BRA=1) // Если BRA=1 (в прошлой команде N=0)
NO ALU PI_STB VEC=0x08 RI=110 // Управление: запрос программного прерывания по вектору 0x08 в режиме HALT
GOTO 0x01 // Перейти на команду выборки следующей инструкции
else // Иначе
NO ALU PI_STB VEC=0x08 RI=100 // Управление: запрос программного прерывания по вектору 0x08 в режиме USER
GOTO 0x01 // Перейти на команду выборки следующей инструкции
WAIT:
Код://======================================================================
//
// Команда WAIT (000001)
//
//======================================================================
0x05: NO ALU PI_STB WAIT RI=000 // Управление: установить режим WAIT, сообщить о режиме WAIT блоку прерываний
GOTO 0x01 // Перейти на команду выборки следующей инструкции
RESET:
Код://======================================================================
//
// Команда RESET (000005)
//
//======================================================================
0x05: NO ALU PI_STB INIT RI=010 // Управление: инициировать INIT
//---------------------------------------------------------------------- (Общий шаг для многих команд)
0x25: ACC=ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
HALT:
Код://======================================================================
//
// Команда HALT (000000)
//
//======================================================================
0x05: NO ALU PI_STB VEC=0x78 RI=110 // Управление: запрос программного прерывания по вектору 0x78 в режиме HALT
GOTO 0x01 // Перейти на команду выборки следующей инструкции
Все однотипные программные прерывания:
USER: RSEL, MFUS, RCPC, RCPS, CODE030, MTUS, WCPC, WCPS, START, STEP
BPT, IOT, EMT, TRAP:
Код://======================================================================
//
// Команды
// USER: RSEL, MFUS, RCPC, RCPS, CODE030, MTUS, WCPC, WCPS, START, STEP
// TRAP10_7, TRAP10_40, TRAP10_6500, TRAP10_6600
//
//======================================================================
0x05: NO ALU PI_STB VEC=0x08 RI=100 // Управление: запрос программного прерывания по вектору 0x08 в режиме USER
GOTO 0x01 // Перейти на команду выборки следующей инструкции
//======================================================================
//
// Команда BPT (000003)
//
//======================================================================
0x05: NO ALU PI_STB VEC=0x0C RI=100 // Управление: запрос программного прерывания по вектору 0x0C в режиме USER
GOTO 0x01 // Перейти на команду выборки следующей инструкции
//======================================================================
//
// Команда IOT (000004)
//
//======================================================================
0x05: NO ALU PI_STB VEC=0x10 RI=100 // Управление: запрос программного прерывания по вектору 0x10 в режиме USER
GOTO 0x01 // Перейти на команду выборки следующей инструкции
//======================================================================
//
// Команда EMT (104000-104377)
//
//======================================================================
0x05: NO ALU PI_STB VEC=0x18 RI=100 // Управление: запрос программного прерывания по вектору 0x18 в режиме USER
GOTO 0x01 // Перейти на команду выборки следующей инструкции
//======================================================================
//
// Команда TRAP (104400-104777)
//
//======================================================================
0x05: NO ALU PI_STB VEC=0x1C RI=100 // Управление: запрос программного прерывания по вектору 0x1C в режиме USER
GOTO 0x01 // Перейти на команду выборки следующей инструкции
Как ни странно, все служебные команды кончились, и начались математическо-логические.
Однооперандные с регистровой адресацией Rn:
INC(B), DEC(B), CLR(B), NEG(B), COM(B), ADC(B), SBC(B),
ASR(B), ROR(B), ASL(B), ROL(B), TST(B), SWAB, SXT, MFPS:
Код://======================================================================
//
// Математическо-логические операции с одним операндом
// и регистровой адресацией Rn
//
// INC(B), DEC(B), CLR(B), NEG(B), COM(B), ADC(B), SBC(B),
// ASR(B), ROR(B), ASL(B), ROL(B), TST(B), SWAB, SXT, MFPS
//
//======================================================================
0x37: if INC(B) Rn(.B)=Rn+1 VZN
if DEC(B) Rn(.B)=Rn+~1+1 VZN
if CLR(B) Rn(.B)=Rn&0 VZNC
if NEG(B) Rn(.B)=~Rn+1 VZNC
if COM(B) Rn(.B)=~Rn^0 VZNC
if ADC(B) Rn(.B)=Rn+C VZNC
if SBC(B) Rn(.B)=Rn+~C+1 VZNC
if ASR(B) Rn(.B)=(Rn^0)>>1 VZNC
if ROR(B) Rn(.B)=((Rn^0)>>1)|(C<<7) VZNC
if ASL(B) Rn(.B)=(Rn^0)<<1 VZNC
if ROL(B) Rn(.B)=((Rn^0)<<1)|C VZNC
if TST(B) ACC(.B)=Rn^0 VZNC
if SWAB Rn=SWAB(Rn^0) VZNC
if SXT if (N) Rn=0^0xFFFF VZNC
else Rn=0^0 VZN
if MFPS Rn=SIGNEXT(PSW) VZN
endif
PLI_REQ // Запросить проверку запросов на прерывание
if (Rn=R7) GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
else GOTO 0x01 // Перейти на команду выборки следующей инструкции
MTPS Rn
Непонятно и специфически устроена команда MTPS, хотя я и догадываюсь почему.Код://======================================================================
//
// Команда MTPS Rn (1064SS)
//
//======================================================================
0x37: PSW.B=Rn Бит T не изменяется
//----------------------------------------------------------------------
0x18,0x38: PI_STB RI=001 // Управление: нет запроса на прерывание (не имеет эффекта, т.к. следующая команда перезапишет RI)
//----------------------------------------------------------------------
0x08 ACC=ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // Перейти на команду выборки следующей инструкции
Дело в том, что модификация бита T в регистре PSW управляется отдельно, и одним из условий, позволяющем не трогать бит Т является /NA=0. Или, иными словами, чтобы адрес следующей микрокоманды был четным. Однако, если мы закончим обработку стандартно, и перейдем на адрес 0x01, то флаг T тоже изменится. Поэтому сделан обходной маневр по четным адресам, добавляющий 8(!) лишних тактов к инструкции. Вот такие вот костыли на ровном месте, казалось бы. А все из-за экономии места в PLM, и непрофильном использовании бит, относящихся к другим данным, в данном случае к адресу следующей микрокоманды.
- - - Добавлено - - -
Если через 100 лет вас кто-то спросит - дедушка, а почему MFPS выполняется 8 тактов, а MTPS 16? А вы и ответите - бит не хватило, пришлось ехать в Киев через Магадан.
Начнём:
По данной команде регистр R5 должен увеличиваться на 2.
Ух! Неужто для режима USER PSW становится равным нулю, а в режиме HALT 0177757? Я думал, что только очищается/ставится бит 8. И кстати регистр PSW вроде 9-разрядный.
По моим данным при сохранении в стеке, значение SP всегда уменьшается на 4, даже если при первой записи произошёл TRAP4.
Вроде бы в качестве условия присутствия эмулятора FIS выступает сброшенное значение разряда 7 в SEL.
Да, 9 разрядов. Остальные незадействованы.
Чтобы очистить/поставить бит 8, нужна константа 0x0100. А ее в блоке констант нет. Гораздо проще все в 0, или все в 0xFFFF установить.
- - - Добавлено - - -
А в чем несостыковка?
Если бит 7 установлен, то то идет прерывание в режиме USER по вектору 0x08 (резервный код).
А если не установлен, то в режиме HALT по вектору SEL+0x08.
- - - Добавлено - - -
Там не может быть уменьшения на 4, т.к. все константы равны 2.
Да и запись в стек идет последовательно. Какой смысл уменьшать его на 4?
- - - Добавлено - - -
Да, все так. Пропустил одну строчку. Исправлю.
Спасибо за проверку)
Так всё таки 0xFFFF или 0xFFEF, т.е. бит T очищен или нет.
А нестыковка в том, какое сравнение делается - словное или байтовое?
По моим опытам получается, что если при первой записи в стек произойдёт TRAP4, то значение SP всегда уменьшается на 4.
Пример: поставим SP равным 0160002. Дадим команду EMT или TRAP. Текущие значения CPC и CPSW сохраняются в стеке. Сперва SP уменьшается на два и в ячейку 0160000 записывается CPSW, запись не удаётся, должен быть TRAP4. TRAP4 происходит, и значения CPC и CPSW пишутся уже в ячейки 0157772 и 0157774. Ячейка 0157776 остаётся нетронутой.
0xFFEF. А точнее, инверсная константа 0x0010.
- - - Добавлено - - -
Не могу сказать, почему это происходит, т.е. еще не изучал блок таймаута. Он навороченный.
- - - Добавлено - - -
Да, байтовое, тоже исправлю.
- - - Добавлено - - -
Если бегло поразмыслить, то скорее всего блок таймаута дает некий фиктивный RPLY, который называется TO_RPLY. Таким образом операция ввода-вывода завершается, и начинается вторая, уменьшающая SP на 2. Но дальше уже все прерывается.