DevioLabавтоматичне керування капіталом
ПРАЦЮЄ 24/7
КРИПТОВАЛЮТИ · АКЦІЇ · 10 БІРЖ

Портфель, який керується автоматично

DevioLab підбирає стратегії, відстежує ринки та автоматизує купівлю і продаж активів. Кількість доступних криптовалют, акцій і торгових можливостей зростає щодня.

10підключених біржCrypto + Stocksв одному портфелі24/7автоматичний контроль

Проектування комп'ютера з архітектурою CISC

Інформація про навчальний заклад

ВУЗ:
Національний університет Львівська політехніка
Інститут:
Інститут комп’ютерних наук та інформаційних технологій
Факультет:
Комп’ютерні науки
Кафедра:
Кафедра електронних обчислювальних машин

Інформація про роботу

Рік:
2026
Тип роботи:
Курсова робота
Предмет:
Архітектура комп'ютерів
Група:
КН
Коротко про документ

Про що ця робота

У курсовій роботі розглянуто принципи проектування комп'ютерів з архітектурою CISC, а також запропоновано реалізацію асемблера та симулятора. Здійснено аналіз розроблених інструкцій, команд та схем спроектованого процесора.

У роботі розглядаються

  • Архітектура комп'ютера
  • Проектування процесора
  • Архітектура CISC
  • Система команд
  • Стек

Зміст і розділи

  1. Аналітичний розділ
  2. Проектний розділ
  3. Алгоритми роботи розробленого асемблера та стимулятора
  4. Функціональна схема комп’ютера до модифікації
  5. Функціональна схема комп’ютера після модифікації
  6. Множина інструкцій комп’ютера
  7. Опис форматів інструкцій розробленого комп’ютера
  8. Тестовий розділ
  9. Висновок
  10. Використана література
  11. Додатки
Для кого:Студенти технічних спеціальностей, викладачі та дослідники у галузі комп'ютерної інженерії та архітектури обчислювальних машин.
Викладачі:Ногаль М. В.

Ключові поняття

CISCархітектура комп'ютерапам'ятьсистема командстекінструкція

Частина тексту файла (без зображень, графіків і формул):

МІНІСТЕРСТВО ОСВІТИ І НАУКИ УКРАЇНИ НАЦІОНАЛЬНИЙ УНІВЕРСИТЕТ “ЛЬВІВСЬКА ПОЛІТЕХНІКА” КАФЕДРА ЕЛЕКТРОННИХ ОБЧИСЛЮВАЛЬНИХ МАШИН ПОЯСНЮВАЛЬНА ЗАПИСКА до курсової роботи на тему ПРОЕКТУВАННЯ КОМП’ЮТЕРА з дисципліни “Архітектура комп’ютерів” Варіант № 9 Перевірила ст. викл. каф. ЕОМ [ім’я автора приховано] Львів- 2019 АНОТАЦІЯ В даній курсові роботі розглядаються принципи проектування комп’ютерів з архітектурою CISC. Здійснено аналіз основних принципів побудови комп’ютерів з використанням вище згаданої архітектури. Здійснено аналіз розроблених інструкцій. Подано схеми спроектованих комп’ютерів, а також опис створених форматів команд. Розглянуто алгоритм роботи розробленого симулятора та асемблера. ЗМІСТ ВИХІДНІ ДАНІ НА ПРОЕКТ УВАННЯ Варіант №9 Дані на проектування: 1. АНАЛІТИЧНИЙ РОЗДІЛ 1.1 Основні принципи побудови комп’ютерів архітектури CISC Архітектурні принципи, які запропонував Джон фон Нейман: 1. Інформація кодується в двійковому представленні. 2. Інформація в комп’ютері ділиться на команди і дані. 3. Різнотипні за змістом слова розрізняються за способом застосування, а не по способу кодування. 4. Слова інформації розміщаються в комірках пам’яті та ідентифікуються номерами комірок – адресами слів. 5. Пам’ять є лінійною. 6. Пам’ять має довільну адресацію. 7. Команди і дані зберігаються в одній пам’яті. 8. Алгоритми представляються у вигляді послідовності керуючих слів, які називаються командами. Команда визначається найменуванням операції та слів інформації, які в ній приймають участь. Алгоритм записаний у вигляді послідовності команд, називається програмою. 9. Весь набір виконуваних комп’ютером команд називається системою команд комп’ютера. 10. Виконання обчислень, які визначені алгоритмом, являють собою послідовне виконання команд в порядку, визначеному програмою. Для виконання задачі на комп’ютері необхідно: − забезпечити вибірку команди програми із його пам’яті в заданій послідовності, організувати звернення до неї за відповідними адресами; − забезпечити розпізнавання типів виконуваних операцій; − організувати звернення до пам’яті за відповідними адресами для вибірки необхідні для виконання кожної команди даних; − організувати виконання над даними операцій відповідно до вказівок команд; − запам’ятати результат обчислень. Для процесора комп'ютера із складною системою команд характерні наступні особливості: − виконання команди за багато тактів, оскільки для цього потрібно здійснити багаторазові операції звернення до основної пам'яті та до програмно доступних регістрів процесора; − орієнтація АЛП на виконання великої кількості операцій, що пов'язано з розширеним складом системи команд; − складна система розпізнавання команди, що пов'язано з великою кількістю методів адресації та великою кількістю форматів команд різної розрядності; − програмне дешифрування команд з метою зменшення затрат обладнання; − складна організація конвеєризації виконання команд, що пов'язано, в першу чергу, з різнотипністю їх виконання; − орієнтація структури на виконання команд типу регістр-пам'ять та пам'ять пам'ять. Основні елементи процесора - арифметико-логічний пристрій, пристрій керування і регістрова пам'ять або, як її ще називають, надоперативний запам'ятовуючий пристрій. До складу регістрової пам'яті, в свою чергу, входять наступні вузли - програмний лічильник, регістри: адреси, команди, даних, слова стану програми, а також регістровий файл, який складається з програмно доступних регістрів. Різноманітність типів даних, форм представлення та опрацювання, необхідні дії для обробки та керування ходом виконання обчислень призводить до необхідності використання різноманітних команд – набору команд. Кожен процесор має власний набір команд, який називається системою команд процесора. Система команд характеризується трьома аспектами: − формат; − способи адресації; − система операцій. Форматом команди – є довжина команди, кількість, розмір, положення, призначення та спосіб кодування полів. Команди мають включати наступні види інформації: − тип операції, яку необхідно реалізувати в даній команді (поле команди операції - КОП) − місце в пам’яті звідки треба взяти перший операнд (А1); − місце в пам’яті звідки треба взяти другий операнд (А2); − місце в пам’яті куди треба помістити результат (А3). КОП займає k розрядів. Ним може бути закодовано до N = 2k різних операцій. Кількість двійкових розрядів, які відводяться під код операції, вибирається таким чином, щоб ними можна було закодувати всі виконувані в даному комп'ютері операції. Якщо деякий комп'ютер може виконувати Nc різних операцій, то мінімальна розрядність поля коду операції k визначається наступним чином: k = [log2 Nc], де вираз в дужках означає заокруглення до більшого цілого. В нашій машині реалізовано 19 команд тобто поле КОП має займати k=[log219]=5. Поле адреси (адресна частина) займає m розрядів. В ньому знаходяться адреси операндів. Кожна адреса займає mi розрядів, де і - номер адреси (і=1,2,...1), 1 - кількість адресних полів. Кожною адресою можна адресувати пам'ять ємністю 2 слів. В комп’ютерах з архітектурою CISC використовується багато різноманітних способів адресації серед них: пряма; безпосередня; непряма; відносна; безадресна 2. ПРОЕКТНИЙ РОЗДІЛ 2.1. Алгоритми роботи розробленого асемблера та стимулятора Алгоритми роботи розробленого асемблера Рис. 2.1.0 Схема роботи асемблера Загальна схема роботи асемблера (рис. 1) складається з 2 проходів. На першому проході асемблер перевіряє коректність синтаксису команд. На другому виконується генерування відповідних машинних команд, тобто числового представлення асемблерної команди. Функція readAndParse виконує зчитування рядку асемблерної програми і декодування на відповідні поля: мітка, код операції, операнди. Отримана таким чином і декодована інструкція перевіряється на коректність: існування команди, відповідна кількість аргументів, існування міток та т. п. Функція testRegArg перевіряє коректність використання назви регістра. Функція testAddrArg перевіряє коректність використання адреси. Функція labelArray перетворює відповідну мітку у адресу. Program.as та program.mc – відповідно вхідний та вихідний файли. Алгоритми роботи розробленого симулятора Рис. 2.1.1. Схема роботи симулятора Симулятор починає свою роботу ініціалізацією пам’яті та регістрів 0 значеннями (рис. 2.). Наступним кроком відбувається заванаження програми у машинних кодах в пам’ять. Далі відбувається покрокове виконання інструкцій та вивід стану на зовнішній пристрій (чи на екран консолі чи у файл). У stateStruct зберігається стан машини – значення регістрів, пам’яті та програмний лічільник. stateStruct Функція Run виконує обробку інструкцій з пам’яті, функція printState виводить поточний стан машини, а функція convertNum виконує перетворення числа у доповняльний код. 2.2. Функціональна схема комп’ютера до модифікації Рис. 2.2. Функціональна схема спрощеного комп’ютера. В спрощеному комп’ютері (СК) в пам’яті зберігаються, як дані так і інструкції. Кожна інструкція закодована числом. Це число складається з декількох полів: поле назви команди чи код операції (КОП) та полів операндів. В СК є два види пам’яті: загальна пам’ять(MEMORY), та регістрова пам’ять (REGISTER FILE). В загальній пам’яті зберігаються інструкції програми та дані над якими оперують інструкції. В регістровий пам’яті зберігаються дані над якими виконуються інструкції. У реальних комп’ютерах регістрова пам’ять є малою за розмірами та швидкою, працює на швидкості ядра процесора, загальна пам’ять є великою за розміром, але набагато повільніша за ядро процесора. Регістрова пам’ять підтримує лише пряму адресацію, загальна пам’ять підтримує декілька типів адресації. У СК є 8 регістрів по 24 розряди, пам’ять складається з 4096 слів по 32 розряди. У СК є спеціальний регістр – лічильник команд (programCounter), в якому зберігається адреса інструкції. За прийнятою домовленістю 0вий регістр завжди містить 0. В регістрі instReg міститься код інструкції, яка виконується. При роботі з пам’яттю (MEMORY) використовуються два регістри – в memAddress зберігається адреса пам’яті, а в memData значення, яке читається/записується в пам’ять. Комп’ютер містить арифметико-логічний пристрій (ALU), який може виконувати 6 дій (подані у таблиці нижче). ALU керується трьохрозрядним сигналом alu_op: Таблиця 1. Операції АЛП ALU працює з двома операндами, один з них завжди є в регістрі aluOperand, інший береться з головної шини (main bus), результат зберігається в регістрі aluReult. instReg – зберігає команду після її зчитування з основної пам’яті. RegisterFile – зберігає значення регістрів. Memory – пам’ять. memAddress – зберігає адресу комірки пам’яті. memData – зберігає значення для читання/запису в пам’ять. ProgramCounter – підраховує команди та зберігає адресу поточної команди. 2.3. Функціональна схема комп’ютера після модифікації Рис. 2.3. Функціональна схема спрощеного комп’ютера після модифікації. Згідно завдання було додано стек. Його глибина = 32 слова по 32 розярди, а також флажок нуля zf, що встановлюється в 1 при умові якщо 2 опернди на АЛП рівні між собою. Для стеку відведено свою пам’ять що можна буде побачити у репорті, він наповнюється і вивантажується за принципом FILO (як і всі стандартні стеки). Дані з шини, що беруться з пам’яті поступають у stackData і за операцією push заносяться до стеку на його вершину, а при операції pop, значення що лежить на вершині вивантажується з нього у stackData і потім поступає на шину даних.Всі коментарі та принципи роботи описані в коментарі до рисунку 4 залишаються незмінними. Було додано: zf – регістр ознаки нуля stack – стек. stackData – зберігає значення для запису в стек чи значення що зчитується з стеку при команді pop Сигнали push і pop служать для запису чи зчитування даних з стеку. 2.4. Множина інструкцій комп’ютера. Таблиця. 2.5. Опис форматів інструкцій розробленого комп’ютера Розроблена машина підтримує наступні формати: Інструкції R-типу (add, nand, idiv, shl, xand, or) Інструкції I-типу (lw, sw, beq, jma, jmne) Інструкції J-типу (jalr, bsr, cmp,neg) Інструкції O-типу (halt, noop) Окремо слід відзначити інструкцію JE – її не можна віднести до існуючих типів інструкції, оскільки вона містить інформацію тільки про код операції та зміщення І інструкцію DEC її не можна віднести до існуючих типів інструкції, оскільки вона містить інформацію тільки про код операції та 1 регістр А Також інструкції PUSH i POP – їx також не можна віднести до існуючих типів інструкції, вони містять інформацію про код операції та один регістр. 2.6. Опис виконання кожного типу інструкцій в по тактовому режимі R-тип: memAddress = programCounter; memData = MEMORY[memAddress]; instReg = memData; programCounter++; aluOperand = REGISTER FILE[arg1]; Decoding(instReg) -> operation, arg1, arg2, arg3; aluResult = ALU(aluOperand, REGISTER FILE[arg2], alu_op) REGISTER FILE[arg3] = aluResult; I-тип memAddress = programCounter; memData = MEMORY[memAddress]; instReg = memData; programCounter++; aluOperand = REGISTER FILE[arg1]; Decoding(instReg) -> operation, arg1, arg2, address; aluResult = ALU (REGISTER FILE[arg2], aluOperand, alu_op); MEMORY[address] = aluResult; (sw)(Або 8. programCounter += address, при виконаній умові; (jma, jmne)Або 8. REGISTER FILE[aluResult] = MEMORY[address]; (lw) J-тип memAddress = programCounter; memData = MEMORY[memAddress]; instReg = memData; programCounter++; aluOperand = REGISTER FILE[arg1]; Decoding(instReg) -> operation, arg1, arg2; 6.a zf = ALU (REGISTER FILE[arg2], aluOperand, alu_op) (cmp) 6.b aluResult = ALU (REGISTER FILE[arg2], aluOperand, alu_op); 7.b zf = у відповідний стан до відповіді чи знайшло «1» ; REGISTER FILE[arg2] = aluResult; (bsr) 6.c aluResult = ALU (zf, alu_op); 7.c programCounter = aluResult ; (je) O-тип memAddress = programCounter; memData = MEMORY[memAddress]; instReg = memData; programCounter++; Decoding(instReg) -> operation; Exit(0) – вихід з програми (halt) S-тип memAddress = programCounter; memData = MEMORY[memAddress]; instReg = memData; programCounter++; 5.a memAddress = instReg[address] 6.a memData = MEMORY[memAddress]; 7.a stackData = memData; 8.a stack.top = stackData; stack.top++; (push) 5.b memAddress = instReg[address]; 6.b stackData = stack.top; stack.top - -; 7.b memData = stackData; 8.b MEMORY[memAddress] = memData; (pop) Команда je memAddress = programCounter; memData = MEMORY[memAddress]; instReg = memData; programCounter++; Decoding(instReg) -> operation, address; programCounter ?= offset (в залежності від zf) Команда dec memAddress = programCounter; memData = MEMORY[memAddress]; instReg = memData; programCounter++; Decoding(instReg) -> operation, arg1; aluOperand = REGISTER FILE[arg1]; aluResult = ALU (aluOperand, alu_op); REGISTER FILE[arg1] = aluResult 3. ТЕСТОВИЙ РОЗДІЛ Див. додатки (тести програм) ВИСНОВОК Отже, для процесора комп’ютера із складною системою команд характерні наступні особливості: виконання команд за багато тактів; орієнтація АЛП на виконання великої кількості операцій, що пов’язано з розширеним складом системи команд. Складна конвеєризація виконання команд, що також пов’язано, в першу чергу, з різнотипністю їх виконання Орієнтація на команди типу регістр-пам’ять та пам’ять- пам’ять. Вказані особливості стимулюють побудову високопродуктивних комп’ютерів. В ході виконання курсової роботи був розроблений асемблер, який дозволяє переводити всі команди, які були подані, як вхідні дані у машинні інструкції, а також асемблер виконує всі перевірки, які потрібно виконувати згідно з завданням і у випадку помилки видає відповідне повідомлення. Правильність роботи асемблера була перевірена за допомогою спеціально розроблених тестів, які написані за допомогою мови асемблера. Ці тести перевіряють коректність роботи реалізованих команд і директив. Також був розроблений симулятор, який дозволяє дешифрувати всі машинні всі машинні інструкції, і згідно з командою виконати операцію, а також створюю звіт потактового виконання програми з виводом стану пам’яті і регістрів. Симулятор відповідає всім поставленим вимогам, робить перевірки на помилки і в разі їх виникнення виводить відповідне повідомлення. Також була розроблена система тестів, яка дозволила провести тестування коректності роботи симулятора. Система тестів була спрямована на виявлення помилок в розшифруванні машинних інструкцій, а також у виконанні команд. ВИКОРИСТАНА ЛІТЕРАТУРА Мельник А. О. Архітектура комп’ютера. Наукове видання. – Луцьк: Волинська обласна друкарня, 2008. – 470 с. Жмакин А. П. Архитектура ЭВМ. – СПб.: БХВ-Петербург, 2006. — 320 с:ил. Таненбаум Э. Архитектура компьютера. 5-е изд. (+CD). — СПб.: Питер, 2007. — 844 с: ил. Patterson D., and Hennessy J. Computer Architecture. A quantitative Approach. Second Edition. - Morgan Kaufmann Publishers, Inc., San Francisco, California, 1996. - 760 p. ДОДАТКИ Файли стимулятора і асемблера Asol.cpp /* Assembler for LC */ #pragma warning(disable:4996) #include <stdlib.h> #include <stdio.h> #include <string.h> #define MAXLINELENGTH 1000 #define MAXNUMLABELS 4096 #define MAXLABELLENGTH 7 /* includes the null character termination */ #define HALT 0 #define ADD 1 #define NAND 2 #define LW 3 #define SW 4 #define DEC 5 #define IDIV 6 #define XADD 7 #define SHL 8 #define OR 9 #define NEG 10 #define JMA 11 #define JMNE 12 #define CMP 13 #define BSR 14 #define PUSH 15 #define POP 16 #define SAND 17 #define SADD 18 #define JE 19 int readAndParse(FILE*, char*, char*, char*, char*, char*); int translateSymbol(char labelArray[MAXNUMLABELS][MAXLABELLENGTH], int labelAddress[MAXNUMLABELS], int, char*); int isNumber(char*); void testRegArg(char*, int address); 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 <assembly-code-file> <machine-code-file>\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; readAndParse(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, "halt") && strcmp(opcode, "dec") && strcmp(opcode, "idiv") && strcmp(opcode, "xadd") && strcmp(opcode, "shl") && strcmp(opcode, "or") && strcmp(opcode, "neg") && strcmp(opcode, "jma") && strcmp(opcode, "jmne") && strcmp(opcode, "cmp") && strcmp(opcode, "bsr") && strcmp(opcode, "je") && strcmp(opcode, "push") && strcmp(opcode, "pop") && strcmp(opcode, "sand") && strcmp(opcode, "sadd") && strcmp(opcode, ".fill") ) { printf("error: unrecognized opcode %s at address %d\n", opcode, address); exit(1); } /* check register fields */ if (strcmp(opcode, "halt") && strcmp(opcode, "sadd") && strcmp(opcode, "sand") && strcmp(opcode, ".fill") && strcmp(opcode, "push") && strcmp(opcode, "pop") && strcmp(opcode, "je")) { testRegArg(arg0, address); if(strcmp(opcode, "dec")){ testRegArg(arg1, address); if (strcmp(opcode, "jma") && strcmp(opcode, "jmne") && strcmp(opcode, "bsr") && strcmp(opcode, "cmp") && strcmp(opcode, "lw") && strcmp(opcode, "neg") && strcmp(opcode, "sw")) { testRegArg(arg2, address); } } } /* check addressField */ if (!strcmp(opcode, "lw") || !strcmp(opcode, "sw") || !strcmp(opcode, "jma") || !strcmp(opcode, "jmne")) { testAddrArg(arg2); } if (!strcmp(opcode, ".fill") || !strcmp(opcode, "je")) { testAddrArg(arg0); } /* check for enough arguments */ if ( (!strcmp(opcode, "idiv") || !strcmp(opcode, "xadd") || !strcmp(opcode, "shl") || !strcmp(opcode, "or") || !strcmp(opcode, "jma") || !strcmp(opcode, "jmne") || !strcmp(opcode, "add") || !strcmp(opcode, "nand") || !strcmp(opcode, "sw") || !strcmp(opcode, "lw") )&& arg2[0] == '\0' || (!strcmp(opcode, "bsr") || !strcmp(opcode, "cmp") || !strcmp(opcode, "neg")) && arg1[0] == '\0' || (!strcmp(opcode, "halt") || !strcmp(opcode, "dec") || !strcmp(opcode, "je") )&& 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 and numbers */ sscanf(label, "%[a-zA-Z0-9]", argTmp); if (strcmp(argTmp, label)) { printf("label has character other than letters and numbers\n"); exit(2); } /* look for duplicate label */ for (i = 0; i < numLabels; 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 < numLabels; 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; readAndParse(inFilePtr, label, opcode, arg0, arg1, arg2); address++) { if (!strcmp(opcode, "add")) { num = (ADD << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | atoi(arg2); } if (!strcmp(opcode, "nand")) { num = (NAND << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | atoi(arg2); } if (!strcmp(opcode, "idiv")) { num = (IDIV << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | atoi(arg2); } if (!strcmp(opcode, "xadd")) { num = (XADD << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | atoi(arg2); } if (!strcmp(opcode, "shl")) { num = (SHL << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | atoi(arg2); } if (!strcmp(opcode, "or")) { num = (OR << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | atoi(arg2); } if (!strcmp(opcode, "bsr")) { num = (BSR << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16); } if (!strcmp(opcode, "cmp")) { num = (CMP << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16); } if (!strcmp(opcode, "neg")) { num = (NEG << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16); } if (!strcmp(opcode, "dec")) { num = (DEC << 22) | (atoi(arg0) << 19); } if (!strcmp(opcode, "push")) { num = (PUSH << 22); } if (!strcmp(opcode, "pop")) { num = (POP << 22); } if (!strcmp(opcode, "sadd")) { num = (SADD << 22); } if (!strcmp(opcode, "sand")) { num = (SAND << 22); } else if (!strcmp(opcode, "halt")) { num = (HALT << 22); } else if (!strcmp(opcode, "lw") || !strcmp(opcode, "sw") || !strcmp(opcode, "jma") || !strcmp(opcode, "jmne") || !strcmp(opcode, "je")) { if (!strcmp(opcode, "lw") || !strcmp(opcode, "sw") || !strcmp(opcode, "jma") || !strcmp(opcode, "jmne")) { /* 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, "jma") || !strcmp(opcode, "jmne")) { addressField = addressField - address - 1; } } else { addressField = atoi(arg2); } } if (!strcmp(opcode, "je")) { addressField = translateSymbol(labelArray, labelAddress, numLabels, arg0); addressField = addressField - address - 1; } //if (addressField < -32656 || addressField > 32657) if (addressField < -2048 || addressField > 2048) { 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, "jma")) { num = (JMA << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | addressField; } if (!strcmp(opcode, "jmne")) { num = (JMNE << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | addressField; } if (!strcmp(opcode, "je")) { num = (JE << 22) | addressField; } if (!strcmp(opcode, "lw")) { num = (LW << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | addressField; } if (!strcmp(opcode, "sw")) { num = (SW << 22) | (atoi(arg0) << 19) | (atoi(arg1) << 16) | addressField; } } else if (!strcmp(opcode, ".fill")) { if (!isNumber(arg0)) { num = translateSymbol(labelArray, labelAddress, numLabels, arg0); } else { if (atol(arg0) <= -8388608 || atol(arg0) >= 8388607) { printf("Digit Overflow at line:%d", address); num = 0; } else { num = atoi(arg0); } } } /* printf("(address %d): %d (hex 0x%x)\n", address, num, num); */ fprintf(outFilePtr, "%d\n", num); } exit(0); } /* * Read and 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 readAndParse(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 < numLabels && strcmp(symbol, labelArray[i]); 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 and has no bad characters. */ void testRegArg(char* arg, int address) { int num; char c; if (atoi(arg) < 0 || atoi(arg) > 7) { printf("error: register out of range at address:%d\n", address); exit(2); } if (sscanf(arg, "%d%c", &num, &c) != 1) { printf("bad character in register argument at address:%d\n", address); 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); } } } Ssol.cpp /* * Instruction-level simulator for the LC */ #pragma warning(disable:4996) #include <stdio.h> #include <stdlib.h> #include <string.h> #include <stack> #include <math.h> #define NUMMEMORY 4096 /* maximum number of words in memory */ #define NUMREGS 8 /* number of machine registers */ #define MAXLINELENGTH 1000 #define HALT 0 #define ADD 1 #define NAND 2 #define LW 3 #define SW 4 #define DEC 5 #define IDIV 6 #define XADD 7 #define SHL 8 #define OR 9 #define NEG 10 #define JMA 11 #define JMNE 12 #define CMP 13 #define BSR 14 #define PUSH 15 #define POP 16 #define SAND 17 #define SADD 18 #define JE 19 #define MY_MIN -8388608 #define MY_MAX 8388607 typedef struct stateStruct { int pc; int mem[NUMMEMORY]; int reg[NUMREGS]; int numMemory; bool zf; std::stack<int> stack; } stateType; void printState(stateType*); void run(stateType); int convertNum(int); void showStack(std::stack <int> s); int main(int argc, char* argv[]) { int i; char line[MAXLINELENGTH]; stateType state; FILE* filePtr; if (argc != 2) { printf("error: usage: %s <machine-code file>\n", argv[0]); exit(1); } /* initialize memories and registers */ for (i = 0; i < NUMMEMORY; i++) { state.mem[i] = 0; } for (i = 0; i < NUMREGS; i++) { state.reg[i] = 0; } state.pc = 0; state.zf = false; /* read machine-code file into instruction/data memory (starting at address 0) */ filePtr = fopen(argv[1], "r"); if (filePtr == NULL) { printf("error: can't open file %s\n", argv[1]); perror("fopen"); exit(1); } for (state.numMemory = 0; fgets(line, MAXLINELENGTH, filePtr) != NULL; state.numMemory++) { if (state.numMemory >= NUMMEMORY) { printf("exceeded memory size\n"); exit(1); } if (sscanf(line, "%d", state.mem + state.numMemory) != 1) { printf("error in reading address %d\n", state.numMemory); exit(1); } printf("memory[%d]=%d\n", state.numMemory, state.mem[state.numMemory]); } printf("\n"); /* run never returns */ run(state); return (0); } void run(stateType state) { int arg0, arg1, arg2, addressField; int instructions = 0; int opcode; int maxMem = -1; /* highest memory address touched during run */ for (; 1; instructions++) { /* infinite loop, exits when it executes halt */ printState(&state); if (state.pc < 0 || state.pc >= NUMMEMORY) { printf("pc went out of the memory range\n"); exit(1); } maxMem = (state.pc > maxMem) ? state.pc : maxMem; /* this is to make the following code easier to read */ opcode = state.mem[state.pc] >> 22; arg0 = (state.mem[state.pc] >> 19) & 0x7; arg1 = (state.mem[state.pc] >> 16) & 0x7; arg2 = state.mem[state.pc] & 0x7; /* only for add, nand */ addressField = convertNum(state.mem[state.pc] & 0xFFF); /* for beq, lw, sw */ // printf("opcode = %d\n", opcode); // printf("state.reg[arg0] = %d\n", state.reg[arg0]); // printf("arg0 = %d\n", arg0); // printf("arg1 = %d\n", arg1); // printf("arg2 = %d\n", arg2); // printf("Adress field = %d\n", addressField); // // state.pc++; if (opcode == ADD) { if(long(state.reg[arg0]) + long(state.reg[arg1]) <= MY_MIN || long(state.reg[arg0]) + long(state.reg[arg1]) >= MY_MAX) { state.reg[arg2] = 0; printf("Digit Overflow in pc=%d\n", state.pc); } else { state.reg[arg2] = state.reg[arg0] + state.reg[arg1]; } } else if (opcode == NAND) { state.reg[arg2] = ~(state.reg[arg0] & state.reg[arg1]); } else if (opcode == LW) { if (state.reg[arg0] + addressField < 0 || state.reg[arg0] + addressField >= NUMMEMORY) { printf("Address out of bounds\n"); exit(1); } state.reg[arg1] = state.mem[state.reg[arg0] + addressField]; // printf("opcode = %d\n", opcode); // printf("state.reg[arg0] = %d\n", state.reg[arg0]); // printf("arg0 = %d\n", arg0); // printf("arg1 = %d\n", arg1); // printf("Adress field = %d\n", addressField); //printf("state.mem[state.reg[arg0] + addressField] = %d\n", arg0+addressField); if (state.reg[arg0] + addressField > maxMem) { maxMem = state.reg[arg0] + addressField; } } else if (opcode == SW) { if (state.reg[arg0] + addressField < 0 || state.reg[arg0] + addressField >= NUMMEMORY) { printf("Address out of bounds\n"); exit(1); } state.mem[state.reg[arg0] + addressField] = state.reg[arg1]; if (state.reg[arg0] + addressField > maxMem) { maxMem = state.reg[arg0] + addressField; } } else if (opcode == PUSH) { if (state.stack.size() > 32) { printf("Out of Stack\n"); exit(1); } state.stack.push(state.reg[1]); } else if (opcode == POP) { if(state.stack.empty()) { printf("Stack is Empty\n"); exit(1); } state.reg[1] = state.stack.top(); state.stack.pop(); } else if (opcode == HALT) { printf("machine halted\n"); printf("total of %d instructions executed\n", instructions + 1); printf("final state of machine:\n"); printState(&state); exit(0); } else if (opcode == IDIV) { if (long(state.reg[arg0]) / long(state.reg[arg1]) <= MY_MIN || long(state.reg[arg0]) / long(state.reg[arg1]) >= MY_MAX) { state.reg[arg2] = abs(state.reg[arg0] / state.reg[arg1]); } } else if (opcode == XADD) { state.reg[arg2] = state.reg[arg0] + state.reg[arg1]; const int temp = state.reg[arg0]; state.reg[arg0] = state.reg[arg1]; state.reg[arg1] = temp; } else if (opcode == SHL) { state.reg[arg2] = state.reg[arg0] << state.reg[arg1]; } else if (opcode == OR) { state.reg[arg2] = state.reg[arg0] | state.reg[arg1]; } else if (opcode == NEG) { state.reg[arg1] = -state.reg[arg0]; } else if (opcode == DEC) { state.reg[arg0] -= 1; } else if (opcode == JMA) { if (abs(state.reg[arg0]) > abs(state.reg[arg1])) { state.pc += addressField; } } else if (opcode == JMNE) { if (state.reg[arg0] != state.reg[arg1]) { state.pc += addressField; } } else if (opcode == BSR) { bool exist = false; for (int k = 23; k >= 0; k--) { if ((state.reg[arg0] & (1 << k)) >> k) { state.reg[arg1] = k; exist = true; break; } } state.zf = exist; } else if (opcode == CMP) { if (state.reg[arg0] == state.reg[arg1]){ state.zf = true; } else { state.zf = false; } } else if (opcode == JE) { if (!state.zf) { state.pc = addressField; } } else if (opcode == SADD) { if (state.stack.size() < 2) { printf("Error, Void Stack"); exit(3); } int temp = state.stack.top(); state.stack.pop(); if(long(temp) + long(state.stack.top()) <= MY_MIN || long(temp) + long(state.stack.top()) >= MY_MAX) { temp = 0; printf("Digit Overflow in pc=%d\n", state.pc); } else { temp += state.stack.top(); } state.stack.pop(); state.stack.push(temp); } else if (opcode == SAND) { if (state.stack.size() < 2) { printf("Error, Void Stack"); exit(3); } int temp = state.stack.top(); state.stack.pop(); temp = (temp & state.stack.top()); state.stack.pop(); state.stack.push(temp); } else { printf("error: illegal opcode 0x%x\n", opcode); exit(1); } state.reg[0] = 0; } } void printState(stateType* statePtr) { int i; printf("\n@@@\nstate:\n"); printf("\tpc %d\n", statePtr->pc); printf("\tnext instruction %d\n", statePtr->mem[statePtr->pc] >> 24); printf("\tmemory:\n"); for (i = 0; i < statePtr->numMemory; i++) { printf("\t\tmem[ %d ] %d\n", i, statePtr->mem[i]); } printf("\tregisters:\n"); for (i = 0; i < NUMREGS; i++) { printf("\t\treg[ %d ] %d\n", i, statePtr->reg[i]); } printf("\tstack:\n"); showStack(statePtr->stack); printf("\tzf %d\n", statePtr->zf); printf("end state\n"); } int convertNum(int num) { /* convert a 16-bit number into a 32-bit Sun integer */ if (num & (1 << 15)) { num -= (1 << 16); } return (num); } void showStack(std::stack <int> s) { while (!s.empty()) { printf("\t\t%d\n", s.top()); s.pop(); } } Тести програм Програма ADD lw 0 1 res lw 0 2 arg start add 1 2 2 halt arg .fill 25 res .fill 10 ----------------------------- memory[0]=790533 memory[1]=794628 memory[2]=303106 memory[3]=0 memory[4]=25 memory[5]=10 … machine halted total of 4 instructions executed final state of machine: @@@ state: pc 4 next instruction 0 memory: mem[ 0 ] 790533 mem[ 1 ] 794628 mem[ 2 ] 303106 mem[ 3 ] 0 mem[ 4 ] 25 mem[ 5 ] 10 registers: reg[ 0 ] 0 reg[ 1 ] 10 reg[ 2 ] 35 reg[ 3 ] 0 reg[ 4 ] 0 reg[ 5 ] 0 reg[ 6 ] 0 reg[ 7 ] 0 stack: zf 0 end state Програма OR lw 0 1 a1 lw 0 2 a2 start or 1 2 3 halt a1 .fill 53 110101 a2 .fill 51 110011 res .fill 0 110111 =55 ----------------------------- machine halted total of 4 instructions executed final state of machine: @@@ state: pc 4 next instruction 0 memory: mem[ 0 ] 790532 mem[ 1 ] 794629 mem[ 2 ] 2400259 mem[ 3 ] 0 mem[ 4 ] 53 mem[ 5 ] 51 mem[ 6 ] 0 registers: reg[ 0 ] 0 reg[ 1 ] 53 reg[ 2 ] 51 reg[ 3 ] 55 reg[ 4 ] 0 reg[ 5 ] 0 reg[ 6 ] 0 reg[ 7 ] 0 stack: zf 0 end stateПрограма IDIV та SW lw 0 1 a1 lw 0 2 a2 start idiv 1 2 3 sw 0 3 res halt a1 .fill -10 a2 .fill 2 res .fill 0 ----------------------------- memory[0]=790533 memory[1]=794630 memory[2]=1613827 memory[3]=1060871 memory[4]=0 memory[5]=-10 memory[6]=2 memory[7]=0 … machine halted total of 5 instructions executed final state of machine: @@@ state: pc 5 next instruction -1 memory: mem[ 0 ] 790533 mem[ 1 ] 794630 mem[ 2 ] 1613827 mem[ 3 ] 1060871 mem[ 4 ] 0 mem[ 5 ] -10 mem[ 6 ] 2 mem[ 7 ] -5 registers: reg[ 0 ] 0 reg[ 1 ] -10 reg[ 2 ] 2 reg[ 3 ] -5 reg[ 4 ] 0 reg[ 5 ] 0 reg[ 6 ] 0 reg[ 7 ] 0 stack: zf 0 end state Програма XADD lw 0 1 a1 lw 0 2 a2 start xadd 1 2 3 halt a1 .fill -10 a2 .fill 2 res .fill 0 ----------------------------- memory[0]=790532 memory[1]=794629 memory[2]=1875971 memory[3]=0 memory[4]=-10 memory[5]=2 memory[6]=0 … machine halted total of 4 instructions executed final state of machine: @@@ state: pc 4 next instruction -1 memory: mem[ 0 ] 790532 mem[ 1 ] 794629 mem[ 2 ] 1875971 mem[ 3 ] 0 mem[ 4 ] -10 mem[ 5 ] 2 mem[ 6 ] 0 registers: reg[ 0 ] 0 reg[ 1 ] 2 reg[ 2 ] -10 reg[ 3 ] -8 reg[ 4 ] 0 reg[ 5 ] 0 reg[ 6 ] 0 reg[ 7 ] 0 stack: zf 0 end stateПрограма SHL та NEG lw 0 1 a1 lw 0 2 a2 start shl 1 2 3 neg 3 4 halt a1 .fill 10 a2 .fill 2 res .fill 0 ----------------------------- memory[0]=790533 memory[1]=794630 memory[2]=2138115 memory[3]=2736128 memory[4]=0 memory[5]=10 memory[6]=2 memory[7]=0 … machine halted total of 5 instructions executed final state of machine: @@@ state: pc 5 next instruction 0 memory: mem[ 0 ] 790533 mem[ 1 ] 794630 mem[ 2 ] 2138115 mem[ 3 ] 2736128 mem[ 4 ] 0 mem[ 5 ] 10 mem[ 6 ] 2 mem[ 7 ] 0 registers: reg[ 0 ] 0 reg[ 1 ] 10 reg[ 2 ] 2 reg[ 3 ] 40 reg[ 4 ] -40 reg[ 5 ] 0 reg[ 6 ] 0 reg[ 7 ] 0 stack: zf 0 end stateПрограма стекових операцій push a1 push a2 sand push a2 sadd pop res halt a1 .fill 22 10110 a2 .fill 5 00101 res .fill 0 00100 ----------------------------- memory[0]=3932167 memory[1]=3932168 memory[2]=4456448 memory[3]=3932168 memory[4]=4718592 memory[5]=4194313 memory[6]=0 memory[7]=22 memory[8]=5 memory[9]=0 … machine halted total of 7 instructions executed final state of machine: @@@ state: pc 7 next instruction 0 memory: mem[ 0 ] 3932167 mem[ 1 ] 3932168 mem[ 2 ] 4456448 mem[ 3 ] 3932168 mem[ 4 ] 4718592 mem[ 5 ] 4194313 mem[ 6 ] 0 mem[ 7 ] 22 mem[ 8 ] 5 mem[ 9 ] 0 registers: reg[ 0 ] 0 reg[ 1 ] 9 reg[ 2 ] 0 reg[ 3 ] 0 reg[ 4 ] 0 reg[ 5 ] 0 reg[ 6 ] 0 reg[ 7 ] 0 stack: zf 0 end state Програма BSR lw 0 1 a1 start bsr 1 2 halt a1 .fill 64039 ----------------------------- machine halted total of 3 instructions executed final state of machine: @@@ state: pc 3 next instruction 0 memory: mem[ 0 ] 790531 mem[ 1 ] 3710976 mem[ 2 ] 0 mem[ 3 ] 64039 registers: reg[ 0 ] 0 reg[ 1 ] 64039 reg[ 2 ] 15 reg[ 3 ] 0 reg[ 4 ] 0 reg[ 5 ] 0 reg[ 6 ] 0 reg[ 7 ] 0 stack: zf 1 end stateПрограма zf та je (ітераційний цикл) lw 0 1 i lw 0 2 end lw 0 3 res start add 3 1 3 cmp 1 2 dec 1 je start halt i .fill 5 end .fill 0 res .fill 0 ----------------------------- machine halted total of 28 instructions executed final state of machine: @@@ state: pc 8 next instruction 0 memory: mem[ 0 ] 790536 mem[ 1 ] 794633 mem[ 2 ] 798730 mem[ 3 ] 364547 mem[ 4 ] 3448832 mem[ 5 ] 1343488 mem[ 6 ] 4980739 mem[ 7 ] 0 mem[ 8 ] 5 mem[ 9 ] 0 mem[ 10 ] 0 registers: reg[ 0 ] 0 reg[ 1 ] -1 reg[ 2 ] 0 reg[ 3 ] 15 reg[ 4 ] 0 reg[ 5 ] 0 reg[ 6 ] 0 reg[ 7 ] 0 stack: zf 1 end state
Допоможи студентському архіву

Ми допомогли тобі — допоможи наступному студенту

Файл ще не обрано

Оголошення від адміністратора

Антиботан аватар за замовчуванням

Подякувати Студентському архіву довільною сумою

Admin

26.02.2023 12:38

Дякуємо, що користуєтесь нашим архівом!