Самодельный процессор nedoRISC-0 (NEDONAND)

Публичный форум для http://www.nedopc.org/nedopc

Moderator: Shaos

Post Reply
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Самодельный процессор nedoRISC-0 (NEDONAND)

Post by Shaos »

Чего-то перечитывая Lavr-a решил я для начала вместо 16-битного проца с 8-битным АЛУ сделать 8-битный проц с 4-битным АЛУ (эдакий nedoZ80). И делать естественно буду только на NAND из сотен 74F00, что у меня есть. Назвал было этот гипотетический проц "nedoRISC-0", однако потом понял, что это не RISC, а скорее некий недогибрид z80 и 6502. Однако потом таки осознал, что это всё-таки RISC (как минимум в духе PIC-a с двумя стадиями конвейера - эдакий nedoPIC). Так что пусть nedoRISC-0 остаётся как наименование абстрактного процессора и его системы команд, а вот нижеописанная реализация на 74F00 будет называться NEDONAND (кодовое наименование nedoPC-00)...

Последняя версия либ для Logisim v2.7.1 всегда будет тут: http://nedopc.org/nedopc/files/logisim-nedonand.zip

Image

Последняя версия печатных плат для бесплатного Eagle v5.12.0 всегда будет тут:
http://nedopc.org/nedopc/files/eagle-nedonand.zip
И кое-что нарисовано в pcb (gEDA):
http://nedopc.org/nedopc/files/geda-nedonand.zip
Кроме того голые платы можно заказать через OSHPark.com:
https://oshpark.com/profiles/Shaos


Ввиду того, что получение OR через NANDы выглядит тяжеловато, я решил убрать операцию OR из списка команд (а потом и от AND отказался, заменив его на NAND) - оставшиеся операции отдалённо напоминают систему команд nedoRISC-1:
000 - RRC (сдвиг произвольного регистра вправо через флаг C и сохранение результата в аккумуляторе);
001 - RLC (сдвиг произвольного регистра влево через флаг C и сохранение результата в аккумуляторе);
010 - NAN (побитная операция И-НЕ между аккумулятором и произвольным регистром с сохранением результата в аккумуляторе);
011 - XOR (побитная операция исключающее ИЛИ между аккумулятором и произвольным регистром с сохранением результата в аккумуляторе);
100 - ADC (сложение аккумулятора с произвольным регистром с учётом флага C и сохранение результата в аккумуляторе);
101 - SBC (вычитание из аккумулятора произвольного регистра с учётом флага C и сохранение результата в аккумуляторе);
110 - ADI (сложение аккумулятора с 3-битным числом и сохранение результата в аккумуляторе);
111 - SBI (вычитание из аккумулятора 3-битного числа и сохранение результата в аккумуляторе).

Все инструкции будут однобайтовыми:
0xxxxxxx - A=0xxxxxxx (записать в аккумулятор 7-битное число);
10xxxyyy - xxx=yyy (скопировать значение регистра ууу в регистр xxx - если xxx и yyy это один и тот же регистр, то его содержимое инвертируется, а в случае xxx=0 это работа с подпрограммами RST/RET);
11oooxxx - операция АЛУ ooo (см. выше) над регистром (или числом) xxx и аккумулятором () - результат ВСЕГДА сохраняется в аккумуляторе, а также меняются ВСЕ флаги.

Регистры:
000 - 0 (всегда 0)
001 - A (аккумулятор)
010 - B
011 - C
100 - D
101 - E
110 - F (регистр флагов и старших битов адреса)
111 - G (младшие 8 битов программного указателя)

Чтобы передать управление по какому-то адресу придётся загрузить число в аккумулятор и потом скопировать его в регистр G (если же надо перейти за пределы текущей 256-байтовой страницы, то придётся ещё и в регистре флагов кое-какие биты установить)...

Code: Select all

  |  x0 |  x1 |  x2 |  x3 |  x4 |  x5 |  x6 |  x7 |  x8 |  x9 |  xA |  xB |  xC |  xD |  xE |  xF |
--+------------------------------------------------------------------------------------------------
0x| A=0 | A=1 | A=2 | A=3 | A=4 | A=5 | A=6 | A=7 | A=8 | A=9 |A=10 |A=11 |A=12 |A=13 |A=14 |A=15 |
---------------------------------------------------------------------------------------------------
1x|A=16 |A=17 |A=18 |A=19 |A=20 |A=21 |A=22 |A=23 |A=24 |A=25 |A=26 |A=27 |A=28 |A=29 |A=30 |A=31 |
---------------------------------------------------------------------------------------------------
2x|A=32 |A=33 |A=34 |A=35 |A=36 |A=37 |A=38 |A=39 |A=40 |A=41 |A=42 |A=43 |A=44 |A=45 |A=46 |A=47 |
---------------------------------------------------------------------------------------------------
3x|A=48 |A=49 |A=50 |A=51 |A=52 |A=53 |A=54 |A=55 |A=56 |A=57 |A=58 |A=59 |A=60 |A=61 |A=62 |A=63 |
---------------------------------------------------------------------------------------------------
4x|A=64 |A=65 |A=66 |A=67 |A=68 |A=69 |A=70 |A=71 |A=72 |A=73 |A=74 |A=75 |A=76 |A=77 |A=78 |A=79 |
---------------------------------------------------------------------------------------------------
5x|A=80 |A=81 |A=82 |A=83 |A=84 |A=85 |A=86 |A=87 |A=88 |A=89 |A=90 |A=91 |A=92 |A=93 |A=94 |A=95 |
---------------------------------------------------------------------------------------------------
6x|A=96 |A=97 |A=98 |A=99 |A=100|A=101|A=102|A=103|A=104|A=105|A=106|A=107|A=108|A=109|A=110|A=111|
---------------------------------------------------------------------------------------------------
7x|A=112|A=113|A=114|A=115|A=116|A=117|A=118|A=119|A=120|A=121|A=122|A=123|A=124|A=125|A=126|A=127|
---------------------------------------------------------------------------------------------------
8x| RET |RST 1|RST 2|RST 3|RST 4|RST 5|RST 6|RST 7| NOP | A=~A| A=B | A=C | A=D | A=E | A=F | A=G |
---------------------------------------------------------------------------------------------------
9x| B=0 | B=A | B=~B| B=C | B=D | B=E | B=F | B=G | C=0 | C=A | C=B | C=~C| C=D | C=E | C=F | C=G |
---------------------------------------------------------------------------------------------------
Ax| D=0 | D=A | D=B | D=C | D=~D| D=E | D=F | D=G | E=0 | E=A | E=B | E=C | E=D | E=~E| E=F | E=G |
---------------------------------------------------------------------------------------------------
Bx| F=0 | F=A | F=B | F=C | F=D | F=E | F=~F| F=G | G=0 | G=A | G=B | G=C | G=D | G=E |SAEFF|SANFF|
---------------------------------------------------------------------------------------------------
Cx|RRC 0|RRC A|RRC B|RRC C|RRC D|RRC E|RRC F|RRC G|RLC 0|RLC A|RLC B|RLC C|RLC D|RLC E|RLC F|RLC G|
---------------------------------------------------------------------------------------------------
Dx|NAN 0|NAN A|NAN B|NAN C|NAN D|NAN E|NAN F|NAN G|XOR 0|XOR A|XOR B|XOR C|XOR D|XOR E|XOR F|XOR G|
---------------------------------------------------------------------------------------------------
Ex|ADC 0|ADC A|ADC B|ADC C|ADC D|ADC E|ADC F|ADC G|SBC 0|SBC A|SBC B|SBC C|SBC D|SBC E|SBC F|SBC G|
---------------------------------------------------------------------------------------------------
Fx|A=A+0|A=A+1|A=A+2|A=A+3|A=A+4|A=A+5|A=A+6|A=A+7|A=A-8|A=A-7|A=A-6|A=A-5|A=A-4|A=A-3|A=A-2|A=A-1|
---------------------------------------------------------------------------------------------------
P.S. Выше версия таблицы опкодов от 25 февраля 2016 года (0x88 стал NOP, 0x80 стал RET, а 0xBE и 0xBF стали инструкциями SAEFF и SANFF - см. тут)

P.P.S. С февраля веду страничку проекта на Hackaday: https://hackaday.io/project/9795-nedonand-homebrew-computer

P.P.P.S. 19 марта 2016 прикрутил 4-битное АЛУ со схемой сопряжения с 8-битным остальным (см. картинку выше)

P.P.P.P.S. 26 марта 2016 зарелизил NEDONAND LITE, в котором ещё нету SAEFF/SANFF (на их месте всё ещё находятся G=F и G=~G), а RET/RST вводят проц в состояние HALT (надо нажимать на кнопку GO, чтобы оно побежало дальше)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

Флаги (регистр F):
bit 7: S - sign (результат оказался отрицательным);
bit 6: Z - zero (результат оказался нулевым);
bit 5: V - overflow (было переполнение при сложении или вычитании чисел со знаком);
bit 4: C - carry/borrow (был перенос при сложении или небыло заимствования при вычитании);
bit 3: H - half carry (был перенос между нибблами);
bit 2: P10 \
bit 1: P9 - старшие 3 бита программного указателя
bit 0: P8 /

Старшие 5 бит флагов повторяют старшие 5 бит регистра R14 из nedoRISC-1, а младшие 3 бита задают старшие 3 бита адреса программного указателя (младший байт которого хранится в регистре G) - получается, что наш недопроцессор может адресовать 2Кб, что очень даже неплохо...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

Все команды, где в качестве приёмника выступает 0, будут абсолютно бессмысленны - поэтому на месте этих 8 инструкций (с кодами от 0x80 до 0x87) можно предусмотреть какие-то другие операции или даже вызов микропрограмм - эдакий RST с запоминанием адреса возврата (и флагов)...

P.S. Получается, что у нас нету памяти данных - только код. Эту проблему можно решить скажем путём отображения какого-то регистра (скажем E) на внешнюю память в некоторых случаях (скажем если код выполняется в младших 64 байтах) - тогда адрес ячейки, к которой происходит обращение, может задаваться двумя другими регистрами (скажем C и D) - например по команде RST (одной из восьми) управление передаётся в начало памяти и регистр E становится шлюзом во внешнюю память данных - тогда подпрограмма чтения байта по адресу CD может выглядеть так:

10010101 (B=E - скопировать значение из E в регистр B)
10111111 (G=G - этот код может означать возврат из подпрограммы RET с автоматическим восстановлением регистров F и G)

а подпрограмма записи байта из B по адресу CD - так:

10101010 (E=B - скопировать значение из регистра B в E)
10111111 (G=G - возврат из подпрограммы RET)

чтобы передать управление на произвольный адрес нужно максимум 5 байтов (если младший байт адреса >=128):

00000xxx (A=00000xxx)
10110001 (F=A - записать 3 младших бита в регистр F)
0yyyyyyy (A=0yyyyyyy)
10001001 (A=A - инвертировать A, если младший байт адреса должен быть >=128)
10111000 (G=A - в этот момент происходит передача управления по полному адресу, включая 3 младших бита из регистра F)

Значит RST могут идти с шагом 8 байт как в старом добром 8080:

RST0 - 0x000 (25 февраля поставил сюда RET)
RST1 - 0x008
RST2 - 0x010
RST3 - 0x018
RST4 - 0x020
RST5 - 0x028
RST6 - 0x030
RST7 - 0x038

Управление после ребута передаётся на адрес 0x000...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

По поводу разнообразных вариаций передачи управления:

1) передача управления в первые 64 байта памяти с шагом 8 байт с сохранением адреса возврата и флагов (1 байт):

10000xxx (0=xxx - RST xxx)

2) передача управления в начало текущей 256-байтовой страницы (1 байт):

10111000 (G=0)

3) передача управления в пределах первой половины текущей 256-байтовой страницы (2 байта):

0xxxxxxx (A=0xxxxxxx)
10111001 (G=A)

4) передача управления в пределах второй половины текущей 256-байтовой страницы (3 байта):

0xxxxxxx (A=0xxxxxxx)
10001001 (A=~A - инвертировать A)
10111001 (G=A)

5) передача управления в начало произвольной 256-байтовой страницы (3 байта):

00000xxx (A=00000xxx)
10110001 (F=A)
10111000 (G=0)

6) передача управления в первую половину произвольной 256-байтовой страницы (4 байта):

00000xxx (A=00000xxx)
00110001 (F=A)
0yyyyyyy (A=0yyyyyyy)
00111001 (G=A)

7) передача управления во вторую половину произвольной 256-байтовой страницы (5 байт):

00000xxx (A=00000xxx)
10110001 (F=A)
0yyyyyyy (A=0yyyyyyy)
10001001 (A=~A - инвертировать A)
10111001 (G=A)

P.S. Условная передача управления будет представлять из себя взятие маски от регистра F и затем сдвиг вправо на нужное количество бит, чтобы потом прибавить это к некоему числу и получить адрес перехода по условию...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16639
Joined: 21 Oct 2009 15:08
Location: Россия

Re: Самодельный процессор nedoRISC-0

Post by Lavr »

Ты б что-нибуть прикинул уже в вентилях. По собственному опыту знаю, когда начинаешь "хотелки" превращать в вентиля,
ой как не гладко оно, порой получается... :osad:

У тебя я сразу вижу один весьма "негладкий" момент:
Получается, что у нас нету памяти данных - только код. Эту проблему можно решить скажем путём отображения какого-то регистра (скажем E) на внешнюю память
Нет, он в теории красивый, но вот в вентилях... :-?

И еще один вопрос интересный: по моим прикидкам, как не крути, но в схеме приходится применить хотя бы один тристабильный
буфер. Как ты собираешься "делать естественно только на NAND"?
iLavr
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

Мультиплексор на NAND-ах я уже прикинул на бумажке :)

А по поводу такого хитровывернутого доступа к памяти данных всё вроде как наоборот проще схемотехнически получается ;)

P.S. Я вот думаю, а не сделать ли вместо сдвига произвольного регистра на 1 бит сдвиг аккумулятора на N бит? Хотя это потребует ещё порядка полусотни корпусов 74F00 - пожалуй ненадо...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16639
Joined: 21 Oct 2009 15:08
Location: Россия

Re: Самодельный процессор nedoRISC-0

Post by Lavr »

Shaos wrote:А по поводу такого хитровывернутого доступа к памяти данных всё вроде как наоборот проще схемотехнически получается ;)
Да на словах всё проще схемотехнически получается ;)
Как дело доходит до вентилей... так и - нет. Но - желаю удачи... :wink:
iLavr
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

Вот прямо сегодня и начну городить вентиля в Logisim-e :roll:
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

Shaos wrote:Вот прямо сегодня и начну городить вентиля в Logisim-e :roll:
Вот две первые "ласточки", нарисованные в Logisim v2.7.1 - простейший D-триггер на NAND-ах (1 корпус 7400):

Image

и 8-входовой мультиплексор на NAND-ах (аналог 74151, но без входа разрешения - 6 корпусов 7400):



P.S. Вот отдельно два "кирпичика", которые я буду использовать чаще всего (чтобы читатель научился их с ходу узнавать в больших схемах) - MUX2:1 (слева) и XOR (справа):

Image Image

P.P.S. Несколько базовых схем одной картинкой (нарисовал 2 марта 2016 года):

Image
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

А вот и один "слайс" АЛУ (6 корпусов 7400), сделанный по мотивам АЛУ на NAND от Lavr-а:



Входы O0,O1,O2 задают код операции. Входы A,B,C - аргументы АЛУ. Входы H и L - соседний старший и соседний младший биты соответственно для операций RRC (000) и RLC (001). Операция 010 выдаёт на DOUT логическое NAND входных аргументов A и B, а операция 011 - XOR. Для операций 100,101,110,111 на выход DOUT просто подаётся сумма с полного сумматора (манипулирование входными аргументами для реализации ADI,SBI,ADC,SBC будет происходить снаружи).

P.S. Поначалу хотел сделать операцию AND, однако в этом случае потребовалось бы на один NAND-гейт больше и оно не влезло бы в ровное количество корпусов 7400 (я хочу каждый "слайс" в отдельной платке сделать) - в результате в системе команд имеем операцию NAND вместо AND и для реализации побитного И между аккумулятором и каким-то регистром придётся инвертировать аккумулятор:
11010rrr ; NAN rrr
10001001 ; A=A (или наверное лучше завести отдельный способ записи такой инверсии, например ~A или A=~A)

P.P.S. Интересно, что для ИЛИ теперь меньше операций потребуется, чем если бы у нас был только AND, например OR между аккумулятором и скажем регистром B делается так:
10001001 ; A=~A
10010010 ; B=~B
11010010 ; NAN B (теперь в аккумуляторе сидит A OR B)
Правда после этого регистре B остаётся с инвертированными битами...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

А вообще можно весь ассемблер таким сделать - A=A-1, A=A+8, A=B*2 и т д :)
Правда надо помнить, что в некоторых случаях (ADC,SBC,RRC,RLC) учитывается флаг C...
P.S. Как минимум можно так записать команды, где флаг C не учитывается - например вместо ADI 2 писать A=A+2, а вместо SBI 2 - A=A-2
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

А может таки сделать полноценные AND и OR, а вместо двух линеек ADI и SBI сделать одну от A=A-4 до A=A+4?...

P.S. Хотя ладно - пусть пока будет так как есть...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

Вот нагородил 4-битное АЛУ, построенное из четырёх "слайсов" (см. выше) - тут тоже любая арифметическая операция 1xx осуществляет простое сложение 4-битных входных величин A и B (обнуление флага С для ADI/SBI уже есть, а вот инверсию B для SBC надо будет делаться этажом выше) - всего получилось 4*6+6=30 корпусов 7400:



Всё проверил - работает! Всё - это RRC,RLC,NAN,XOR и A+B+C. Кстати тут мне удалось вывести C'=1 в случае логических операций NAN и XOR (в первом варианте C' выводился как при сложении даже для логических операций, т.е. его значение зависело от аргументов)

P.S. В-принципе, можно уже нарисовать и заказать платки "слайсов", которые по приходу можно собрать и воткнуть в бредборду, на которой собрать это 4-битное АЛУ и погонять на разных скоростях, наблюдая за результатом по осциллографу, чтобы оценить пиковое быстродействие...

P.P.S. На самом деле оценить можно прямо сейчас, прикинув задержки в схеме - т.к. один 74F00 гейт в среднем имеет задержку порядка 3.5 нс (5 в худшем случае), то задержка в одном слайсе будет до 9*3.5=31.5 нс (45 в худшем случае), а на всём АЛУ - 4*31.5+4*3.5=140 нс (в худшем случае 180+20=200) или 1/(2*140e-9)=3.5 МГц (в худшем случае 2.5 МГц)!

P.P.P.S. Чуть позже добавил вычисление флага переполнения V', который используется если аргументы сложения и вычитания были со знаком, а в случае неарифметических операций там будет мусор...

P.P.P.P.S. 23 февраля 2016 года добавил пару NAND-гейтов, чтоб выдавать V'=1 только в случае сложений-вычитаний (когда O2=1) и теперь количество корпусов стало ровным - можно разводить платку ;)

P.P.P.P.P.S. 1 марта 2016 года поправил взятие аргумента для сдвигов RRC/RLC (надо было B вместо A), добавил обнуление флага C в случае операций A=A+n и A=A-n, а также сделал вывод наружу сигнала /ZERO, который сигнализирует нулём, что выполняемая операция это RRC, для которой порядок исполнения нибблов должен быть обратный (сначала старший ниббл, потом младший)...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Lavr
Supreme God
Posts: 16639
Joined: 21 Oct 2009 15:08
Location: Россия

Re: Самодельный процессор nedoRISC-0

Post by Lavr »

Shaos wrote:тут мне удалось вывести C'=1 в случае логических операций NAN и XOR ;)
Хозяин, конечно, барин... но "в случае логических операций", мне что-то помнится, флаг переноса в 0 сбрасывают... нет?
iLavr
User avatar
Shaos
Admin
Posts: 23744
Joined: 09 Jan 2003 06:22
Location: Silicon Valley
Contact:

Re: Самодельный процессор nedoRISC-0

Post by Shaos »

Lavr wrote:
Shaos wrote:тут мне удалось вывести C'=1 в случае логических операций NAN и XOR ;)
Хозяин, конечно, барин... но "в случае логических операций", мне что-то помнится, флаг переноса в 0 сбрасывают... нет?
C'=1 проще ;)
Без этих гейтов на выходе C' выдавал переполнение как при сложении, даже если операция была логическая, то есть оно было то 0, то 1 в зависимости от аргументов :)
А вообще мне надо бы ещё и "overflow" флаг V тут сделать (вумные люди пишут что это просто XOR переполнения из 6 бита и переполнения из 7 бита) - и флаг V тоже вроде как должен обнуляться при логических операциях...

P.S. С другой стороны на V при логических операциях можно наплювать (пусть будет мусор), а C'=1 может оказаться полезной фичей, позволяющей достаточно просто установить флаг C в 1...
Я тут за главного - если что шлите мыло на me собака shaos точка net
Post Reply