начну пожалуй с фреймворка для написания микропроцессоров, над которым будет построен 8080 (и 8085), далее 6502, а потом и всякие пики подтянутся
для начала максимально абстрагируемся от конкретных микропроцессоров - представим, что у нас есть некий API по доступу к 8-битной памяти, адресуемой 16-битным адресом, причём у памяти есть "слои" (например для 8080 слой 0 может обозначать память, а слой 1 - порты ввода-вывода)
| | |
| Code: typedef char NEDOSIGNAL; /* suggested values 'H','L','Z' */ typedef unsigned char NEDOBYTE; typedef unsigned short NEDOWORD; typedef unsigned long NEDODWORD;
typedef NEDOBYTE (*NEDOFUN_RD)(void*,int,NEDOWORD); /* read callback */ typedef void (*NEDOFUN_WR)(void*,int,NEDOWORD,NEDOBYTE); /* write callback */ typedef void (*NEDOFUN_ER)(void*,char*); /* error callback */ typedef int (*NEDOFUN_EX)(void*,NEDOBYTE); /* execution callback returns number of cycles to simulate */
#define NEDOMACHINE_SIGN "NEDOMAC"
typedef struct _NEDOMACHINE { char sign[8]; /* signature "NEDOMAC",\0 */ NEDOWORD addr; /* current address */ NEDOFUN_RD rfun; /* pointer to read function */ NEDOFUN_WR wfun; /* pointer to write function */ NEDOFUN_ER efun; /* pointer to error function */ NEDOFUN_EX xfun[256]; /* 256 pointers to execution functions */ NEDOBYTE data[1]; /* custom data of any size */ } NEDOMACHINE;
NEDOMACHINE* nedomachine_new(int datasz, NEDOFUN_RD rfun, NEDOFUN_WR wfun, NEDOFUN_ER efun); void nedomachine_operation(NEDOMACHINE *m, NEDOBYTE opcode, NEDOFUN_EX xfun); void nedomachine_step(NEDOMACHINE *m); void nedomachine_destroy(NEDOMACHINE *m);
| |
| | |
в общем случае "машин" в программе может быть создано много - коллбеки могут их различать по указателю на активную машину
nedomachine_new создаёт новую машину с указанием размера данных, под которые также должна быть аллоцирована память, а также указателей на читающую и пишущую функции для доступа к памяти, позже добавил функцию обработки ошибок (может быть NULL)
nedomachine_operation добавляет функцию-обработчик инструкции процессора с кодом opcode
nedomachine_step производит один шаг симуляции за который будет выполнена одна команда либо один такт процессора (зависит от конкретной реализации исполняющих коллбеков)
nedomachine_destroy освобождает память удаляя ранее созданный объект
в момент когда нужно обработать команду (внутри nedomachine_step), машина увеличит текущий адрес на единицу и вызовет коллбек-функцию с индексом, соответствующим ранее прочитанной команде (функция типа NEDOFUN_EX)
P.S. 26 августа добавил сигнатуру, коллбек для обработки ошибок и переименовал некоторые функции вернув обратно понятие шага эмуляции step
P.P.S. 27 августа понял, что в этом фреймворке можно не только процессоры эмулить, но и
произвольные микрокодовые конструкции, причём как с автоматическим инкрементом адреса, так и без...