--PAGE_BREAK--Система команд
Різноманітність типів даних, форм представлення та опрацювання, необхідні дії для обробки та керування ходом виконання обчислень призводить до необхідності використання різноманітних команд — набора команд.
Кожен процесор має власний набір команд, який називається системою команд процесора.
Система команд характеризується трьома аспектами:
- формат,
- способи адресації,
- система операцій.
Форматом команди — є довжина команди, кількість, розмір, положення, призначення та спосіб кодування полів. Команди мають включати наступні види інформації:
- тип операції, яку необхідно реалізувати в даній команді (поле команду операції — КОП);
- місце в пам’яті звідки треба взяти перший операнд (А1);
- місце в пам’яті звідки треба взяти другий операнд (А2);
- місце в пам’яті куди треба помістити результат (А3).
Кожному з цих видів інформації відповідає своя частина двійкового слова — поле. Реальна система команд зазвичай має команди декількох форматів, тип формату визначає КОП.
Команда в комп'ютері зберігається в двійковій формі. Вона вказує тип операції, яка має бути виконаною, адреси операндів, над якими виконується операція, та адреси розміщення результатів виконання операції. Відповідно до цього команда складається з двох частин, коду операції та адресної частини.
КОП займає k розрядів. Ним може бути закодовано до N = 2k різних операцій. Кількість двійкових розрядів, які відводяться під код операції, вибирається таким чином, щоб ними можна було закодувати всі виконувані в даному комп'ютері операції. Якщо деякий комп'ютер може виконувати Nc різних операцій, то мінімальна розрядність поля коду операції k визначається наступним чином: k = [log Nc], де вираз в дужках означає заокруглення до більшого цілого.
Поле адреси (адресна частина) займає m розрядів. В ньому знаходяться адреси операндів. Кожна адреса займає mi розрядів, де і — номер адреси (і=1,2,. n), n — кількість адресних полів. Кожною адресою можна адресувати пам'ять ємністю 2nі слів.
Розмір команди k + m повинен бути узгодженим з розміром даних, тобто бути з ним однаковим або кратним цілому числу, що спрощує організацію роботи з пам'яттю. Як правило, розмір команди рівний 8, 16, 32 біти.
При написанні програми крім двійкової можуть використовуватись й інші форми представлення команд: вісімкова, шістнадцяткова, символьна (мнемонічна). Використання вісімкового і шістнадцяткового кодування дозволяє скоротити записи і спростити роботу програміста. Як відомо 3 двійкових розряди (тріада) замінюються на 1 вісімковий, а 4 двійкових розряди (тетрада) — на 1 шістнадцятковий. Приклад:
(000011111111) 2= (0377) 8= (0FF) 16;
Мнемонічне кодування спрощує процес написання, читання і відлагодження програми. Основний принцип такого кодування — кожна команда представляється 3-х або 4-х буквеним символом, який показує назву команди. Деякі приклади мнемонічного кодування:
ADD — додати (add),
SUB — відняти (subtract),
MPY — перемножити (multiply),
DIV — поділити (divide).
Операнди також представляються символічно. Наприклад команда ADD R Y означає додавання вмісту комірки пам'яті Y до вмісту регістра R. Зауважимо, що операція виконується над вмістом, а не над адресою комірки пам'яті та регістра.
Таким чином, з'являється можливість написання машинних програм в символічній формі. Повний набір символічних назв і правила їх використання утворюють мову програмування, відому як асемблерна мова. Символічні імена називаються мнемонічними, а правила їх використання для створення команд і програм називаються синтаксисом мови.
Програма, яка переводить із мнемонічного коду асемблерної мови в машинний, називається асемблером. Команди, які використовуються для переводу вихідної програми в асемблерну, називаються командами асемблера. Ці команди вказують як інтерпретувати назви, де розмістити програму в пам'яті, яка кількість комірок пам'яті необхідна для зберігання даних.
Способи адресації
Варіанти інтерпретації бітів (розрядів) поля адреси з метою знаходження операнда називаються способами адресації. Коли команда вказує на операнд, він може знаходитись в самій команді, в основній або зовнішній пам'яті чи в регістровій пам'яті процесора. За роки існування комп'ютерів була створена своєрідна технологія адресації, яка передбачає реалізацію різних способів адресації, чому послужило ряд причин: забезпечення ефективного використання розрядної сітки команди; забезпечення ефективної апаратної підтримки роботи з масивами даних; забезпечення задання параметрів операндів; можливість генерації великих адрес на основі малих. Існує велика кількість способів адресації. Розглянемо п’ять основних способів адресації операндів в командах.
Пряма— в цьому випадку адресне поле зберігає адресу операнда. Її різновидом є пряма регістрова адресація, яка адресує не комірку пам’яті а номер регістру.
Безпосередня— в поле адреси команди поміщається не адреса, а сам операнд.
Непряма— в полі адреси команди зберігається адреса комірки пам’яті в якій знаходиться адреса операнда. Такій спосіб дозволяє оперувати з адресами як з даними. Різновид непряма-регістрова адресація, адреса адреси зберігається в регістрі загального призначення.
Відносна— адреса формується, як сума з двох доданків: бази, яка зберігається в спеціальному регістрі чи в одному з регістрів спеціального призначення, та зміщення, яке задається в полі адреси команди. Різновид індексна та базова індексна. При індексній замість базового регістра є індексний, який автоматично модифікується (зазвичай збільшується на 1). Базова-індексна адресація формується адреса як сума трьох доданків: бази, індексу та зміщення.
Безадресна— поле адреси в команді відсутнє. Адреса операнда, або немає змісту або є по замовчуванню (наприклад дії на спеціальним регістром — акумулятором). Безадресні команди неможливо використати для інших регістрів чи комірок пам’яті. Одним з різновидів безадресної адресації є використання стеку. В команду вводяться спеціальні ознаки з тим, щоб пристрій керування міг розпізнати використаний спосіб. Це можуть бути додаткові розряди в команді, або для різних типів команд закріплюватись різні способи адресації.
продолжение
--PAGE_BREAK--Вихідні дані на проектування
1. Реалізація додаткових команд. Необхідно реалізувати 8 додаткових команд. Серед них 3 арифметичні, 3 логічні та 2 команди керування згідно варіанту. В таблиці представлено повний перелік множини інструкцій.
Інструкції R-типу:
біти 24-22: код операції
біти 21-19: regA
біти 18-16: reg B
біти 15-3: не використовуються (=0)
біти 2-0: destReg
I-тип інструкцій:
біти 24-22: код операції
біти 21-19: regA
біти 18-16: reg B
біти 15-0: зміщення (16 біт, значення від — 32768 до 32767)
J-тип інструкцій:
біти 24-22: код операції
біти 21-19: regA
біти 18-16: regB
біти 15-0: не використовуються (=0)
Додатковий тип адресації — безадресна (реалізація стеку). Ця адресація имагає двох додаткових інструкцій: PUSH, POP.
O-тип інструкцій:
біти 24-22: код операції
біти 21-0: не використовуються (=0)
\
продолжение
--PAGE_BREAK--Роз'яснення та аналіз основних принципів побудови комп'ютерів на прикладі визначених на реалізацію інструкцій
Структура СК після модифікації:
Рис 1. Функціональна схема СК після модифікації
В СК було додано 13 інструкцій, внаслідок чого поле КОП збільшилося на 2 біти до 5 біт (максимально 32 інструкції з яких використано 21). Решта частина коду операції не зазнала зміни. Був доданий стек глибиною 32 слова по 32 біти, покажчик вершини стеку, прапорець стану ZF.
Перевірка правильності роботи реалізованих команд у прикладах
1. div: 45/5=9.
--PAGE_BREAK--Висновок
При виконанні даного курсового проекту було реалізовано прототипний CISC — комп’ютер згідно із поставленим завданням. Створений комп’ютер пройшов тестування на коректність виконуваних операцій та на відловлювання помилок у вхідному асемблерному коді при синтаксичному та семантичному аналізі. Засвоєно принципи дії та архітектуру прототипних варіантів CISC — комп’ютера. Було внесено зміни в структуру існуючого симулятора CISC — комп’ютера, а саме, доповнена система команд заданими інструкціями, змінено формат усіх команд в частині КОП. До існуючих типів адресації CISC — комп’ютера було добавлено безадресний тип адресації, що в свою чергу призвело до створення стеку всередині структури комп’ютера. Було проведено аналіз роботи команд усіх типів та написано тести з поданням результату роботи симулятора у вигляді виведеного стану машини.
Література
1. Мельник А.О. Архітектура комп’ютера. Наукове видання. — Луцьк: Волинська обласна друкарня, 2008. — 470 с.
2. Жмакин А.П. Архитектура ЭВМ. — СПб.: БХВ-Петербург, 2006. — 320 с.
3. Таненбаум Э. Архитектура компьютера.5-е изд. (+CD). — СПб.: Питер, 2007. — 844 с.
4. Patterson D., and Hennessy J.computer Architecture. A quantitative Approach. Second Edition. — Morgan Kaufmann Publishers,Inc., San Francisco, California, 1996. — 760 p.
Додатки
Доаток I(код програми-асемблера):
/* Assembler for LC */
#include
#include
#include
#define MAXLINELENGTH 1000
#define MAXNUMLABELS 65536
#define MAXLABELLENGTH 7 /* includes the null character termination */
#define ADD 0
#define NAND 1
#define LW 2
#define SW 3
#define BEQ 4
#define JALR 5
#define HALT 6
#define NOOP 7
#define div 8
#define imul 9
#define xidiv 10
#define andf 11
#define xorf 12
#define cmpge 13
#define jmae 14
#define jmnae 15
#define bsf 16
#define bsr 17
#define jne 18
#define push 19
#define pop 20
int readandfParse (FILE *, char *, char *, char *, char *, char *);
int translateSymbol (char labelArray [MAXNUMLABELS] [MAXLABELLENGTH], int labelAddress [MAXNUMLABELS], int, char *);
int isNumber (char *);
void testRegArg (char *);
void testAddrArg (char *);
int main (int argc, char *argv [])
{
char *inFileString, *outFileString;
FILE *inFilePtr, *outFilePtr;
int address;
char label [MAXLINELENGTH], opcode [MAXLINELENGTH], arg0 [MAXLINELENGTH],
arg1 [MAXLINELENGTH], arg2 [MAXLINELENGTH], argTmp [MAXLINELENGTH];
int i;
int numLabels=0;
int num;
int addressField;
char labelArray [MAXNUMLABELS] [MAXLABELLENGTH];
int labelAddress [MAXNUMLABELS];
if (argc! = 3) {
printf («error: usage: %s \n»,
argv [0]);
exit (1);
}
inFileString = argv [1];
outFileString = argv [2];
inFilePtr = fopen (inFileString, «r»);
if (inFilePtr == NULL) {
printf («error in opening %s\n», inFileString);
exit (1);
}
outFilePtr = fopen (outFileString, «w»);
if (outFilePtr == NULL) {
printf («error in opening %s\n», outFileString);
exit (1);
}
/* map symbols to addresses */
/* assume address start at 0 */
for (address=0; readandfParse (inFilePtr, label, opcode, arg0, arg1, arg2);
address++) {
/*
printf ("%d: label=%s, opcode=%s, arg0=%s, arg1=%s, arg2=%s\n",
address, label, opcode, arg0, arg1, arg2);
*/
/* check for illegal opcode */
if (strcmp (opcode, «add») && strcmp (opcode, «nand») &&
strcmp (opcode, «lw») && strcmp (opcode, «sw») &&
strcmp (opcode, «beq») && strcmp (opcode, «jalr») &&
strcmp (opcode, «halt») && strcmp (opcode, «noop») &&
strcmp (opcode,". fill") && strcmp (opcode, «div») &&
strcmp (opcode, «imul») && strcmp (opcode, «xidiv») &&
strcmp (opcode, «andf») && strcmp (opcode, «xorf») &&
strcmp (opcode, «cmpge») && strcmp (opcode, «jmae») &&
strcmp (opcode, «jmnae») && strcmp (opcode, «bsr») &&
strcmp (opcode, «jne») && strcmp (opcode, «bsf») &&
strcmp (opcode, «push») && strcmp (opcode, «pop»))
{
printf («error: unrecognized opcode %s at address %d\n», opcode,
address);
exit (1);
}
/* check register fields */
if (! strcmp (opcode, «add») ||! strcmp (opcode, «nand») ||
! strcmp (opcode, «lw») ||! strcmp (opcode, «sw») ||
! strcmp (opcode, «beq») ||! strcmp (opcode, «jalr») ||
! strcmp (opcode, «div») ||! strcmp (opcode, «imul») ||
! strcmp (opcode, «xidiv») ||! strcmp (opcode, «andf») ||
! strcmp (opcode, «xorf») ||! strcmp (opcode, «cmpge») ||
! strcmp (opcode, «bsf») ||! strcmp (opcode, «bsr»))
{
testRegArg (arg0);
testRegArg (arg1);
}
if (! strcmp (opcode, «nand») ||! strcmp (opcode, «add») ||
! strcmp (opcode, «div») ||! strcmp (opcode, «imul») ||
! strcmp (opcode, «xidiv») ||! strcmp (opcode, «andf») ||
! strcmp (opcode, «xorf») ||! strcmp (opcode, «cmpge»))
{
testRegArg (arg2);
}
/* check addressField */
if (! strcmp (opcode, «lw») ||! strcmp (opcode, «sw») ||
! strcmp (opcode, «beq») ||! strcmp (opcode, «jmae») ||
! strcmp (opcode, «jmnae») ||! strcmp (opcode, «jne»))
{
testAddrArg (arg2);
}
if (! strcmp (opcode,". fill"))
{
testAddrArg (arg0);
}
/* check for enough arguments */
if ( (strcmp (opcode, «halt») && strcmp (opcode, «noop») &&
strcmp (opcode,". fill") && strcmp (opcode, «jalr») &&
strcmp (opcode, «bsf») && strcmp (opcode, «bsr») &&
strcmp (opcode, «pop») && strcmp (opcode, «push») &&
strcmp (opcode, «je») && arg2 [0] =='\0') ||
(! strcmp (opcode, «jalr») && arg1 [0] =='\0') ||
(! strcmp (opcode,". fill") && arg0 [0] =='\0'))
{
printf («error at address %d: not enough arguments\n», address);
exit (2);
}
if (label [0]! = '\0') {
/* check for labels that are too long */
if (strlen (label) >= MAXLABELLENGTH) {
printf («label too long\n»);
exit (2);
}
/* make sure label starts with letter */
if (! sscanf (label, "% [a-zA-Z]", argTmp)) {
printf («label doesn't start with letter\n»);
exit (2);
}
/* make sure label consists of only letters andf numbers */
sscanf (label, "% [a-zA-Z0-9]", argTmp);
if (strcmp (argTmp, label)) {
printf («label has character other than letters andf numbers\n»);
exit (2);
}
/* look for duplicate label */
for (i=0; i
if (! strcmp (label, labelArray [i])) {
printf («error: duplicate label %s at address %d\n»,
label, address);
exit (1);
}
}
/* see if there are too many labels */
if (numLabels >= MAXNUMLABELS) {
printf («error: too many labels (label=%s) \n», label);
exit (2);
}
strcpy (labelArray [numLabels], label);
labelAddress [numLabels++] = address;
}
}
for (i=0; i
/* printf ("%s = %d\n", labelArray [i], labelAddress [i]); */
}
/* now do second pass (print machine code, with symbols filled in as
addresses) */
rewind (inFilePtr);
for (address=0; readandfParse (inFilePtr, label, opcode, arg0, arg1, arg2);
address++) {
if (! strcmp (opcode, «add»)) {
num = (ADD
} else if (! strcmp (opcode, «nand»)) {
num = (NAND
} else if (! strcmp (opcode, «div»)) {
num = (div
} else if (! strcmp (opcode, «imul»)) {
num = (imul
} else if (! strcmp (opcode, «xidiv»)) {
num = (xidiv
} else if (! strcmp (opcode, «andf»)) {
num = (andf
} else if (! strcmp (opcode, «xorf»)) {
num = (xorf
} else if (! strcmp (opcode, «cmpge»)) {
num = (cmpge
} else if (! strcmp (opcode, «jalr»)) {
num = (JALR
} else if (! strcmp (opcode, «bsf»)) {
num = (bsf
} else if (! strcmp (opcode, «push»)) {
num = (push
} else if (! strcmp (opcode, «pop»)) {
num = (pop
} else if (! strcmp (opcode, «halt»)) {
num = (HALT
} else if (! strcmp (opcode, «noop»)) {
num = (NOOP
} else if (! strcmp (opcode, «bsr»)) {
num = (bsr
} else if (! strcmp (opcode, «lw») ||! strcmp (opcode, «sw») ||
! strcmp (opcode, «beq») ||! strcmp (opcode, «jmae») ||
! strcmp (opcode, «jmnae») ||! strcmp (opcode, «jne»)) {
/* if arg2 is symbolic, then translate into an address */
if (! isNumber (arg2)) {
addressField = translateSymbol (labelArray, labelAddress,
numLabels, arg2);
/*
printf ("%s being translated into %d\n", arg2, addressField);
*/
if (! strcmp (opcode, «beq») ||! strcmp (opcode, «jmae») ||! strcmp (opcode, «jmnae»)) {
addressField = addressField-address-1;
}
} else {
addressField = atoi (arg2);
}
if (addressField 32767) {
printf («error: offset %d out of range\n», addressField);
exit (1);
}
/* truncate the offset field, in case it's negative */
addressField = addressField & 0xFFFF;
if (! strcmp (opcode, «beq»)) {
num = (BEQ
| addressField;
} else if (! strcmp (opcode, «jmae»)) {
num = (jmae
| (addressField);
} else if (! strcmp (opcode, «jmnae»)) {
num = (jmnae
| (addressField);
} else if (! strcmp (opcode, «jne»)) {
num = (jne
} else {
/* lw or sw */
if (! strcmp (opcode, «lw»)) {
num = (LW
(atoi (arg1)
} else {
num = (SW
(atoi (arg1)
}
}
} else if (! strcmp (opcode,". fill")) {
if (! isNumber (arg0)) {
num = translateSymbol (labelArray, labelAddress, numLabels,
arg0);
} else {
num = atoi (arg0);
}
}
/* printf (" (address %d): %d (hex 0x%x) \n", address, num, num); */
fprintf (outFilePtr, "%d\n", num);
}
exit (0);
}
/*
* Read andf parse a line of the assembly-language file. Fields are returned
* in label, opcode, arg0, arg1, arg2 (these strings must have memory already
* allocated to them).
*
* Return values:
* 0 if reached end of file
* 1 if all went well
*
* exit (1) if line is too long.
*/
int readandfParse (FILE *inFilePtr, char *label, char *opcode, char *arg0,char *arg1, char *arg2)
{
char line [MAXLINELENGTH];
char *ptr = line;
/* delete prior values */
label [0] = opcode [0] = arg0 [0] = arg1 [0] = arg2 [0] = '\0';
/* read the line from the assembly-language file */
if (fgets (line, MAXLINELENGTH, inFilePtr) == NULL) {
/* reached end of file */
return (0);
}
/* check for line too long */
if (strlen (line) == MAXLINELENGTH-1) {
printf («error: line too long\n»);
exit (1);
}
/* is there a label? */
ptr = line;
if (sscanf (ptr, "% [^\t\n]", label)) {
/* successfully read label; advance pointer over the label */
ptr += strlen (label);
}
/*
* Parse the rest of the line. Would be nice to have real regular
* expressions, but scanf will suffice.
*/
sscanf (ptr, "%* [\t\n\r] % [^\t\n\r] %* [\t\n\r] % [^\t\n\r] %* [\t\n\r] % [^\t\n\r] %* [\t\n\r] % [^\t\n\r] ",
opcode, arg0, arg1, arg2);
return (1);
}
int translateSymbol (char labelArray [MAXNUMLABELS] [MAXLABELLENGTH],
int labelAddress [MAXNUMLABELS], int numLabels, char *symbol)
{
int i;
/* search through address label table */
for (i=0; i
}
if (i>=numLabels) {
printf («error: missing label %s\n», symbol);
exit (1);
}
return (labelAddress [i]);
}
int isNumber (char *string)
{
/* return 1 if string is a number */
int i;
return ( (sscanf (string, "%d", &i)) == 1);
}
/* Test register argument; make sure it's in range andf has no bad characters. */
void testRegArg (char *arg)
{
int num;
char c;
if (atoi (arg) 7) {
printf («error: register out of range\n»);
exit (2);
}
if (sscanf (arg, "%d%c", &num, &c)! = 1) {
printf («bad character in register argument\n»);
exit (2);
}
}
/* Test addressField argument. */
void testAddrArg (char *arg)
{
int num;
char c;
/* test numeric addressField */
if (isNumber (arg)) {
if (sscanf (arg, "%d%c", &num, &c)! = 1) {
printf («bad character in addressField\n»);
exit (2);
}
}
}
Додаток II (код симулятора)
/*Instruction-level simulator for the LC */
#include
#include
#include
#include
#include
using namespace std;
#define NUMMEMORY 65536 /* maximum number of words in memory */
#define NUMREGS 8 /* number of machine registers */
#define MAXLINELENGTH 1000
#define STACKDEPTH 32 продолжение
--PAGE_BREAK--