Проект Sprinternet

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

Moderator: Shaos

User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Обновил исходники сервера в репозитории на гитлабе:

https://gitlab.com/nedopc/net

А также добавил исходники первой сетевой программы для Спринтера :)

https://gitlab.com/nedopc/net/-/blob/master/apps/sprinter-tests/inet1.asm

Сейчас она работает только в эмуляторе (скоро выложу исходники с частичной поддержкой сетевого API):
Screenshot from 2021-07-25 01-27-59.png
P.S. Вторая сетевая программа для Спринтера:

https://gitlab.com/nedopc/net/-/blob/master/apps/sprinter-tests/inet2.asm
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Как оказалось мой SprinterNet API очень похож на низкоуровневый API Spectranet (документация на сайте автора похерена):
https://web.archive.org/web/20120212190609/http://spectrum.alioth.net/doc/index.php/Spectranet:_Tutorial_2
Там даже либа для программировании на Си тоже есть, как и я планировал (правда для Z88DK).
Отсюда возникла идея - а не подружить ли SprinterNet и Spectranet? А именно:
- дать возможность со Спринтера ходить по спректранетовским ресурсам в виде TNFS-серверов;
- дать возможность использовать SprinterNet утилиты на ZX со Spectranet (как минимум утилиты командной строки и текстовые утилиты не использующие расширенную память);
- допустить собираемость спектранетовских программ под Спринтер с платой SprinterNet.
А вот запускаемость уже готовых спектранетовских бинарей на Спринтере вряд ли получится т.к. в Спектранете точки входа в API лежат в нулевом окне процессора и подменяют собой 48к ПЗУ спектрума...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Сравнение моего SprinterNet API со Spectranet API (по архиву https://web.archive.org/web/20200618075948/http://spectrum.alioth.net/doc/index.php/Software) - как оказалось они очень похожи:
Shaos wrote: #D003 - getconf (возврат IP-конфигурации путём копирования 32 байт с адреса HL и 6 байт мака с адреса DE) - возвращает конфигурацию в том виде, как она сохранена в EEPROM (имя пользователя, IP-адрес, маска, гейтвей, 3 экстра байта для DHCP и 1 байт таймзона) + MAC;
https://web.archive.org/web/20120414225619/http://spectrum.alioth.net/doc/index.php/Ifconfig_inet

Code: Select all

; get_ifconfig_inet (HLCALL 0x3E6F) - read the internet protocol address
; get_ifconfig_netmask (HLCALL 0x3E72) - read the netmask
; get_ifconfig_gw (HLCALL 0x3E75) - read the default gateway 

    ld de, inet_addr
    ld hl, GET_IFCONFIG_INET
    call HLCALL

    ld de, inet_netmask
    ld hl, GET_IFCONFIG_NETMASK
    call HLCALL

    ld de, inet_gw
    ld hl, GET_IFCONFIG_GW
    call HLCALL

; he get_ifconfig_inet(), get_ifconfig_netmask() and get_ifconfig_gw() functions fill a 4 byte buffer with 
; the current IP address, netmask and gateway respectively, in big endian form. 
Сишный интерфейс:

Code: Select all

    #include <sys/types.h>
    #include <spectranet.h>

    void get_ifconfig_inet(in_addr_t *inet_addr);
    void get_ifconfig_netmask(in_addr_t *inet_netmask);
    void get_ifconfig_gw(in_addr_t *inet_gw);
У меня все настройки забираются в один присест плюс ещё будет возможность забрать настройки в человеческом формате через псевдопеременные.
Shaos wrote: #D00C - setip (изменение IP-конфигурации с адреса HL) -> A - запись в EEPROM IP-адреса, маски и гейтвея (если IP-адрес нулевой, то в недалёком будущем оно будет в рамках локальной сети делать DHCP запрос) и возвращает код ошибки (0 если всё Ок)- изменение конфигурации повлечёт за собой ре-инициализацию визнета;
https://web.archive.org/web/20120414225619/http://spectrum.alioth.net/doc/index.php/Ifconfig_inet

Code: Select all

; get_ifconfig_inet (HLCALL 0x3E6F) - read the internet protocol address
; get_ifconfig_netmask (HLCALL 0x3E72) - read the netmask
; get_ifconfig_gw (HLCALL 0x3E75) - read the default gateway
; deconfig (HLCALL 0x3E57) - Deconfigure all internet address settings 

    ; all the functions use 4 byte buffers for the
    ; big endian address (inet_addr_t)
    ld hl, inet_addr
    ld ix, IFCONFIG_INET
    call IXCALL

    ld hl, inet_netmask
    ld ix, IFCONFIG_NETMASK
    call IXCALL

    ld hl, inet_gw
    ld ix, IFCONFIG_GW
    call IXCALL

    ld hl, DECONFIG
    call HLCALL

; The ifconfig_inet(), ifconfig_netmask() and ifconfig_gw() functions set the interface configuration for internet addresses. 
; The functions take a pointer to a 4 byte big endian internet address, netmask or gateway, defined as in_addr_t. 
; The functions make an immediate change to the relevant interface configuration, however, the change is not permanent
; and will be lost when the power is cycled or if the built in DHCP client runs on reset. Permanent changes must be made
; in the configuration stored in flash.

; The deconfig() function resets the IP address, default gateway and netmask with immediate effect. The change is not permament. 
Как можно видеть у спектранета эти настройки временные - для постоянных надо перезаписывать флеш. У меня же изменение конфигурации делается одним вызовом и это сразу меняет EEPROM и переинициализирует WizNet.

Сишный интерфейс в Спектранете:

Code: Select all

    #include <sys/types.h>
    #include <spectranet.h>

    void ifconfig_inet(in_addr_t *inet_addr);
    void ifconfig_netmask(in_addr_t *inet_netmask);
    void ifconfig_gw(in_addr_t *inet_gw);

    void deconfig();
Плюс в Спектранете есть функции для чтения и записи MAC-адреса, что в случае SprinterNet ненужно (и даже вредно):
https://web.archive.org/web/20120212192405/http://spectrum.alioth.net/doc/index.php/Sethwaddr

Code: Select all

sethwaddr (IXCALL 0x3E51) - set the MAC address
gethwaddr (HLCALL 0x3E54) - get the MAC address 
(в спектранете функция записи мак-адреса также является временной - т.е. лишь меняет мак-адрес в ОЗУ)
Shaos wrote: #D00F - socket (D=domain, E=type) -> A - возвращает следующий свободный сокет (если тип сокета AF_INET или AF_PACKET, то сокетов может быть максимум 3, а если AF_LOCAL, то скажем 16);
https://web.archive.org/web/20200217222129/http://spectrum.alioth.net/doc/index.php/Socket

Code: Select all

ld c, SOCK_STREAM       ; A reliable stream - TCP
ld hl, SOCKET           ; Call table for socket() - 0x3E00
call HLCALL             ; Trigger ROM page in
bit 7, a                ; Check for a negative return code (MSB set)
jr nz, .handle_error    ; failed to allocate a socket if the return code < 0

; at this point, A contains the file descriptor (aka socket handle)
Сишный интерфейс (на самом деле проверка на успешность должна выглядеть как if(sock >= 0) т.к. 0 это валидный номер сокета):

Code: Select all

int sock;
sock=socket(AF_INET, SOCK_STREAM, 0);
if(sock > 0)
{
   /* socket opened successfully, do something */
}
else
{
   /* handle the error */
}

// The socket function opens an end point for communication, and returns a file descriptor on success. 
// Only AF_INET sockets are supported. In the C interface, the domain and protocol parameters are 
// provided for compatibility with the BSD socket library and are ignored. The protocol parameter 
// should be set to zero; it is very possible that the protocol parameter will be used in a later release of the library. 
У меня ещё предполагалось возможность использования AF_LOCAL (UNIX-сокеты внутри машины) и AF_PACKET (RAW-сокеты):

Code: Select all

int sock_r;
sock_r=socket(AF_PACKET,SOCK_RAW,htons(ETH_P_ALL));
if(sock_r<0)
{
 printf("error in socket\n");
 return -1;
}
Shaos wrote: #D012 - bind (A=sock, HL=my_addr, E=addrlen) -> A - устанавливает порт для сокета (вызывает функцию визнета OPEN для открытия серверного сокета) и вызывает код ошибки (0 если всё Ок);
https://web.archive.org/web/20120212191405/http://spectrum.alioth.net/doc/index.php/Bind

Code: Select all

ld a, (socket_fd)   ; The socket handle, as returned by socket
ld de, 2000         ; Port number
ld hl, BIND         ; Jump table entry point - 0x3E0C
call HLCALL
jr c, .handle_error ; On error, carry flag is set

; bind() gives the socket sockfd the local address my_addr. In this implementation, only the port address is used 
; for the local address, and other parameters in the sockaddr structure are currently ignored. Fields are provided for compatibility.
; It is normally necessary to assign a local address before a SOCK_STREAM can accept incoming connections. 
; The port number passed to bind is the port that will be listened on when the listen call is made.

; Return value

; On success, the assembly language interface returns with the carry flag cleared. 
; On error, the accumulator contains the error number and the carry flag is set. 
Сишный интерфейс:

Code: Select all

#include <sys/socket.h>
#include <sys/types.h>

int sockfd;
struct sockaddr_in addr;
sock=socket(AF_INET, SOCK_STREAM, 0);
if(sock > 0)
{
   addr.sin_family = AF_INET;
   addr.sin_addr.s_addr = htonl(INADDR_ANY); /* provided for compatibility */
   addr.sin_port = htons(2000); /* htons is a no-op, but a macro is provided for compatibility */
   if(bind(sockfd, &addr, sizeof(addr)) < 0)
   {
      handle_error("bind");
   }
}

// On success, the C interface returns zero. On error, -1 is returned, and errno is set to the error number. 

// The port number is the only local address that is used, since the hardware only supports a single
// internet protocol address; in the C interface, all other fields in the sockaddr structure are ignored. 
// C programmers should still avoid invalid values in case these values are used in the future. 
// It is acceptable to zero out unused values.
Shaos wrote: #D015 - listen (A=sock, E=backlog) -> A - слушает входящие сообщения серверного TCP сокета (backlog в данный момент может принимать значения от 0 до 2 - вызывает функцию визнета LISTEN если сокет один либо OPEN/LISTEN несколько раз, если требуемых сокетов больше чем 1) и возвращает код ошибки (0 если всё Ок);
Shaos wrote: #D018 - accept (A=sock, HL=in_addr, E=addrlen) - в регистре A возвращает сокет, к которому подцепился TCP клиент (функция не имеет аналога в визнете и будет реализована программно - возвращаемый сокет может совпадать или не совпадать с входящим);
Shaos wrote: #D01B - shutdown (A=sock, E=param) - закрывает соединение правильным образом с серверной стороны в случае TCP (вызывает функцию визнета DISCON);
Shaos wrote: #D01E - connect (A=sock, HL=their_addr, E=addrlen) -> A - коннектится к серверу по TCP со стороны клиента, используя параметры адреса (вызывает функции визнета OPEN и CONNECT), возвращает код ошибки (0 если всё Ок);
Shaos wrote: #D021 - send (A=sock, HL=buf, DE=size, NO flags) -> BC - послать данные по TCP и вернуть количество переданных байт (вызывает функцию визнета SEND);
Shaos wrote: #D024 - recv (A=sock, HL=buf, DE=size, NO flags) -> BC - получить данные по TCP и вернуть количество принятых байт (вызывает функцию визнета RECV);
Shaos wrote: #D027 - sendto (A=sock, HL=buf, DE=size, NO flags, IY=out_addr) -> BC - послать данные по UDP и вернуть количество принятых байт (устанавливает адрес и порт удалённого конца и вызывает функцию визнета SEND);
Shaos wrote: #D02A - recvfrom (A=sock, HL=buf, DE=size, NO flags, IY=in_addr) -> BC - получить данные по UDP и вернуть количество принятых байт (вызывает функцию визнета RECV и копирует адрес и порт с которых пришло сообщение в in_addr);
Shaos wrote: #D02D - close (A=sock) - закрывает сокет (вызывает функцию визнета CLOSE, однако в случае серверных сокетов логика будет более запутанная, т.к. закрываемый сокет надо будет снова переиспользовать в accept);
Shaos wrote: #D030 - httpget (IY=url, HL=buf, DE=maxsize) -> BC - прочитать данные из интернета по урлу в буфер ограниченного размера (в BC возвращается количество скопированных байт либо код ответа HTTP если был установлен флаг C - причём 0 будет обозначать ошибку соединения);
В спектранете аналогичной функции (самодостаточный HTTP-клиент для забирания небольших порций данных с произвольного HTTP-сервера) попросту нет.
Shaos wrote: #D033 - resolv (HL=host) -> BCDE - выдает IP-адрес в регистрах по имени сайта, расположенному по адресу HL и заканчивающемся нулевым байтом (в первой версии IP-адрес будет искаться в записях hosts и если там не найдено или просрочилось - будет производится запрос к шлюзу, а в будущем может быть реализован честный DNS-запрос);
https://web.archive.org/web/20120212111230/http://spectrum.alioth.net/doc/index.php/Gethostbyname

Code: Select all

; gethostbyname (IXCALL 0x3E27) - get network host entry 

   ld hl, STR_HOSTNAME
   ld de, BUF_ADDRESS
   ld ix, GETHOSTBYNAME
   call IXCALL

; The gethostbyname() call converts the string passed in name to an address. The parameter name may be 
; a null-terminated hostname (such as 'www.worldofspectrum.org' or a null-terminated dotted decimal string 
; representation of an IP address. If a dotted decimal address is passed, no lookup is made, and the string 
; is converted to a 4 byte big-endian representation of the address. If a hostname is passed, the hostname 
; is looked up using the DNS protocol, and the resolved address is returned as a 4 byte big-endian value. 
; With the current implementation, only one address is returned on a successful lookup.

; For the assembly language interface, the register pair HL points to a null-terminated string containing the
; hostname or dotted decimal IP address, and the DE register pair points to a location in memory with at least
; 4 bytes free to receive the 4 byte big-endian representation of the address.

; Return values

; The assembly language interface returns with the carry flag set on error, with the A register containing the return code. 
Сишный интерфейс:

Code: Select all

   #include <netdb.h>

   struct hostent *gethostbyname(char *name);

/*
For the C function call, the pointer returned is to a statically allocated buffer. 
If the value returned needs to be preserved when a subsequent call to 
gethostbyname() is made, the value must be copied before the next call is made.
The C interface returns a null pointer if gethostbyname() fails to resolve the address.
*/
Я планирую написать совместимую по заголовочным файлам либу для Спринтера (для z88dk и для SolidC), чтобы одни и те же сишные исходники можно было бы собирать и для ZX+Specranet, и для Sprinter+SprinterNet. В репозитории спектранета есть несколько чисто сишных программ:
- сетевая игра ctfgame
- клиент irc
- tankgame
- twitter (с проксей на перле, которую думаю можно переписать на php и внедрить в наш шлюз)
ну и ещё пара простых примеров клиентов и серверов под спектранет также можно сделать пересобираемыми под SprinterNet.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Shaos wrote:Ещё идея у меня была т.к. WizNet не хранит в себе MAC-адрес (его надо программно прописывать), можно под мою карманную корпорацию официально зарезервировать диапазон MAC-адресов, записав адреса оттуда в EEPROM-ы, которые раздавать вместе с платами. Сейчас блок из 4096 адресов стоит $780 выплаченных однократно - подробнее см.https://standards.ieee.org/products-services/regauth/oui36/index.html) :dj:
Зарезервировал :)
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Напомню эпопею с прототипами SprinterNet:
SprinterNet-prototype1-small.jpg
SprinterNet-prototype2-small.jpg
Наконец-то дошли руки начать сборку третьего прототипа (через полгода после получения платок):
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Обновил фотку третьего прототипа выше после того как воткнул все микросхемы (сам модулёк WizNet располагается с другой стороны)
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Видеоролики прямых эфиров с этих выходных, в течение которых я реализовывал функций спринтернета в эмуляторе Спринтера под музыку 90х (и AY):
https://www.youtube.com/watch?v=4AB8e912gOw (функция resolv - 4 часа)
https://www.youtube.com/watch?v=BZxzXnRNljY (функция time - 3 часа)
Уже после стрима подправил реализацию time, чтобы отрабатывался функционал на тот случай, когда слишком часто запрашивают (возвращать сохранённое вместо того, чтобы каждый раз лазить на веб-сервер sprinternet.io):
Screenshot from 2021-11-14 22-17-18.png
Человеческий формат пока возвращает в UTC - потом сделаю коррекцию на текущую таймзону...
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Shaos wrote:Обновил фотку третьего прототипа выше после того как воткнул все микросхемы (сам модулёк WizNet располагается с другой стороны)
В третьем прототипе несколько сигналов на плате развелись неправильно и пересеклись - исправляется путём просверливания двух дырок, перерезания двух дорожек и напаивания двух проводков:

 FIX
shaos-ts10-brd-FIX.jpg

Однако чтобы на руках были безошибочные платы тоже, я по быстрому заказал в OSHPark исправленный вариант платы в количестве 3 штук ещё в сентябре 2021 года (это уже как бы получается четвёртый прототип платы):
SprinterNet-proto4-00.jpg
You do not have the required permissions to view the files attached to this post.
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Как говорится "из-за известных событий" концепция изменилась - теперь я не рассматриваю как рабочий вариант привязку к серийному номеру Спринтера (т.к. пути с репликантами Спринтера у меня разошлись) - теперь я рассматриваю привязку к маку сетевой карточки, которая также должна будет работать на IBM PC совместимых машинах с шиной ISA8 или ISA16...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Плюс всё ещё остаётся в планах TS2068 с совместимой картой и в будущем может появиться решение для РК-совместимых машин. Надо ещё на сервере поддержать ZX-совместимые машины с сетевым интерфейсом Spectranet, а также разрешить пользователям ходить через веб и с эмуляторов (т.е. привязка к маку должна быть необязательна), но в то же время надо как-то уметь фильтровать спамеров...
Я тут за главного - если что шлите мыло на me собака shaos точка net
TolikTrek
Writer
Posts: 10
Joined: 18 Jan 2022 09:52

Re: Project SprinterNet

Post by TolikTrek »

Shaos wrote:Плюс всё ещё остаётся в планах TS2068 с совместимой картой и в будущем может появиться решение для РК-совместимых машин. Надо ещё на сервере поддержать ZX-совместимые машины с сетевым интерфейсом Spectranet, а также разрешить пользователям ходить через веб и с эмуляторов (т.е. привязка к маку должна быть необязательна), но в то же время надо как-то уметь фильтровать спамеров...
Так и чё?
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

А чё? У вас же есть ёпс-платка - вот её и юзайте ;)

Мне пока не до спринтернета...
Я тут за главного - если что шлите мыло на me собака shaos точка net
User avatar
Shaos
Admin
Posts: 23989
Joined: 08 Jan 2003 23:22
Location: Silicon Valley

Re: Project SprinterNet

Post by Shaos »

Shaos wrote:...теперь я рассматриваю привязку к маку сетевой карточки, которая также должна будет работать на IBM PC совместимых машинах с шиной ISA8 или ISA16...
Вот чего подумалось - я тут от Z80 (недавно почившего в бозе) начал потихоньку отходить, больше концентрируясь на 8080/8085 - можно попробовать написать прошивку платки таким образом, чтобы она работала и там, и сям (а ещё у меня есть PC XT-совместимый комп с процом V20, который умеет работать и как 8088, и как 8080) - в перспективе у меня может появиться свой собственный компик на 8085 с ISA-шиной, где эта сетевушка замечательно пригодилась бы...

P.S. Вот как в бложеке https://www.bramm.dk/blog/?page_id=554 предлагается различать Z80 и 8080:

Code: Select all

mvi  a,2
ora  a       ; Clear the N flag
push psw
pop  d
ana  e       ; If a=0, this is a Z80, else a=2
Но похоже 8085 тоже как и Z80 имел флаг N (бит 1), который был недокументированный у 8085 и в народе назывался V, т.е. код выше задетектит 8085 как Z80 - надо ещё что-то найти, чтобы отличать 8085 от Z80, например второй недокументированный флаг у 8085 в народе называется K (бит 5), одна из функций которого сохранять факт 16-битного переполнения при выполнении инструкций INX/DCX и ещё кое-что (см. https://www.righto.com/2013/02/looking-at-silicon-to-understanding.html) - этот флаг в 8080 всегда равен 0, а Z80 сохраняет туда копию бита 5 результата (или аргумента, если это сравнение)...

P.P.S. Подробнее про флаг 5 у 8085 от Кена Ширриффа (righto.com):
One mystery was the purpose of the K flag: "It does not resemble any normal flag bit."[1] Its use for increment and decrement is clear, but for arithmetic operations why would you want the exclusive-or of the overflow and sign? It turns out the the K flag is useful for signed comparisons. If you're comparing two signed values, the first is smaller if the exclusive-or of the sign and overflow is 1.[6] This is exactly what the K flag computes.
т.е. бит 5 будет содержать 1 если при сравнении со знаком первый аргумент был меньше второго - например после того как мы поняли, что это 8085 или Z80 регистр A будет содержать #00 (0) и если его сравнить скажем с #FF (-1), то в случае 8085 бит 5 флагов станет равным 0, а в случае Z80 - 1:

Code: Select all

mvi  a,2
ora  a       ; Clear the N flag
push psw
pop  d
ana  e       ; If a=0, this is a Z80 or 8085, else it's 8080
jnz its_8080
cpi #FF
push psw
pop d
mvi a,#20
ana e        ; If a=0, this is a 8085, else it's z80
jz its_8085
its_z80:
...
its_8085:
...
its_8080:
Я тут за главного - если что шлите мыло на me собака shaos точка net
imsushka
Maniac
Posts: 231
Joined: 01 Jan 2022 04:34
Location: USSR, Tashkent

Re: Project SprinterNet

Post by imsushka »

а выполнить команду Z80 нельзя ? на 8080 она nopом пролетит
aviator
Maniac
Posts: 291
Joined: 10 Dec 2008 08:39
Location: Стокгольм, Швеция

Re: Project SprinterNet

Post by aviator »

Так вроде ж микроконтроллеры с ядром Z80 ещё производят. Кроме того, если ядра для FPGA. В последнем случае можно своих команд добавить, накрутить...
Z80 жил, Z80 жив, Z80 будет жить.
С уважением, Сергей.