Разработка программной эмуляции процессора

Рассмотрение принципа работы процессора и его практической реализации с использованием языка описания аппаратуры Verilog. Проектирование системы команд процессора. Выбор размера массива постоянной памяти. Подключение счетчика инструкций и файла регистра.

Рубрика Программирование, компьютеры и кибернетика
Вид курсовая работа
Язык русский
Дата добавления 26.05.2022
Размер файла 1,2 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

Институт КСИБ

Кафедра Информатики и вычислительной техники

Направление подготовки 09.03.01 Информатика и вычислит. техника

Профиль ЭВМ, комплексы, системы и сети

курсовая работа

по дисциплине ЭВМ и периферийные устройства

на тему: «Разработка программной эмуляции процессора»

Выполнил(-а) студент(-ка) Зосимов М.А.

курса 2 группы 20-КБ-ИВ1

Руководитель (нормоконтролер)

работы Атрощенко В.А.

Реферат

Курсовая работа: 39 с., 3 рис., 2 табл., 5 источников, 2 прил.

ЦЕНТРАЛЬНЫЙ ПРОЦЕССОР, КОМАНДА, АДРЕС, НЕПОСРЕДСТВЕННАЯ АДРЕСАЦИЯ, РЕГИСТРОВАЯ АДРЕСАЦИЯ, ПРЯМАЯ АДРЕСАЦИЯ, ПРЕВЫВАНИЕ, СЛОЖЕНИЕ, СДВИГ, ИНВЕРСИЯ

В данной курсовой работе рассматривается принцип работы процессора и его практическая реализация с использованием языка описания аппаратуры Verilog согласно заданному варианту.

Объект исследования - центральный процессор.

Цель работы - разработать программную реализацию заданного процессора, используя язык описания аппаратуры.

Вариант задания:

Содержание

процессор язык файл массив

Введение

1. Устройство центрального процессора

1.1 Память инструкций и счетчик команд

1.2 Память данных

1.3 Файл регистров

2. Проектирование системы команд процессора

2.1 Команды ассемблера

2.2 Команды типа R-type (register type)

2.3 Команды типа I-type (immediate type)

2.4 Счетчик команд

2.5 Файл регистров

3. Выбор размера массива постоянной памяти

3.1 Память данных

3.2 Память инструкций

4. Процесс обработки команд в процессоре

4.1 Шина данных и контроллер

4.2 Подключение счетчика инструкций

4.2 Подключение файла регистров

4.3 Разбор команд (контроллер)

4.4 Выполнение команд (шина данных)

5. Верхний уровень проекта

Заключение

Список используемой литературы

Приложение. Листинг

Приложение. Проверка на антиплагиат

Введение

В курсовой работе по дисциплине «ЭВМ и периферийные устройства» целью является освоение основных принципов, положенных в основу работы центральных процессорных устройств (ЦПУ), и получение представления о принципах обработки и выполнения команд процессором.

В современном мире трудно найти область техники, где не применялись бы микропроцессоры.

В микропроцессорах - наиболее сложных микроэлектронных устройствах - воплощены самые передовые достижения инженерной мысли. В условиях свойственной данной отрасли производства жесткой конкуренции и огромных капиталовложений выпуск каждой новой модели микропроцессора, так или иначе, связан с очередным научным, конструкторским, технологическим прорывом.

В курсовой работе основные задачи освоить основные элементы архитектуры процессора на примере процессора MIPS, понять язык ассемблер и конвертацию его в машинный код процессора, углубить знания в области дисциплины «ЭВМ и периферийные устройства.

1. Устройство центрального процессора

Центральный процессор - это основной рабочий компонент компьютера, основная задача которого выполнение программы, находящейся в основной памяти.

Процессор вызывает команды из памяти, определяет их тип, затем выполняет их одну за другой.

Компоненты процессора соединены шиной, которая представляет собой набор параллельных дорожек печатной платы процессора и по которым передаются адреса, данные и сигналы управления.

Шины могут быть внешними (связывающими процессор с памятью и устройствами ввода-вывода) и внутренними.

Архитектура процессора в целом определяется тремя основными блоками:

- арифметико-логическим устройством (АЛУ);

- памятью (набором регистров);

- блоком управления по командам ассемблера.

Для работы процессора необходимы память инструкций (instruction memory) и память данных (data memory), а также адрес текущей выполняемой инструкции, которую контролирует счетчик программы (program counter - pc). Общая схема работы процессора представлена на рисунке 1.

Рис. 1 Общая схема работы процессора

На каждый такт процессора из памяти инструкций берется инструкция с адресом pc, далее в зависимости от типа инструкции и ее параметров данные берутся из файла регистров и/или из памяти данных. С этими данными выполняются соответствующие действия, и они отправляются обратно в файл регистров и/или в память данных и меняют значение счетчика команд рс. Таким образом, текущее состояние процессора определено значениями, записанными в файл регистров, память данных и счетчик команд, а логика перехода между различными состояниями процессора определена командами, выбранными из памяти инструкций.

1.1 Память инструкций и счетчик команд

Память инструкций (instruction memory) адресуемая область памяти, хранящая последовательность команд, которые одну за другой выполняет процессор. Адресуемая память означает, что каждое 32-битовое слово (word) в этой области, состоящее из четырех байтов, имеет свой порядковый номер, т.е. адрес. Для 32-битовой архитектуры длина адреса определяется также 32 битами (4 байта). Следовательно, память инструкций может содержать максимально 232 адресов памяти.

Счетчик программы (program counter pc) содержит 32-битный адрес команды, которую выполняет процессор в текущем такте работы. Поскольку каждая команда занимает 4 байта, то корректными значениями счетчика программы могут быть только адреса, которые кратны 4. Такая адресация слов позволяет обеспечить адресацию составляющих эти слова байтов.

1.2 Память данных

Память данных (data memory) - это адресуемая область памяти, хранящая произвольные данные, которыми может оперировать процессор во время выполнения программы. Аналогично памяти инструкций длина адреса для 32-битной архитектуры составляет 32 бита, т.е. программа может адресовать максимум 232 адресов памяти данных. Байты также логически организованы в слова по 4 байта на слово (для 32-битной архитектуры). Тогда на физическом уровне объем памяти для 32 битных слов составит массив размером 232 х 32 бит.

1.3 Файл регистров

Файл регистров (register file) часть памяти процессора MIPS32 с массивом 32x32 бита (разрядность может быть другой). Каждый регистр файла регистров содержит 32 бита информации и может иметь свой индивидуальный адрес от 0 до 31. Таким образом, количество адресов файла регистров равно 25 = 32, а длина адреса каждого регистра составляет 5 бит информации. При этом для удобства регистры разбиты на группы, а также имеют символьные имена и конкретные назначения, что отражено в таблице 1.

Память регистров (в отличие от памяти данных) доступна процессорному блоку непосредственно и располагается с ним на одном кристалле, поэтому операции с регистрами выполняются быстро, но их количество ограничено. Исходя из этих ограничений, работа с регистрами обычно осуществляется по следующей схеме: данные загружаются в один или несколько регистров из памяти инструкций или внешней памяти, процессор выполняет с ними необходимые операции и отправляет результат обратно во внешнюю память или в файл регистров, но никогда в память инструкций.

Таблица 1

Регистры процессора MIPS32

Название

Номер

Назначение

$0

0

константа 0 (только чтение)

$at

1

временная ассемблера

$v0-$v1

23

возвращаемые значения процедур

$a0-$a3

47

аргументы процедур

$t0-$t7

815

временные переменные

$s0-$s7

1623

сохраненные переменные

$t8-$t9

2425

временные переменные

$k0-$k1

2627

временные значения операционной системы

$gp

28

глобальный указатель

$sp

29

указатель стека

$fp

30

указатель стекового кадра (stack frame)

$ra

31

адрес возврата процедуры

В программе, написанной в данной курсовой работы предусмотрено использование следующих регистров: $0, $t0-$t7, $s0-$s7. Адреса этих регистров приведены в таблице 2. При необходимости двоичные значения для остальных регистров легко вычислить самостоятельно, применив недостающие комбинации пятиразрядного кода.

Таблица 2

Двоичные индексы используемых регистров процессора MIPS32 в работе

Регистр

Адрес

$0

00000

$s0

10000

$s1

10001

$s2

10010

$s3

10011

$s4

10100

$s5

10101

$s6

10110

2. Проектирование системы команд процессора

2.1 Команды ассемблера

Язык ассемблер это самый низкоуровневый язык программирования. По сути, это представленный в удобном для чтения человеком вид машинного кода, с которым работает процессор. Каждая команда ассемблера имеет однозначное представление в машинном коде, и наоборот любую команду, записанную машинным кодом, можно легко перевести в читаемый вид на ассемблере.

Для каждого процессора язык ассемблера свой. В ассемблере набор команд подобран таким образом, чтобы все их многообразие можно было однозначно закодировать всеми возможными комбинациями значений доступных 32 бит (для 32-битного процессора) как код машинной команды. При этом с помощью этого набора можно было эффективно выполнять программы, транслируемые в ассемблер компиляторами высокоуровневых языков программирования (типа С или С++). Выполнить этот подбор задача архитекторов процессора.

Набор и структура команд, которые использованы при реализации процессора, выбраны и реализованы таким образом как посчитали возможным инженеры и архитекторы MIPS Technologies. Команды с архитектур других процессоров могут решать эту же задачу другим образом. Для каждой из архитектур есть свои причины использования команд ассемблера: инженерные, технологические, коммерческие и другие.

Реализация команд 32-битного процессора MIPS, которые будут использоваться в работе:

- add (сложение);

- lw (загрузка значения из памяти данных);

- sw (сохранение значения в память данных);

- addi (сложение с константой);

- subi (условный переход);

Команды ассемблера процессора MIPS разбиты на группы по типу используемых ими параметров операндов. Машинный код каждой команды вместе с адресами операнд занимает 32 бита (для 32-битной архитектуры MIPS).

2.2 Команды типа R-type (register type)

Команды типа R-type имеют 3 операнда, все операнды это адреса регистров: два регистра источники данных для выполнения команды, один регистр - результат выполненной команды.

Регистровая команда add

Эта команда складывает значения двух регистров и помещает результат в третий регистр.

Синтаксис на ассемблере выглядит так:

add rd, rs, rt

rd, rs, rt адреса регистров. Команда add берет значения из регистров rs и rt, адреса которых указаны в команде; вычисляет сумму этих регистров и записывает результат в регистр rd по указанному адресу в команде.

В архитектуре процессора MIPS эта команда имеет вид:

add $s0, $s1, $s2

Для архитектуры процессора это будет выглядеть как операция $s0=$s1+$s2, вычисляющая сумму значений, хранящихся в регистрах $s1 и $s2, и результат, записанный в регистр $s0.

В машинном коде команды типа R-type разбиты по битам на следующие поля:

[ op] [ rs] [ rt] [ rd] [shamt] [ funct]

(6 бит) (5 бит) (5 бит) (5 бит) (5 бит) (6 бит)

Поля op и funct - это поля операций, причем поле op (opcode) = 0 для всех операций для R-type, а поле funct (function): для команды add=32, для команды sub=34.

Поля rs, rt, rd это адреса регистров операндов соответствующих команд.

Поля rs, rt - поля адресов источников операндов (rs - источник 1, rt - источник 2). Обозначение выбрано следующим образом: символ r - register, символ s - source (источник), а символ t следует в алфавите после символа s.

Поле rd - поле результата или назначение (destination), поэтому в rd символ d.

Поле shamt - определяющее сдвиг битов в адресах

(amount of shift) = 0 для всех операций типа R-type.

2.3 Команды типа I-type (immediate type)

Команды типа I-type в отличие от команд типа R-type умеют работать с числовыми константами (immediates - незамедлительные значения, т.е. их не нужно ниоткуда получать), которые встроены непосредственно в код команды.

Из рассматриваемого списка команд к таковым относятся:

lw, sw, addi, beq

Команда lw (load word загрузить слово) загружает значение слова из памяти данных в регистр.

Синтаксис на ассемблере:

lw rt, imm (rb),

где rt адрес регистра назначения, imm - константа, формирующая адрес загружаемого значения из памяти, rb базовый адрес регистра, содержащего значение, относительно которого осуществляется сдвиг на значение константы для формируемого адреса загрузки из памяти.

В архитектуре процессора MIPS эта команда имеет вид:

lw $s0, 4 ($0),

которая вычисляет адрес загружаемого значения в регистр s0, взятого из памяти по адресу (4+0=4), где 4 - это константа imm, а 0 - это адрес базового регистра (в нашем случае в качестве базового регистра используется нулевой регистр, который имеет адрес 0).

Команда sw (store word сохранить слово) сохраняет значение из регистра в память данных за счет записи этого значения.

Синтаксис на ассемблере:

sw rt, imm (rb)

rt адрес регистра-источника откуда будет записываться информация, imm - константа, формирующая адрес сохранения значения в памяти, rb - адрес базового регистра, относительно которого формируется адрес сохранения в памяти.

В архитектуре процессора MIPS команда сохранения слова имеет вид:

sw $s0, 4 ($0),

она вычисляет адрес сохранения значения из регистра s0 в память процессора по адресу (4+0=4), где 4 это - константа imm, а 0 - это адрес базового регистра (в качестве базового регистра используется нулевой регистр, который всегда имеет адрес 0).

Команда addi (add immediate сложить с константой) складывает значение регистра с константой и записывает результат в регистр.

Синтаксис на ассемблере:

addi rt, rs, imm

rt адрес регистра-назначения, rs адрес регистра источника, содержащего первое слагаемое, imm константа - второе слагаемое.

Команда addi должна взять значения из регистра rs, вычислить сумму данных регистра rs и числа imm (rs+imm) и записать этот результат в регистр rt.

В архитектуре процессора MIPS эта команда сложения с константой имеет вид:

addi $s0, $s1, 4,

она вычисляет следующую сумму: $s1+4 = $s0 и записывает результат в регистр $s0.

Команда beq (branch if equal ветвление, если равно) осуществляет условный переход по значению адреса счетчика программы в указанное место при выполнении определенного условия.

В обычной ситуации процессор выполняет программу строка за строкой. Этот механизм реализован при помощи счетчика программы (program counter - pc): на каждый такт процессор выбирает из памяти инструкций команду, адрес которой хранит счетчик программы, после ее выполнения счетчик программы увеличивает значение адреса на одну команду и на следующем такте процессор выберет для выполнения команду, которая в памяти инструкций следует за текущей. Так может продолжаться до тех пор, пока не закончится память инструкций.

Команды перехода (в данном случае условного) позволяют нарушить последовательный ход программы и на следующем такте процессора выполнять команду, не следующую за текущей, а выбрать команду в указанном адресе памяти инструкций. Для этого достаточно установить нужное значение в счетчик программы (pc).

При помощи команды условного перехода beq можно организовывать циклы и блоки проверки условий.

Синтаксис такой команды на ассемблере:

beq rs, rt, target

rs, rt адреса регистров, значения которых сравнивает команда;

target - (цель) адрес перехода относительно текущей инструкции.

Адрес перехода target задается при помощи специальных меток символьных имен, которые можно назначить на любую строку в ассемблерной программе.

В архитектуре процессора MIPS команда условногоперехода может иметь вид:

label: addi $s0, $0, 4

beq $s0, $s1, label,

она сравнит значения регистров s0 и s1 и передаст управление инструкции, адрес которой в памяти инструкций помечен меткой label, если значения равны (в данном примере это команда на одну строку выше команды перехода beq); если значения не равны, то программа продолжит последовательное выполнение команд со следующей строки программы.

В машинном коде эти инструкции выглядят следующим образом:

[ op] [ rs] [ rt] [ imm]

(6 бит) (5 бит) (5 бит) (16 бит)

op код операции, который имеет следующие значения: для lw=35, для sw=43, для addi=8, для beq=4.

rs, rt адреса регистров-операндов,

target (цель) - метка, устанавливаемая на адрес перехода.

Система команд процессора приведена в таблице 3.

Таблица 3

Система команд процессора

Код операции (6b)

Мнемоника

Содержание

100000

add

сложение

100011

lw

загрузка значения из памяти данных

101011

sw

сохранение значения в память данных

001000

addi

сложение с константой

000100

beq

условный переход

Пример реализации эмуляции процессора MIPS32 в среде Quartus II

Разработка процессора MIPS осуществляется на языке Verilog, в котором использованы понятия процессора, языка ассемблера и системы реализованных команд. Язык SystemVerilog обеспечивает описания аппаратуры процессора.

Проект процессора будет состоять из пяти модулей, написанных на языке SystemVerilog, Сначала требуется создать эти модули, а затем перейти к его верхнему схемному уровню процессора. В приложении Е приведены основные операторы языка SystemVerilog и приоритет их выполнения. Приложение Ж содержит примеры обозначения чисел (констант) на языке SystemVerilog.

Основные модули, которые определяют текущее состояние системы это счетчик команд (program counter), файл регистров (register file), память инструкций (instruction memory) и память данных (data memory).

Далее эти модули соединяются между собой центральной логикой работы процессора, в рамках которой реализованы механизмы разбора потока ассемблерных команд из памяти инструкций и логика их исполнения с помощью модуля шины данных и контроллера (datapath_and_controller). Каждая команда в момент выполнения будет влиять на один или несколько перечисленных модулей одновременно, изменяя счетчик программы, файл регистров и память данных.

На каждый такт периодического сигнала Clock процессор выбирает ровно одну команду из памяти инструкций и в этом же такте исполняет ее.

Проект будет состоять из следующих программных модулей:

- pc.v - счетчик команд;

- regfile.v - файл регистров;

- datapath_and_controller.v модуль основной логики (шина данных и контроллер);

- datamem.v память данных;

- instrmem.v - память инструкций;

- Processor.bdf - схема верхнего уровня, осуществляющая соединение всех модулей.

2.4 Счетчик команд

Программный модуль счетчика команд (program counter) позволяет установить следующее значение счетчика программы на каждый такт синхросигнала.

На вход этого элемента поступает 1 бит тактового сигнала clk (Clock) и 32-битное следующее значение счетчика программы pc' (program counter next pc_next). По переднему фронту сигнала clk 32-битное текущее значение счетчика команд pc (program counter) меняется на следующее значение выхода счетчика команд pc'. Такое изменение счетчика команд pc происходит на каждом такте синхронизирующего сигнала clk.

Код программы на языке Verilog реализует именно эту логику работы счетчика команд. В коде программы /* означают комментарии программы, поясняющие действия её команд и операндов.

pc.v

/**

* Счетчик программы - переход на следующее значение на каждый такт.

* @param clk - тактовый сигнал clock

* @param pc_next - следующее значение для счетчика программы (program counter)

* @param pc - текуще значение счетчика программы (program counter)

*/

module pc

(input clk,input [31:0] pc_next, output reg [31:0] pc);

always @(posedge clk) /*всегда выполнять по переднему фронту

pc <= pc_next;/* счетчику программ присваивать новое значение

endmodule

2.5 Файл регистров

Программный модуль файл регистров (register file) хранит значения внутренних регистров процессора и позволяет получать 32-битное значение регистра по пятибитному адресу, а также делать запись 32-битного значения в регистр файла регистров по пятибитному адресу.

Модуль может обеспечивать чтение значений до двух регистров одновременно, а запись выполнять только в один регистр за один такт сигнала Clock.

Весь код модуля выглядит следующим образом:

regfile.v

module regfile(input clk,

/* Чтение 2х регистров */

input [4:0] ra1, input [4:0] ra2,

output [31:0] rd1, output [31:0] rd2,

/* Запись в регистр */

input we, input [4:0] wa, input [31:0] wd);

reg [31:0] rf [31:0];

always @(posedge clk)

if(we) rf[wa] <= wd;/*если we=1 записать данные wd по адресу регистра wa/*

assign rd1 = ra1 ? rf[ra1]: 0;/* reg[0] всегда ноль*/

assign rd2 = ra2 ? rf[ra2]: 0;/* reg[0] всегда ноль*/

endmodule

В программном коде выше описаны следующие параметры:

Для операций чтения

Входы:

ra1 адрес чтения (read address) регистра-источника 1 5 бит;

ra2 адрес чтения (read address) регистра-источника 2 5 бит.

Выходы:

rd1 считываемые данные (read data) регистра-источника 1 32 бит;

rd2 считываемые данные (read data) регистра-источника 2 32 бит.

Для операций записи

Входы:

clk тактовый сигнал clock запись в регистр-назначение осуществляется на каждый тактовый сигнал при включенном флаге write enabled (we =1);

we флаг разрешения записи (write enabled);

wa адрес записи (write address) регистра-назначения 5 бит;

wd записываемые данные для (write data) регистра-назначения 32 бит.

Для хранения данных файла регистра используется массив размером 32 x 32 бит (адресов 25 = 32 бита, размер слов 32 бита) и команда программы reg [31:0] rf [31:0].

Операция записи данных wd (write data) в регистр по адресу wa (write address) на каждый такт сигнала clk (clock) производится, если флаг we (write enabled) равен 1 по следующим командам ранее приведенной программы.

always @(posedge clk)

if(we) rf[wa] <= wd;

Операция чтения из двух регистров производится по адресам ra1 и ra2. Значения считываемых из регистров данных появляются на выходах модуля rd1 и rd2 в момент присвоения значений адресов входам ra1 и ra2 с появлением тактового сигнала clock. Для регистра по адресу 0 всегда возвращается значение 0 (в регистре $0 всегда находится константа ноль), что показано во фрагменте приведенной ранее программы:

assign rd1 = ra1 ? rf[ra1]: 0; // reg[0] всегда ноль

assign rd2 = ra2 ? rf[ra2]: 0; // reg[0] всегда ноль

3. Выбор размера массива постоянной памяти.

3.1 Память данных

Программный модуль памяти данных (data memory) RAM (random access memory) представляет собой запоминающее устройство с произвольным доступом на чтение и запись. Память адресуется

32-битным указателем 232 бит = 4096 Мегабайт. Организована память

32-битными словами по 4 байта каждый, загрузка и сохранение осуществляется также словами, состоящими из 4 байт. Таким образом, полный объем памяти составляет 1 073 741 824 бит в доступном адресном пространстве.

datamem.v

/**

* Память данных.

* @param clk - clock

* @param we - флаг разрешения записи (write enabled)

* @param addr - адрес доступа на чтение/запись (address)

* @param wd - записываемые данные (write data)

* @param rd - считанные данные (read data)

*/

module datamem_plain (input clk,input we, input [31:0] addr,

input [31:0] wd, output [31:0] rd);

// массив памяти данных

reg [31:0] RAM [63:0];

// запись данных в RAM если флаг we (write enabled) равен '1'

always @(posedge clk)

if(we) RAM[addr[31:2]] <= wd;

// чтение данных из RAM

// выравнивание слов по байтам (word aligned) - деление кода дреса addr на 4// (просто отбросить 2 последних бита)

assign rd = RAM[addr[31:2]];

endmodule

Массив 32-битных слов с N-адресами - это доступная физическая память. N = 1 073 741 824 - количество бит, выделенных для памяти; но такого объема памяти для реальных физических устройств ПЛИС не хватит. Поэтому можно взять вентилей столько, сколько потребуется программе. В данном случае примем N = 63, поэтому фрагмент ранее приведенной программы имеет вид:

// массив памяти данных

reg [31:0] RAM [63:0];

Чтение и запись данных в память RAM происходит по каждому такту импульса clock:

- запись при условии, если флаг we (write enabled) равен 1;

- чтение происходит по факту присвоения нового значения адреса входу с addr.

При работе с адресом происходит выравнивание памяти по словам (word aligned): для обращения к 4-байтовому слову по адресу байта адрес addr требуется поделить на 4 (т.е. сдвинуть код адреса вправо на 2 бита, что соответствует выражению «Отбросить 2 последних бита»).

Фрагмент кода ранее приведенной программы имеет вид

// запись данных в RAM если флаг we (write enabled) равен '1' always @(posedge clk)

if(we)RAM[addr[31:2]] <= wd;

// чтение данных из RAM

assign rd = RAM[addr[31:2]];

3.2 Память инструкций

Программный модуль памяти инструкций (instruction memory) ROM (read-only memory) - это память, доступная только для чтения. По логике адресации полная аналогия с памятью данных: 32-битный адрес, 32-битные слова с выравниванием по 4 байта. Главное отличие от модуля памяти данных это отсутствие интерфейса записи.

Как и в случае с модулем памяти данных, код программы будет считываться непосредственно из модуля Verilog. Он представлен в виде двоичных констант с заранее определенными адресами: одна инструкция одно 4-х байтное слово. Для этого предварительно код программы на ассемблере необходимо вручную перевести в двоичный вид по разбиению, которое было приведено в разделе настоящих методических указаний 6.2.

Например, для такой ассемблерной программы, состоящей из двух строк

addi $s0, $0, b0000000011111111

sw $s0, 0xf000 ($0)

модуль памяти инструкций на языке Verilog будет выглядеть следующим образом:

instrmem.v

module instrmem (

/* адрес чтения инструкции */

input [31:0] addr,

/* значение инструкции */

output reg [31:0] instr);

always @ (addr)

case (addr)

32'h00000000: instr <= 32'b100011_00000_10000_0000000000000000; // lw $s0, 0 ($0)

32'h00000004: instr <= 32'b001000_10000_10001_0000000000010010; // addi $s1, $s0, 18

32'h00000008: instr <= 32'b100111_10001_10010_0000000000001001; //subi $s2, $s1, 9

32'h0000000C: instr <= 32'b101011_00000_10010_0000000000000100; //sw $s2,4($0)

32'h00000010: instr <= 32'b000010_00000000000000000000000000; //j 0

default: instr <= 0;

endcase

endmodule

//lw слова 0

//прибавить к нему 18 addi

//вычесть из него 9 subi

//sw по адресу 4

//j перейти в начало

//lw $s0, 0($0)

//addi $s1, $s0, 18

//subi $s2, $s1, 9

//sw $s2,4($0)

//j 0

Определяется:

- для входа в инструкции:

addr - 32-битный адрес инструкции, необходимый для подключения к текущему значению счетчика программы (program counter).

- для выхода (получения инструкции):

instr - 32-битное значение инструкции, которое должно быть прочитано в двоичном представлении ассемблерной команды, на которую указывает адрес addr (или счетчик программы), в соответствии с полями команды её представления в типовом процессоре MIPS.

4. Процесс обработки команд в процессоре

4.1 Шина данных и контроллер

Программный модуль шина данных и контроллер (datapath and controller) осуществляет разбор потока команд ассемблерной программы, который приходит к нему из памяти инструкций, и производит выполнение каждой команды на один такт синхросигнала процессора clk.

В данный модуль входят два основных логических блока:

контроллер (controller) дешифровка двоичных инструкций (машинных кодов) процессора, которые поступают в модуль из памяти инструкций;

- шина данных (datapath) логика передачи данных между блоками процессора: между файлом регистров и памятью данных, установка счетчика программы и т.д. в зависимости от значения текущей инструкции.

Программный код модуля имеет следующий вид:

/** * Шина данных и контроллер (datapath and contoller) - переключает счетчик программы

* (program counter), содержит значения файла регистров (register file) и обрабатывает инструкции.

* @param clk - тактовый сигнал clock

* @param pc - счетчик программы (program counter)

* @param instr - значение текущей инструкции

* @param dmem_we - флаг разрешения записи (we - write enabled) в память данных (dmem - data memory)

* @param dmem_addr - адрес (addr) доступа к памяти данных для чтения/записи

* @param dmem_wd - данные для записи в память данных (wd - write data)

* @param dmem_rd - данные чтения из памяти данных (rd - read data)

*/

module datapath and controller (input clk,

/* Счетчик программы и текущая инструкция */

output [31:0] pc, input [31:0] instr)

/* Работа с памятью данных */

output reg dmem we,

output reg[31:0]dmem_addr,

output reg[31:0]dmem_wd,

input [31:0] dmem_rd);

Код модуля, приведенный выше, на каждый такт процессора выполняет следующие действия:

1. Разбор текущего значения 32-битной инструкции на составляющие поля команды.

2. В зависимости от типа инструкции и значений ее внутренних полей производится вычисление значений, которые должны быть отправлены в файл регистров, память данных или счетчик программы по факту выполнения текущей команды.

3. В момент такта процессора clock происходит запись значений, подготовленных на предыдущем этапе, уже непосредственно в файл регистров, память данных и счетчик инструкций.

4. Этапы повторяются, пока не закончатся инструкции в памяти инструкций.

Для вычисления результатов работы каждой команды и записи вычисленных значений по назначению на каждый такт синхросигнала clock используются всё те же два блока always always @(*) и always @(posedge clk). Первый блок always @(*) вычисляет значения результата работы инструкций и находится непосредственно в текущем модуле шина данных и контроллер (datapath and controller), а второй always @(posedge clk) в трех экземплярах содержится в модулях счетчик программы (pc program counter), регистровом файле (register file) и памяти данных (data memory).

Параметры программы:

clk тактовый сигнал clock;

pc - значение счетчика программы (program counter);

instr значение текущей инструкции;

dmem we флаг разрешения записи (we write enabled) в память данных (dmem data memory);

dmem addr адрес (addr) доступа к памяти данных для чтения/записи;

dmem wd данные для записи в память данных (wd - write data);

dmem rd данные чтения из памяти данных (rd - read data).

4.2 Подключение счетчика инструкций

Для созданного модуля процессора счетчик инструкций (program counter) подключаемые параметры clk (clock) и pc (program counter) поступают извне, для манипуляции с адресом следующей инструкции pc_next подсоединяется локальный регистр. Все, что в него попадет между тактами процессора в процессе исполнения команды, будет записано в выход pc на каждый тактовый сигнал clk.

Если записано новое значение с адресом инструкции в регистр pc_next в процессе выполнения текущей команды, то на следующий такт сигнала clk на входе instr появится 32-битное значение инструкции, расположенной в памяти инструкций по этому новому адресу.

Фрагмент программы для этого случая имеет вид:

reg [31:0] pc_next;

// Program counter

pc pcount (clk, pc_next, pc);

4.3 Подключение файла регистров

Второй созданный модуль файл регистров (register file). Все управляющие входы/выходы продублированы в виде локальных переменных, которым соответствую отдельные соединительные дорожки и регистры. Пояснения к механизмам чтения-записи в целом аналогичны описанному выше счетчику инструкций.

Чтение. Как только регистр файла регистров rf_ra1 (register file read address 1) получает новое значение в виде пяти битного адреса происходит чтение. Дорожка rf_rd1 (register file read data 1) получает 32-битное значение, которое хранится в файле регистров по указанному адресу rf_ra1.

Аналогично происходит запись в регистр файла регистров fr_ra2 (register file read address 2), для этого автоматически инициируется получение значения на 32-битной дорожке rf_rd2 (register file read data 2). Запись синхронизирована с тактовым сигналом процессора clk (clock). Устанавка rf_we (register file write enable) в 1 обеспечит разрешение записи. В rf_wa (register file write address) устанавливается пятибитный адрес регистра, в который будет произведена запись, в rf_wd (register file write data) - 32-битное значение для записи: на следующий такт сигнала clk значение rf_wd отправится в регистр по адресу rf_wa. Если флаг rf_we установлен в 0, то запись не производится.

Программа для файла регистров имеет вид:

/ Файл регистров /

reg [4:0] rf_ra1, rf_ra2;

wire [31:0] rf_rd1, rf_rd2;

reg rf_we;

reg [4:0] rf_wa;

reg [31:0] rf_wd;

regfile rf(clk, rf_ra1, rf_ra2, rf_rd1, rf_rd2, rf_we, rf_wa, rf_wd);

4.4 Разбор команд (контроллер)

Разбор инструкций на составляющие поля происходит при помощи создания на каждое поле переменной wire (перевод «провод», в нашем понимании дорожки печатной платы) с нужной разрядностью. Этой переменной при помощи оператора assign присваивается соответствующий диапазон битов внутри 32-битной инструкции instr.

Список инструкций, названия и разрядность полей, а также их расположение внутри инструкции были рассмотрены в разделе 6.2 данных методических указаний.

Первое поле, общее для всех типов инструкций, имеет код операции op (opcode), который занимает 6 старших бит.

Фрагмент программы имеет следующий вид:

// Инструкции

wire [5:0] instr_op;

assign instr_op = instr[31:26]; // 6 бит

Для инструкций типа R-type нужны поля: rs, rt, rd, shamt, funct. Неиспользуемые поля можно закомментировать.

// R-тип

wire [4:0] instr_rtype_rs;

wire [4:0] instr_rtype_rt;

wire [4:0] instr_rtype_rd;

//wire [4:0] instr_rtype_shamt;

wire [5:0] instr_rtype_funct;

assign instr_rtype_rs = instr[25:21]; // 5 бит

assign instr_rtype_rt = instr[20:16]; // 5 бит

assign instr_rtype_rd = instr[15:11]; // 5 бит

//assign instr_rtype_shamt = instr[10:6]; // 5 бит - в этом типе не используется

assign instr_rtype_funct = instr[5:0]; // 6 бит

Для инструкций типа I-type необходимы поля: rs, rt, imm.

// I-тип

wire [4:0] instr_itype_rs;

wire [4:0] instr_itype_rt;

wire [15:0] instr_itype_imm;

assign instr_itype_rs = instr[25:21]; // 5 бит

assign instr_itype_rt = instr[20:16]; // 5 бит

assign instr_itype_imm = instr[15:0]; // 16 бит

4.5 Выполнение команд (шина данных)

Для удобства работы создается несколько констант с значениями полей op (код операции общий для всех) и funct (для команд типа

R-type) и для всех команд, которые будет уметь исполнять проектируемый процессор: lw, sw, addi, beq, add.

Фрагмент программы для поля ОР для инструкций имеет вид:

parameter INSTR_OP_LW = 6'b100011;

parameter INSTR_OP_SW = 6'b101011;

parameter INSTR_OP_ADDI = 6'b001000;

parameter INSTR_OP_J = 6'b000010;

parameter INSTR_OP_RTYPE = 6'b000000;

parameter INSTR_RTYPE_FUNCT_ADD = 6'b100000;

parameter INSTR_RTYPE_FUNCT_SUB = 6'b100010;

parameter INSTR_OP_SUBI = 6'b100111;

Программа в первом always в стартовой секции устанавливает значения по умолчанию для всех команд: перевод счетчика инструкций на следующую команду (+4 бита к текущему значению), запрещается запись в файл регистров и память данных, остальные значения сбрасываются в 0, и открывается ветвление case по полю instr_op (код операции).

Код программы имеет вид:

always @(*)

begin

// по умолчанию перевод счетчика на следующую инструкцию

pc_next = pc + 4;

// запрет записи в файл регистров и память данных

rf_we = 0;

dmem_we = 0;

// сброс остальных значений в 0 по умолчанию

rf_ra1 = 0;

rf_ra2 = 0;

rf_wa = 0;

rf_wd = 0;

dmem_addr = 0;

dmem_wd = 0;

case(instr_op)

Далее в каждой из веток case произойдет реализация соответствующей команды.

Например, команда типа R-type: add.

Поле opcode для всех команд R-type равно нулю, а окончательный тип команды определяет поле funct, поэтому сразу же открываем по этому полю второе вложенное ветвление case, чтобы можно было отличить add от других команд этого типа, инструкция программы имеет вид:

INSTR_OP_RTYPE:

case(instr_rtype_funct)

Ниже приведен код команды add для реализации команды сложения значений двух регистров:

INSTR_RTYPE_FUNCT_ADD:

begin

// add $s2, $s0, $s2

// $s2 = $s1 + $s0

// rs=$s0, rt=$s2, rd=$s2

// rf_rd1 получит значение регистра rs

rf_ra1 = instr_rtype_rs;

// rf_rd2 получит значение регистра rt

rf_ra2 = instr_rtype_rt;

// записать значение в регистр rd на следующий такт clock

rf_wa = instr_rtype_rd;

rf_wd = rf_rd1 + rf_rd2;

rf_we = 1;

end

Команда add работает следующим образом:

add $s2, $s1, $s0

Результат работы команды:

$s2 = $s1 + $s0 в регистр $s2 попадает сумма значений двух регистров $s1 и $s0

Поля операции:

rs= адрес $s0, rt= адрес $s1, rd= адрес $s2

Выполнение инструкции программы будет происходить следующим образом. Считывается значение первого операнда: устанавливается адрес чтения регистра rf_ra1 в значение поля операции rs (5 бит). Сразу после этого 32-битное значение регистра появится в переменной rf_rd1.

rf_ra1 = instr_rtype_rs;

Аналогично считывается значение второго операнда: устанавливается адрес чтения регистра rf_ra2 в значение поля операции rt (5 бит). После этого 32-битное значение регистра появится в переменной rf_rd2.

rf_ra2 = instr_rtype_rt;

Значения операндов-источников rs и rt считаны на них указывают переменные rf_rd1 и rf_rd2 соответственно. Теперь нужно записать результат в файл регистров по адресу, указанному в третьем операнде-назначении rd.

Значение адреса записи регистра rf_wa устанавливается в значение поля операции rd.

rf_wa = instr_rtype_rd;

Значение для записи попадает в регистр rf_wd (32 бит) это сумма значений двух регистров rs и rt, т.к. выполняется операция сложения.

rf_wd = rf_rd1 + rf_rd2;

Осталось включить флаг разрешения записи в файл регистров rf_we, таким образом, новое значение с суммой регистров rs и rt отправится в регистр rd на следующий такт сигнала clock.

rf_we = 1;

Аналогично реализуются и другие команды типа R. После написания кода для команд типа R необходимо закрыть вложенный case для команд этого типа:

endcase

После завершения этого типа команды можно продолжить работу с командами всех остальных типов.

Команды lw загружают слово (32 бит) из памяти данных (0 и 4) в регистры $s0 и $s1.По спецификации команды адрес слова в памяти данных является суммой значений регистра-операнда rs и константы imm.

Выполнение команды происходит следующим образом:

1. Получаем значение регистра rs в rf_rd1, присвоив адрес регистра переменной rf_ra1.

2. Вычисляем адрес как rf_rd1 + imm (значение регистра

rs + константа imm) и одновременно получаем значение слова в памяти данных в переменной dmem_rd, присвоив значение вычисленного адреса переменной dmem_addr (механизм аналогичен описанному механизму получения значения из регистра).

3. Осуществляем запись значения dmem_rd в регистр rt на следующий такт clock уже известным способом.

INSTR_OP_LW:

begin

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_itype_rs;

// прочитать значение из памяти,

// dmem_rd немедленно получит значение по адресу dmem_addr

dmem_addr = rf_rd1 + instr_itype_imm;

// записать значение в регистр rt на следующий такт clock

rf_wa = instr_itype_rt;

rf_wd = dmem_rd;

rf_we = 1;

end

Команда sw сохраняет слово (32 бит) из указанного регистра в память данных. По спецификации команды адрес слова в памяти данных является суммой значений регистра-операнда rs и константы imm. Механизм записи в память данных очевидно аналогичен механизму записи в файл регистров указываем адрес, значение, включаем флаг записи и ждем следующий такт clock.

INSTR_OP_SW:

begin

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_itype_rs;

// rf_rd2 немедленно получит значение регистра rt

rf_ra2 = instr_itype_rt;

// записать значение в память данных на следующий такт clock

dmem_addr = rf_rd1 + instr_itype_imm;

dmem_wd = rf_rd2;

dmem_we = 1;

end

Команда addi складывает значение регистра и константы, результат сохраняет в регистр.

INSTR_OP_ADDI:

begin

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_itype_rs;

// записать значение в регистр rt на следующий такт clock

rf_wa = instr_itype_rt;

rf_wd = rf_rd1 + instr_itype_imm;

rf_we = 1;

end

Команда subi вычитание константы из содержимого регистра, размещение результата в регистре назначения Rd.

INSTR_OP_SUBI:

begin

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_itype_rs;

// записать значение в регистр rt на следующий такт clock

rf_wa = instr_itype_rt;

rf_wd = rf_rd1 - instr_itype_imm;

rf_we = 1;

end

Команда j выполняется переход по адресу внутри всего объема (4М слов) памяти программ.

INSTR_OP_J:

begin

pc_next = instr_jtype_addr;

end

endcase

5. Верхний уровень проекта

После написания всех нужных модулей на языке Verilog создаём файл с расширением.bdf - это и будет верхний схемный уровень в иерархии проекта. На этой схеме разместим все созданные вами модули (рис. 3) и соединим их графически.

С помощью квадратных скобок можно показать разрядность шины. Если требуется соединим шины разной разрядности соответствующим образом их подписав, как указано у блока regfile: instr[25..21], instr[20..16], instr[15..11].

После этого проводим симуляцию полученной схемы. Она отображен на рисунке 2.

Рис. 2 Пример симуляции проекта

Рис. 3 Верхний уровень проекта

Заключение

В данной курсовой работе был разработан процессор MIPS с заданными параметрами с использованием языка аппаратуры на языке Verilog, в котором использованы понятия процессора, языка ассемблера и системы реализованных команд. Язык SystemVerilog обеспечивает описания аппаратуры процессора.

Работа состоит из пяти модулей. В первую очередь были созданы эти модули, а затем работа перешла к верхнему схемному уровню процессора.

Команда в момент выполнения влияет на один или несколько модулей одновременно, изменяя счетчик программы, файл регистров и память данных. Процессор выбирает ровно одну команду из памяти инструкций на каждый такт периодического сигнала Clock и в этом же такте исполняет ее.

В конце была проведена симуляция процессора, на которой видно время, потраченное на выполнение каждой команды.

Список используемой литературы

1. Акулов О.А., Медведев Н.В. Информатика. Базовый курс: учебник для студентов вузов. М.: Омега-Л, 2013. 574 с.

2. Гук М. Аппаратные средства IBM PC. Энциклопедия. СПб.: Питер, 2006. 1072 с.

3. Таненбаум Э., Остин Т. Архитектура компьютера. 6 изд. СПб.: Питер, 2013. 816 с.

4. Харрис Д.М. Цифровая схемотехника и архитектура компьютера / Д.М. Харрис, С.Л. Харрис; пер. с англ. Imagination Technologies. М.: ДМК Пресс, 2018. 792 с.

Приложение. Листинг

module regfile(input clk,

/* Чтение 2х регистров */

input [4:0] ra1, input [4:0] ra2,

output [31:0] rd1, output [31:0] rd2,

/* Запись в регистр */

input we, input [4:0] wa, input [31:0] wd);

reg [31:0] rf [31:0];

always @(posedge clk)

if(we) rf[wa] <= wd;

assign rd1 = ra1 ? rf[ra1]: 0; // reg[0] всегда ноль

assign rd2 = ra2 ? rf[ra2]: 0; // reg[0] всегда ноль

endmodule

/**

*

Счетчик программы - переход на следующее значение на каждый такт.

*

* @param clk - тактовый сигнал clock

*

* @param pc_next - следующее значение для счетчика программы (program counter)

* @param pc - счетчик программы (program counter)

*/

module pc(input clk,

input [31:0] pc_next, output reg [31:0] pc);

always @(posedge clk)

pc <= pc_next;

endmodule

/** * Шина данных и контроллер (datapath and contoller) - переключает счетчик программы

* (program counter), содержит файла регистров (register file) и обрабатывает инструкции.

* @param clk - тактовый сигнал clock

* @param pc - счетчик программы (program counter)

* @param instr - значение текущей инструкции

* @param dmem_we - флаг разрешения записи (we - write enabled) в память данных (dmem - data memory)

* @param dmem_addr - адрес (addr) доступа к памяти данных для чтения/записи

* @param dmem_wd - данные для записи в память данных (wd - write data)

* @param dmem_rd - данные чтения из памяти данных (rd - read data)

*/

module datapath_and_controller(input clk,

output [31:0] pc, input [31:0] instr,

output reg dmem_we,

output reg [31:0] dmem_addr,

output reg [31:0] dmem_wd,

input [31:0] dmem_rd);

reg [31:0] pc_next;

pc pcount(clk, pc_next, pc);

reg [4:0] rf_ra1, rf_ra2;

wire [31:0] rf_rd1, rf_rd2;

reg rf_we;

reg [4:0] rf_wa;

reg [31:0] rf_wd;

regfile rf(clk,

rf_ra1, rf_ra2, rf_rd1, rf_rd2,

rf_we, rf_wa, rf_wd);

wire [5:0] instr_op;

assign instr_op = instr[31:26];

// R-тип

wire [4:0] instr_rtype_rs;

wire [4:0] instr_rtype_rt;

wire [4:0] instr_rtype_rd;

//wire [4:0] instr_rtype_shamt;

wire [5:0] instr_rtype_funct;

assign instr_rtype_rs = instr[25:21]; // 5 бит

assign instr_rtype_rt = instr[20:16]; // 5 бит

assign instr_rtype_rd = instr[15:11]; // 5 бит

//assign instr_rtype_shamt = instr[10:6]; // 5 бит - в этом типе не используется

assign instr_rtype_funct = instr[5:0]; // 6 бит

//I-тип

wire [4:0] instr_itype_rt;

wire [4:0] instr_itype_rs;

wire [15:0] instr_itype_imm;

assign instr_itype_rs = instr[25:21]; // 5 бит

assign instr_itype_rt = instr[20:16]; // 5 бит

assign instr_itype_imm = instr[15:0]; // 16 бит

//J-тип

wire [25:0] instr_jtype_addr;

assign instr_jtype_addr = instr [25:0];

parameter INSTR_OP_LW = 6'b100011;

parameter INSTR_OP_SW = 6'b101011;

parameter INSTR_OP_ADDI = 6'b001000;

parameter INSTR_OP_J = 6'b000010;

parameter INSTR_OP_RTYPE = 6'b000000;

parameter INSTR_RTYPE_FUNCT_ADD = 6'b100000;

parameter INSTR_RTYPE_FUNCT_SUB = 6'b100010;

parameter INSTR_OP_SUBI = 6'b100111;

always @(*)

begin

// по умолчанию перевод счетчика на следующую инструкцию

pc_next = pc + 4;

// запрет записи в файл регистров и память данных

rf_we = 0;

dmem_we = 0;

// сброс остальных значений в 0 по умолчанию

rf_ra1 = 0;

rf_ra2 = 0;

rf_wa = 0;

rf_wd = 0;

dmem_addr = 0;

dmem_wd = 0;

case(instr_op)

INSTR_OP_RTYPE:

case(instr_rtype_funct)

INSTR_RTYPE_FUNCT_ADD:

begin

// add $s0, $s1, $s2

// $s0 = $s1 + $s2

// rs=$s1, rt=$s2, rd=$s0

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_rtype_rs;

// rf_rd2 немедленно получит значение регистра rt

rf_ra2 = instr_rtype_rt;

// записать значение в регистр rd на следующий такт clock

rf_wa = instr_rtype_rd;

rf_wd = rf_rd1 + rf_rd2;

rf_we = 1;

end

endcase

INSTR_OP_LW:

begin

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_itype_rs;

// прочитать значение из памяти,

// dmem_rd немедленно получит значение по адресу dmem_addr

dmem_addr = rf_rd1 + instr_itype_imm;

// записать значение в регистр rt на следующий такт clock

rf_wa = instr_itype_rt;

rf_wd = dmem_rd;

rf_we = 1;

end

INSTR_OP_SW:

begin

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_itype_rs;

// rf_rd2 немедленно получит значение регистра rt

rf_ra2 = instr_itype_rt;

// записать значение в память данных на следующий такт clock

dmem_addr = rf_rd1 + instr_itype_imm;

dmem_wd = rf_rd2;

dmem_we = 1;

end

INSTR_OP_ADDI:

begin

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_itype_rs;

// записать значение в регистр rt на следующий такт clock

rf_wa = instr_itype_rt;

rf_wd = rf_rd1 + instr_itype_imm;

rf_we = 1;

end

INSTR_OP_SUBI:

begin

// rf_rd1 немедленно получит значение регистра rs

rf_ra1 = instr_itype_rs;

// записать значение в регистр rt на следующий такт clock

rf_wa = instr_itype_rt;

rf_wd = rf_rd1 - instr_itype_imm;

rf_we = 1;

end

INSTR_OP_J:

begin

pc_next = instr_jtype_addr;

end

endcase

end

endmodule

/**

* Память данных.

* @param clk - clock

* @param we - флаг разрешения записи (write enabled)

* @param addr - адрес доступа на чтение/запись (address)

* @param wd - записываемые данные (write data)

* @param rd - считанные данные (read data)

*/

module datamem_plain (input clk,

input we, input [31:0] addr,

input [31:0] wd, output [31:0] rd);

// массив памяти данных

reg [31:0] RAM [63:0];

// запись данных в RAM если флаг we (write enabled) равен '1'

always @(posedge clk)

if(we) RAM[addr[31:2]] <= wd;

// чтение данных из RAM

// выравнивание по словам (word aligned) - поделить адрес addr на 4

// (просто отбросить 2 последних бита)

assign rd = RAM[addr[31:2]];

endmodule

module instrmem (

/* адрес чтения инструкции */

input [31:0] addr,

/* значение инструкции */

output reg [31:0] instr);

always @ (addr)

case (addr)

32'h00000000: instr <= 32'b100011_00000_10000_0000000000000000; // lw $s0, 0 ($0)

32'h00000004: instr <= 32'b001000_10000_10001_0000000000010010; // addi $s1, $s0, 18

32'h00000008: instr <= 32'b100111_10001_10010_0000000000001001; //subi $s2, $s1, 9

32'h0000000C: instr <= 32'b101011_00000_10010_0000000000000100; //sw $s2,4($0)

32'h00000010: instr <= 32'b000010_00000000000000000000000000; //j 0

default: instr <= 0;

endcase

endmodule

//lw слова 0

//прибавить к нему 18 addi

//вычесть из него 9 subi

//sw по адресу 4

//j перейти в начало

//lw $s0, 0($0)

//addi $s1, $s0, 18

//subi $s2, $s1, 9

//sw $s2,4($0)

//j 0

Приложение. Проверка на антиплагиат

Размещено на Allbest.ru


Подобные документы

  • Разработка структурной схемы процессора; синтез микропрограммного и управляющего автомата с жесткой логикой. Функциональная организация процессора: программные модели, форматы данных и команд. Организация оперативной памяти. Проектирование блока операций.

    учебное пособие [1,1 M], добавлен 09.04.2013

  • Функциональная и структурная организация ЭВМ. Разработка функциональных микропрограмм заданных команд. Их объединение и привязка к структуре операционного автомата процессора. Разработка управляющего автомата процессора с программируемой логикой.

    дипломная работа [4,0 M], добавлен 25.03.2012

  • Принцип работы процессора, способы его охлаждения, кодовые названия. Шины процессора, разрядность и кэш–память. Технологии расширения и поток команд процессора. Процессорные вентиляторы и их характеристика. Алгоритм и способы разгона процессора.

    реферат [38,0 K], добавлен 21.02.2009

  • Разработка модели процессора, выполняющего набор машинных команд. Структурная схема процессора (операционного и управляющего автоматов), анализ принципа работы. Содержательный алгоритм микропрограммы, синтез управляющего автомата на основе жесткой логики.

    курсовая работа [871,9 K], добавлен 16.09.2010

  • Принцип работы процессора (одномагистральная структура). Временные диаграммы, описывающие выполнение микроопераций для каждой команды. Структурная схема управляющего автомата на основе памяти с одним полем адреса. Описание процессора на языке Active VHDL.

    курсовая работа [621,0 K], добавлен 24.09.2010

  • Рост производительности и снижение потребляемой мощности процессора. Упрощенная-схема процессора BF535. Поддержка моделей памяти. Стандарты коммуникационных протоколов. Системные регистры процессора. Регистровый файл данных. Шины связи регистрового файла.

    презентация [6,3 M], добавлен 14.12.2013

  • Разработка устройства, реализующего набор команд из числа операций с плавающей точкой семейства процессора i486. Структура сопроцессора FPU. Принцип выполнения операций, разработка блок-схемы, построение структурной схемы основных блоков процессора.

    курсовая работа [734,9 K], добавлен 27.10.2010

  • История развития центрального процессора. Основные проблемы создания многоядерных процессоров. Проектирование микропроцессорной системы на базе процессора Intel 8080. Разработка принципиальной схемы и блок-схемы алгоритма работы микропроцессорной системы.

    курсовая работа [467,6 K], добавлен 11.05.2014

  • Описание архитектуры внешних выводов кристалла процессора. Рассмотрение форматов данных для целых чисел со знаком и без знака. Выбор модели памяти и структуры регистровой памяти. Использование кэш прямого отображения. Арифметические и логические команды.

    курсовая работа [890,5 K], добавлен 05.06.2015

  • Ознакомление с языком ассемблера процессора Neuro Matrix NM 6403, его возможности, особенности работы, содержание операций в регистрах, архитектура. Разработка программы для заполнения блока памяти, компилирование и отладка файла, фиксирование его адреса.

    лабораторная работа [48,2 K], добавлен 18.10.2012

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.