ВМ2: Самая загадочная команда CODE030
Все, что вы хотели узнать о команде CODE030, но боялись спросить :v2_wink2:
Пояснения:
1. На флаги VZNC влияют все микрокоманды, однако переписывают их в PSW только те, у которых это отдельно указано.
2. Режим проверки условий GET_STATE устроен таким образом, что условия проверяются по окончании микрокоманды,
добавляя к ней еще 4 такта (а что делать, надо же прокачать PLM проверки условий),
а результат проверки (BRA=1, если условие совпало) доступен уже в следующей микрокоманде.
В начале следующей микрокоманды условие будет сброшено (BRA=0), в независимости от того, воспользовались им или нет.
3. SEXT() - расширение знака байта до слова.
Код:
//======================================================================
//
// Команда CODE030 (000030)
//
//======================================================================
Адрес Микрокоманда PSW Дополнительно Комментарий
0x05: R0=0
//----------------------------------------------------------------------
0x27: ACC.B=R2 GET_STATE N=0 // Если N=0, то BRA=1, иначе BRA=0
//---------------------------------------------------------------------- Начало цикла
0x35: if (BRA=1) // Если BRA=1 (в прошлой команде N=0)
R0.B=R0+1 GET_STATE N=0 // Если N=0, то BRA=1, иначе BRA=0
else // Иначе
ACC=R0 VZNC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // и перейти на команду выборки следующей инструкции
//----------------------------------------------------------------------
0x31: if (BRA=1) // Если BRA=1 (в прошлой команде N=0)
R1=R1<<1
else // Иначе
ACC=R0 VZNC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x01 // и перейти на команду выборки следующей инструкции
//----------------------------------------------------------------------
0x19: R3=(R3<<1)|PSW[0]
//----------------------------------------------------------------------
0x1E: R2=SEXT((R2<<1)|PSW[0]) GET_STATE N=0 // Если N=0, то BRA=1, иначе BRA=0
GOTO 0x35 // Перейти на команду 0x35
ВМ2: Выборка инструкций и обработка прерываний
Одно из самых таинственных действий процессора 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 // Перейти на команду выборки следующей некэшированной инструкции
ВМ2: Адресации однооперадных команд
Непростые команды, использующие почти все возможные ухищирения, чтобы каждой командой сделать побольше.
Тут у нас и кэш сбрасывается, а регистр BIR (буфер для слова инструкции) используется, как данные. И прочее.
Плюс большая универсальность, т.к. одной микропрограммой обрабатывается множество вариантов адресаций и команд.
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, MTPS, MFPS,
JMP, JSR:
Код:
//======================================================================
//
// Oперации с одним операндом
// расположенном в памяти
//
// 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, MTPS, MFPS
// JMP, JSR
//
// step=1 для байтовых команд, если dd<>R6 и dd<>R7
// step=2 для всх остальных команд
//
// Циклы шины IO_X001 для:
//
// TST(B), MTPS:
// Read (IO_RD, IO_IN) - Инициировать цикл чтения шины в регистр BRD
//
// CLR, SXT:
// Write (IO_WR) - Инициировать цикл записи BRD на шину
//
// CLRB, COM(B), INC(B), DEC(B), NEG(B), ADC(B), SBC(B),
// ROR(B), ROL(B), ASR(B), ASL(B), SWAB, MFPS:
// R-M-W (IO_RD, IO_WR, IO_IN) - Инициировать цикл чтения шины в регистр BRD
// с последующим циклом записи по готовности BRD
//
// JMP, JSR:
// нет цикла шины
//
//======================================================================
0x17: if (Rn) RA=Rn IO_X001 // Инициировать цикл шины
Rn=Rn
GOTO 0x33
if (Rn)+ and (RI0=0) // Если Rn<>R7
RA=Rn IO_X001 // Инициировать цикл шины
Rn=Rn+step
GOTO 0x33
if (Rn)+ and (RI0=1) and (IX0=1) // Если Rn=R7, и операция чтения слова (TST)
PC1=PC2 DISABLE_CACHE // Запретить кэш и включить режим использования BIR как данных
// Фактически PC1=PC1+2
BRD=BIR IO_X001 // Подготовить, но не начинать цикл шины
GOTO 0x33
if (Rn)+ and (RI0=1) and (IX0=0) // Если Rn=R7, и не операция чтения слова
PC1=PC2 DISABLE_CACHE // Запретить кэш и включить режим использования BIR как данных
// Фактически PC1=PC1+2
RA=PC1-2 IO_X001 // Инициировать цикл шины
GOTO 0x33
if -(Rn) Rn=Rn-step
RA=Rn IO_X001 // Инициировать цикл шины
GOTO 0x33
if @-(Rn) Rn=Rn-2
RA=Rn IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
GOTO 0x22
if @(Rn)+ and (RI0=0) // Если Rn<>R7
Rn=Rn+2
RA=Rn IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
GOTO 0x22
if @(Rn)+ and (RI0=1) // Если Rn=R7
PC1=PC2 DISABLE_CACHE // Запретить кэш и включить режим использования BIR как данных
// Фактически PC1=PC1+2
RA=BIR IO_X001 // Инициировать цикл шины
GOTO 0x33
if X(Rn) PC1=PC2 DISABLE_CACHE // Запретить кэш и включить режим использования BIR как данных
RA=Rn+BIR IO_X001 // Инициировать цикл шины
GOTO 0x33
if @X(Rn) PC1=PC2 DISABLE_CACHE // Запретить кэш и включить режим использования BIR как данных
RA=Rn+BIR IO_RD, IO_IN // Инициировать цикл чтения шины в регистр BRD
//---------------------------------------------------------------------- Прочитана ячейка с адресом операнда
0x22: PC1=PC2 DISABLE_CACHE // Запретить кэш и включить режим использования BIR как данных
WAIT_BRD // Ожидание готовности чтения BRD
RA=BRD IO_X001 // Инициировать цикл шины
ENABLE_CACHE // Разрешить кэш
//---------------------------------------------------------------------- Операнд прочитан из памяти, если цикл шины Read или RMW
0x33: WAIT_BRD // Ожидание готовности чтения BRD
if (JMP/JSR) // Если команда JMP/JSR
ACC=RA
ENABLE_CACHE // Разрешить кэш
GOTO 0x18
else
ALU BRD // Операции ALU из шага 0x37, в качестве операнда используется BRD
// Если используется цикл записи Write или RMW, то по записи в BRD, продолжается цикл записи
ENABLE_CACHE // Разрешить кэш
if MTPS GOTO 0x18 // Завершить команду MTPS особым способом
PLI_REQ // Запросить проверку запросов на прерывание
if X(Rn) or @X(Rn) or (Rn=R7) // Если использовали адресацию по R7, то
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
else // Иначе
GOTO 0x01 // Перейти на команду выборки следующей инструкции
//---------------------------------------------------------------------- Обработка JMP/JSR
0x18: if (MTPS) PI_STB RI=001 // Управление: нет запроса на прерывание (не имеет эффекта, т.к. следующая команда перезапишет RI)
GOTO 0x08 // Перейти на холостую команду и выборку следующей инструкции
if (JMP) // Если JMP
PC1=PC2=RA PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
else // Иначе JSR
RA=R6=R6-2 IO_WR, IO_CMD // Инициировать цикл записи BRD на шину
//---------------------------------------------------------------------- Обработка JSR
0x0E: BRD=Rs // Инициилизировать BRD и продолжить цикл записи
//----------------------------------------------------------------------
0x0C: Rs=PC1
//----------------------------------------------------------------------
0x09: PC1=ACC PLI_REQ // Запросить проверку запросов на прерывание
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
//---------------------------------------------------------------------- Завершение MTPS
0x08: ACC=ACC PLI_REQ // Запросить проверку запросов на прерывание
if X(Rn) or @X(Rn) or (Rn=R7) // Если использовали адресацию по R7, то
GOTO 0x21 // Перейти на команду выборки следующей некэшированной инструкции
else // Иначе
GOTO 0x01 // Перейти на команду выборки следующей инструкции
- - - Добавлено - - -
Просьба специалиста по PDP @Alex_K проверить эти адресации.
Также исправил на предыдущей странице микрокод для однооперандных регистровых инструкций. Добавил случай, когда Rn=R7.