Архитектура PDP-11
Цикл работы процессора
Адресное пространство
- 1 байт содержит 8 бит.
- Машинное слово состоит из 2 байт (16 бит).
- Байты и слова имеют единое адресное пространство.
- Байт с меньшим адресом лежит в младшем разряде.
- Машинные слова имеют адреса от 0 до 65534. (16-разрядный адрес)
- Память PDP-11 расположена в первых 56 Кб адресуемых ячеек памяти (адреса 000000-157777)
- Начиная с адреса 160000 и выше (старшие 8kB) находятся регистры периферийных устройств.
- В некоторый моделях PDP регистры процессора (R0-R7, PSW) отображены в адресном пространстве в диапазоне 177700-1777017
Регистры процессора
Регистры - аналог ячеек памяти, расположенные внутри ЦП
- Регистры 16-битные
- Машина имеет 8 регистров общего назначения (далее R0..R7). Обращение ко всем регистрам имеет одинаковый формат.
- Регистр R7 содержит адрес памяти, из которого будем считывать следующее машинное слово, иначе называется PC (programm counter).
- Регистр R6 содержит адрес памяти, являющийся вершиной стека, иначе называется SP (stack pointer)
- Команд для доступа отдельно к младшим или старшим байтам регистра - нет.
Регистры внешних устройств
- istat=0177560 - регистр состояния устройства ввода
- idata=0177562 - регистр данных устройства ввода
- ostat=0177564 - регистр состояния устройства вывода
- odata=0177566 - регистр данных устройства вывода
- когда 7-ой бит регистра состояния устройств ввода/вывода содержит 1, то устройство готово к работе.
Слово состояния процессора (PSW)
Кроме регистров у процессора есть еще одно доступное слово,
характеризующее состояние процессора. Выполнение некоторых команд может
привести к изменению некоторых бит-флагов.
Из 16-битного слова состояния процессора (Process State Word) необходимо моделировать только 4 последних бита: флаги N, Z, V, C.
- Z - is zero – индикатор нуля, равен 1, если в результате выполнения операции получился ноль.
- N - is negative – индикатор отрицательного
результата, равен 1, если в результате выполнения операции получилось
отрицательное число.
- C - индикатор переноса.
- V - индикатор знакового переполнения.
ЦП обычно устанавливает С в 1, если произошел перенос из 15-го бита.
Можно считать С не существующим "16-тым битом".
V устанавливается в 1, если, например, при сложении положительных чисел
получилось отрицательное число (в результате переполнения). Заметим, что
при этом флаг С=0.
Команды и псевдокоманды ассемблера
Директивы ассемблера PDP-11
- Директивы начинаются со знака . (точка).
- Директивы не являются мнемониками машинного кода, а управляют самим ассемблером или служат для размещения данных.
- Управляющие директивы не создают машинного кода, но влияют на
дальнейшее преобразование (например задают константы или новый адрес
размещения машинного кода).
- Директивы размещения данных предназначены для формирования в исполняемом коде данных, отличных от инструкций процессора.
- Ниже приведены наиболее часто употребляемые директивы.
- .= адрес - разместить следующие команды, начиная с указанного адреса.
- Пример:
.=1000 следующий код размещается, начиная с адреса 1000
- На самом деле, эта директива изменяет значение специальной
переменной с именем . (точка), чье значение равно текущему адресу
размещения машинного кода.
- .BYTE числа через запятую
- размещает указанные числа по одному в байте (если число не помещается в байт, страшие разряды откидываются)
- .BLKB N
- резервирует N байт в памяти, начиная с текущего адреса
- .WORD числа через запятую
- размещает указанные числа по одному в слове
- .BLKW N
- резервирует N слов в памяти, начиная с текущего адреса
- .ASCII #текст# - размещает в памяти символы
указанного текста по одному в байте. Символ начала и конца текста может
быть любой (в данном случае #). Примеры:
-
.ASCII #Hello, world!#
-
.ASCII SHello, world!S
-
.ASCII /Hello, world!/
-
.ASCII #Hello,# <015><012> #world!# - после запятой напечатаются \r\n (символы возврата каретки и новой строки)
- .ASCIZ #текст# - аналогично
.ASCIZ , но в конце строки добавляет байт, содержащий ноль.
- .EVEN - следующее слово гарантированно с четного
адреса (пропускает 1 байт, если нужно). Нужно использовать после
директив размещения, чтобы последующие команды размещались по четному
адресу.
- Константы и метки. В следующем фрагменте кода приведена именованная
константа А (равная восьмеричному числу 123), метка В, восьмеричное
число 15, десятичное число 12, символьная константа z (равна значению
ascii кода символа z, т.е 122 десятичное или 172 восьмеричное).
A = 123
.=1000
B: .WORD 15, 12., 'z, A, B
этот фрагмент будет преобразован в следующие слова (вторая колонка,
восьмеричные числа) по указанным адресам (первая колонка, восьмеричные
числа). Третья колонка - объяснения.
001000 000015 восьмеричная константа 15 легла по адресу, указанному в .= как текущий
001002 000015 десятичное 12 есть 15 в восьмеричной системе
001004 000172 это ascii-код символа z
001006 000123 значение константы А
001010 001000 значение константы (метки) B
Заметим, что мы можем использовать В как именованную константу со
значением 1000 (т.е. метка равна адресу, по которому она расположена).
Область видимости метки - весь файл (как ниже, так и выше по тексту).
Аргументы
Режимы адресации (операнды SS и DD)
Управление памятью
Страничная организация памяти
Формирование физического адреса
Инструментальные средства для программирования на PDP-11
Ассемблер
as11 имя_входного_файла [-l имя_листинг_файла] [-o имя_исполняемого_файла]
Программа, преобразующая мнемоники команд ассемблера в машинный код. В
результате работы создает файл листинга и исполняемый файл.
Формат исполняемого файла
Исполняемый файл (s-rec файл) состоит из нескольких блоков. Каждый блок состоит из адреса начала блока adr, количества байтов данных в блоке n и байтов данных a1, a2 .. an (по одному байту на строку).
Все числа шестнадцетиричные.
Формат файла листинга
Файл листинга используется для облегчения отладки программ на
ассемблере. Строится на основе файла с программой из мнемоник
ассемблера.
Добавляется колонка адреса ячейки памяти (первая) и содержимого ячейки памяти (вторая). Далее идет исходный код.
Пример фрагмента исходной программы:
. = 1000
main: mov #main,sp ; init stack
Построенный по данному фрагменту листинг:
000000: . = 1000
001000:
001000: main: mov #main,sp ; init stack
012706
001000
Эмулятор
pdp11 [опции] имя_исполняемого_файла
- Опции:
-
-s N - начальный адрес исполнения, восьмеричное (по умолчанию 1000).
-
-n - не формировать параметры argc/argv для функции main().
-
-q - не печатать никакой дополнительной информации кроме вывода эмулируемой программы.
-
-t - трассировка на stderr.
-
-T - подробная трассировка на stderr.
-
-o - запустить в отладчике.
- Команды отладчика:
-
Q - выйти из отладчика и эмулятора.
-
0-7 - восьмеричные цифры, задают адрес.
-
g - go, выполнять, начиная с указанного адреса.
-
s - step, пошаговое выполние от указанного адреса или текущего значения PC.
-
p - продолжить исполнять программу с текущего значения PC.
-
^p - прервать исполнение и войти в отладчик.
-
rX - содержимое регистра для r0-r7 или значение PSW для rs .
-
/ - открыть регистр или ячейку памяти для просмотра/изменения.
-
< > пробел - открыть предыдущий/следующий регистр или ячейку памяти.
-
i - открыть инструкцию (дизассемблированную).
Режим трассировки эмулятора
При запуске эмулятора с опцией -t в поток stderr пошагово выводятся исполняемые инструкции с отображением операндов.
Например, для программы
. = 1000
; Compute sum of zero-terminated array
;
mov #array, r1
clr r0
loop:
add (r1)+, r0
tst (r1)
bne loop
halt
array:
.word 1,2,3,0
трассировка будет выглядеть как
$ pdp11 -t array
---------------- running --------------
001000: mov #001016,r1 [001002]=001016
001004: clr r0
001006: add (r1)+,r0 [001016]=000001 R0=000001
001010: tst (r1) [001020]=000002
001012: bne 001006
001006: add (r1)+,r0 [001020]=000002 R0=000003
001010: tst (r1) [001022]=000003
001012: bne 001006
001006: add (r1)+,r0 [001022]=000003 R0=000006
001010: tst (r1) [001024]=000000
001012: bne 001006
001014: halt
---------------- halted ---------------
r0=000006 r2=000000 r4=000000 sp=000000
r1=001024 r3=000000 r5=000000 pc=001016
psw=000004: cm=k pm=k pri=0 Z [12]
После остановки эмулятора печатаются значения регистров.
В случае большого объема трассировки, ее лучше перенаправлять в файл.
$ pdp11 -t big_program 2> out.txt
И останавливать выполнение pdp11 нажатием Ctrl+C в случае зацикливания.
Компилятор языка С
Словарь
- SP
- stack pointer - R6, содержит адрес вершины стека
- PC
- program counter - R7, счетчик команд, содержит адрес ячейки памяти, которую будут читать следующей.
- PSW
- Processor State Word - слово, характеризующее состояние процессора; содержит различные флаги
- RAM
- random access memory - память с произвольным доступом
(линейный массив, в отличие от памяти последовательного доступа,
например магнитной ленты).
- байт
- минимальная адресуемая единица памяти
- бит
- 0 или 1
машинное;слово:
разрядность:
- регистры
- аналог ячеек памяти, расположенные внутри ЦП
- ЦП
- центральный процессор
Тесты
Hello, world
;.include "ascii.s11"
CR=15
LF=12
. = 1000
main: mov #main,sp ; init stack
mov #hello,r0
jsr pc,puts
halt
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; putchar
; input: RO - ascii char
; output: none
; clobber: flags
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ocsr = 0177564 ; TTO command and status register for PDP-11
odat = 0177566 ; TTO data register
;
putchar: tstb @#ocsr ; test bit 7 in ocsr (it's sign bit!!!)
bpl putchar ; if ( bit 7 == 0 ) wait ... device is busy
movb r0,@#odat ; put char to the odat
rts pc ; return
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; puts
; input: RO - asciz string
; output: none
; clobber: flags, r0
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
puts: mov r1,-(sp) ; save r1 in stack
mov r0,r1 ; copy addr to r1
l1: movb (r1)+,r0 ; put next char to r0
beq l2 ; if (r0 == 0) goto l2
jsr pc,putchar ; call putchar()
br l1 ; goto l1
l2: mov (sp)+,r1 ; restore r1 from stack
rts pc ; return
hello: .asciz <CR><LF>/hello, world!/<CR><LF> |