Дело было вечером, делать было нечего.
Предлагаю разработать процессорный элемент, пока Viktor2312 ищет какие флаги добавить в регистр флагов
Процессор будет называться 5-РИМВ
Технические требования:
0. стеково/регистровый, ну что бы как стековый мог работать и как регистровый
1. 8 регистров общего назначения, ширина 64бит
2. фиксированная ширина кода операции 16бит!
4. регулируемая ширина слова стека данных
5. команд алу 32, кодировать 12 битами
6. указатель инструкций 12 битный
7. только относительные переходы
8. процессор без флагового регистра
9. возможность при синтезе задать максимальную разрядность процессора, но так что бы на коды инструкций не влияло
И да, писать придется на Verilog, думаю Viktor2312 поможет на VHDL перевести
У кого какие мнения по поводу ТЗ? реально?
---------- Post added at 21:17 ---------- Previous post was at 21:11 ----------
Команда ALU
Код:
15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
1 1 [siz] [ aluop ][ dst ][ left ][ right ]
команды будут 4 видов 3х адресные, 2х адресные, 1н адресные, безадресные
3х адресные, код операции задается в 3х битном поле aluop
0 - add dst, left, right // dst = left + right
1 - adc dst, left, right // dst = left + right + flag
2 - sub dst, left, right // dst = left - right
3 - sbc dst, left, right // dst = left - right - flag
4 - and dst, left, right // dst = left & right
5 - or dst, left, right // dst = left | right
6 - xor dst, left, right // dst = left ^ right
7 - 2х адресные команды, код операции 2х адресных команд задает поле left
2х адресные команды:
0 - shr dst, right // dst = right >> 1, младший бит в флаг, старший 0
1 - ror dst, right // dst = right >> 1, младший бит в флаг, старший из флага
2 - add dst, right // dst = right + left left, используется как непосредственный параметр, только не от 0до7 а от 1 до 8
3 - sub dst, right // dst = right - left, left опять же imm
4 - == // flag = (dst == right)
5 - < // flag = (dst < right)
6 - > // flag = (dst > right)
7 - 1 адресная команда, код одноадресных команд в поле right
1но адресные команды
0 - neg // dst = 0-dst
1 - inv // dst = fffffffff^dst
2 - not // dst = !dst
3 - ==0 // dst==0
4 - <0 // dst < 0
5 - parity
6 - четность
7 - безадресные команды алу, код команды задает поле dst
безадресные команды
0 - set flag // flag = 1
1 - reset flag // flag = 0
2 - invert flag // flag = !flag
3..7 резерв
Команда условного перехода
И команда вызова процедуры
b[15:13] == 3'b010 JR
b[15:13] == 3'b011 CALL
b[12] - F, срабатывает при равном значении F=flag
b[11:0] для jr относительный адрес в словах, ширина слова задается максимально разрядностью процедуры, то есть если продура maxsize = 64бит, то прыгать будет кратно 8 байт, если адрес == 0 то это команда halt
для call - номер процедуры в каталоге процедур, если номер процедуры 0, то это команда ret
Каталог процедур это табличка, на табличку процедур указывает указатель из дескриптора задачи.
В каталоге задается физический адрес процедуры (Физический адрес инструкции это PROC_BASE + PC), максимальная ширина слова, ну там можно, длина процедуры, к примеру для защиты, можно максимальную глубину стека, что бы защита от переполнения была, итд, пусть пока будет табличка из элементов скажем по 8 байт, аля дескрипторы 80386
отсюда и PC = 12 битам, нефик делать процедуру больше 4к слов, для 64бит процедур это аж 32кб
Команда const, загружает в регистр константу
b[15:12] == 4'b0000
b[11] - imm, если 1 то 8бит констранта непосредственно в команде, если 0, то указатель на таблицу констант процедуры
b[10:9] - imm8 старшие 2 бита для непосредственно заданной 8 бит константы
b[8:6] - dst, номер регистра куда загружать константу
b[5:0] - если imm ==0 то тут номер констатны в таблице констант, если imm==1 то тут младшие 6 бит непосредственной 8 бит константы
константы в коде будут храниться перед телом процедуры, адресация будет как в стеке в сторону уменьшения адресов, то есть если процедура юзает 2 константы, то перед текло процедуры будет пару слов с константами, ширина слова константы, равна разрядности процедуры из дескриптора
Команды обмена с памятью
команд 6
b[15:11] = 5'b10010 // select var, выставляет для чтения адрес переменной в стеке
b[15:11] = 5'b10011 // select [base + index*mul + offs], выставляет адрес для чтения из памяти
эти 2 команды игнорируют прерывания
b[15:11] = 5'b10000 // ld чтение с шины данных
b[15:11] = 5'b10100 // st var, сохраняет регистр в переменную в стеке
b[15:11] = 5'b10101 // st [base+offs], сохраняет регистр в памяти
b[15:11] = 5'b10111 // st [base+index], сохраняет регистр в памяти
для чтения, получилось более гибкая адресация, но это не все, команды еще стараются быть полезными
форматы команд:
команда select var
b[10:9] - mode, определяет доп действия, 00-если следующая команда ALU, то данные с шины будут левым аргументом алу, 01-если следующая команда ALU, то данные с шины будут правым аргументом, 10-11 на поведение АЛУ не влияет, 10-декремент регистра dst, 11-инкремент регистра dst
b[8:6] - dst регистр, который инкрементируется/декрементируется если заданно параметром mode
b[5:0] - номер переменной в стеке
команда select [base + index*mul + offset]
b[10:9] - mul 00-x0, 01-x1, 10-x2, 11-x4, то есть mul=00 регистр index не используется (на 0 умножил)
b[8:6] - base
b[5:3] - offset
b[2:0] - index
команда ld, читает данные с шины в регистр, применима после команд select и const с чтением константы из памяти
b[10:9] - sz, размер читаемого аргумента
b[8:6] - dst, регистр для записи результата
b[5:3] - aluop - команды алу, пока придумал следующие
000-nop
001-знаковое расширение
команда st var
b[10:9] - size
b[8:6] - src, сохраняемый регистр
b[5:0] - номер переменной
команда st [base + offset]
b[10:9] - size
b[8:6] - base
b[5:3] - offset
b[2:0] - right - записываемый регистр
команда st [base + index], аналогично предыдущей, только b[5:3] номер регистра index