mirror of
https://github.com/TomHarte/CLK.git
synced 2024-07-10 12:29:01 +00:00
Added a compact and copy stage for instruction pages, both [mostly] eliminating the mistake of letting static data structures contain pointers to instance storage and opening the door for addition of the DD and FD pages.
This commit is contained in:
parent
c70dfe1b09
commit
5dcfd85642
@ -10,6 +10,7 @@
|
|||||||
#define Z80_hpp
|
#define Z80_hpp
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
#include <cstring>
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
#include "../MicroOpScheduler.hpp"
|
#include "../MicroOpScheduler.hpp"
|
||||||
@ -71,14 +72,14 @@ enum BusOperation {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct MachineCycle {
|
struct MachineCycle {
|
||||||
const BusOperation operation;
|
BusOperation operation;
|
||||||
const int length;
|
int length;
|
||||||
const uint16_t *address;
|
uint16_t *address;
|
||||||
uint8_t *const value;
|
uint8_t *value;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MicroOp {
|
struct MicroOp {
|
||||||
enum {
|
enum Type {
|
||||||
BusOperation,
|
BusOperation,
|
||||||
DecodeOperation,
|
DecodeOperation,
|
||||||
MoveToNextProgram,
|
MoveToNextProgram,
|
||||||
@ -122,7 +123,8 @@ struct MicroOp {
|
|||||||
SetInstructionPage,
|
SetInstructionPage,
|
||||||
|
|
||||||
None
|
None
|
||||||
} type;
|
};
|
||||||
|
Type type;
|
||||||
void *source;
|
void *source;
|
||||||
void *destination;
|
void *destination;
|
||||||
MachineCycle machine_cycle;
|
MachineCycle machine_cycle;
|
||||||
@ -156,9 +158,23 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
uint8_t temp8_;
|
uint8_t temp8_;
|
||||||
|
|
||||||
MicroOp **current_instruction_page_;
|
MicroOp **current_instruction_page_;
|
||||||
MicroOp *base_page_[256];
|
struct InstructionPage {
|
||||||
MicroOp *ed_page_[256];
|
MicroOp *instructions[256];
|
||||||
MicroOp *fd_page_[256];
|
MicroOp *all_operations;
|
||||||
|
|
||||||
|
InstructionPage() : all_operations(nullptr) {
|
||||||
|
for(int c = 0; c < 256; c++) {
|
||||||
|
instructions[c] = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~InstructionPage() {
|
||||||
|
delete[] all_operations;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
InstructionPage base_page_;
|
||||||
|
InstructionPage ed_page_;
|
||||||
|
InstructionPage fd_page_;
|
||||||
|
|
||||||
#define XX {MicroOp::None, 0}
|
#define XX {MicroOp::None, 0}
|
||||||
|
|
||||||
@ -208,15 +224,34 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
|
|
||||||
typedef MicroOp InstructionTable[256][20];
|
typedef MicroOp InstructionTable[256][20];
|
||||||
|
|
||||||
void assemble_page(MicroOp **target, InstructionTable &table) {
|
void assemble_page(InstructionPage &target, InstructionTable &table) {
|
||||||
|
size_t number_of_micro_ops = 0;
|
||||||
|
size_t lengths[256];
|
||||||
|
|
||||||
|
// Count number of micro-ops required.
|
||||||
for(int c = 0; c < 256; c++) {
|
for(int c = 0; c < 256; c++) {
|
||||||
target[c] = table[c];
|
size_t length = 0;
|
||||||
|
while(table[c][length].type != MicroOp::MoveToNextProgram && table[c][length].type != MicroOp::None) length++;
|
||||||
|
length++;
|
||||||
|
lengths[c] = length;
|
||||||
|
number_of_micro_ops += length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate a landing area.
|
||||||
|
target.all_operations = new MicroOp[number_of_micro_ops];
|
||||||
|
|
||||||
|
// Copy in all programs and set pointers.
|
||||||
|
size_t destination = 0;
|
||||||
|
for(int c = 0; c < 256; c++) {
|
||||||
|
memcpy(&target.all_operations[destination], table[c], lengths[c] * sizeof(MicroOp));
|
||||||
|
target.instructions[c] = &target.all_operations[destination];
|
||||||
|
destination += lengths[c];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void assemble_ed_page(MicroOp **target) {
|
void assemble_ed_page(InstructionPage &target) {
|
||||||
#define NOP_ROW() XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX
|
#define NOP_ROW() XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX, XX
|
||||||
static InstructionTable ed_program_table = {
|
InstructionTable ed_program_table = {
|
||||||
NOP_ROW(), /* 0x00 */
|
NOP_ROW(), /* 0x00 */
|
||||||
NOP_ROW(), /* 0x10 */
|
NOP_ROW(), /* 0x10 */
|
||||||
NOP_ROW(), /* 0x20 */
|
NOP_ROW(), /* 0x20 */
|
||||||
@ -251,7 +286,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
#undef NOP_ROW
|
#undef NOP_ROW
|
||||||
}
|
}
|
||||||
|
|
||||||
void assemble_base_page(MicroOp **target) {
|
void assemble_base_page(InstructionPage &target) {
|
||||||
#define INC_DEC_LD(r) \
|
#define INC_DEC_LD(r) \
|
||||||
Program({MicroOp::Increment8, &r}), \
|
Program({MicroOp::Increment8, &r}), \
|
||||||
Program({MicroOp::Decrement8, &r}), \
|
Program({MicroOp::Decrement8, &r}), \
|
||||||
@ -263,7 +298,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
#define DEC_INC_DEC_LD(rf, r) \
|
#define DEC_INC_DEC_LD(rf, r) \
|
||||||
Program(WAIT(2), {MicroOp::Decrement16, &rf.full}), INC_DEC_LD(r)
|
Program(WAIT(2), {MicroOp::Decrement16, &rf.full}), INC_DEC_LD(r)
|
||||||
|
|
||||||
static InstructionTable base_program_table = {
|
InstructionTable base_program_table = {
|
||||||
/* 0x00 NOP */ { {MicroOp::MoveToNextProgram} }, /* 0x01 LD BC, nn */ Program(FETCH16(bc_, pc_)),
|
/* 0x00 NOP */ { {MicroOp::MoveToNextProgram} }, /* 0x01 LD BC, nn */ Program(FETCH16(bc_, pc_)),
|
||||||
/* 0x02 LD (BC), A */ Program(STOREL(a_, bc_)),
|
/* 0x02 LD (BC), A */ Program(STOREL(a_, bc_)),
|
||||||
|
|
||||||
@ -400,7 +435,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
/* 0xe7 RST 20h */ XX,
|
/* 0xe7 RST 20h */ XX,
|
||||||
/* 0xe8 RET PE */ RET(TestPE), /* 0xe9 JP (HL) */ Program({MicroOp::Move16, &hl_.full, &pc_.full}),
|
/* 0xe8 RET PE */ RET(TestPE), /* 0xe9 JP (HL) */ Program({MicroOp::Move16, &hl_.full, &pc_.full}),
|
||||||
/* 0xea JP PE */ JP(TestPE), /* 0xeb EX DE, HL */Program({MicroOp::ExDEHL}),
|
/* 0xea JP PE */ JP(TestPE), /* 0xeb EX DE, HL */Program({MicroOp::ExDEHL}),
|
||||||
/* 0xec CALL PE */ CALL(TestPE), /* 0xed [ED page] */Program({MicroOp::SetInstructionPage, ed_page_}),
|
/* 0xec CALL PE */ CALL(TestPE), /* 0xed [ED page] */Program({MicroOp::SetInstructionPage, &ed_page_}),
|
||||||
/* 0xee XOR n */ Program(FETCH(temp8_, pc_), {MicroOp::Xor, &temp8_}),
|
/* 0xee XOR n */ Program(FETCH(temp8_, pc_), {MicroOp::Xor, &temp8_}),
|
||||||
/* 0xef RST 28h */ XX,
|
/* 0xef RST 28h */ XX,
|
||||||
/* 0xf0 RET p */ RET(TestP), /* 0xf1 POP AF */ Program(POP(temp16_), {MicroOp::DisassembleAF}),
|
/* 0xf0 RET p */ RET(TestP), /* 0xf1 POP AF */ Program(POP(temp16_), {MicroOp::DisassembleAF}),
|
||||||
@ -410,7 +445,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
/* 0xf7 RST 30h */ XX,
|
/* 0xf7 RST 30h */ XX,
|
||||||
/* 0xf8 RET M */ RET(TestM), /* 0xf9 LD SP, HL */Program(WAIT(2), {MicroOp::Move16, &hl_.full, &sp_.full}),
|
/* 0xf8 RET M */ RET(TestM), /* 0xf9 LD SP, HL */Program(WAIT(2), {MicroOp::Move16, &hl_.full, &sp_.full}),
|
||||||
/* 0xfa JP M */ JP(TestM), /* 0xfb EI */ Program({MicroOp::EI}),
|
/* 0xfa JP M */ JP(TestM), /* 0xfb EI */ Program({MicroOp::EI}),
|
||||||
/* 0xfc CALL M */ CALL(TestM), /* 0xfd [FD page] */Program({MicroOp::SetInstructionPage, fd_page_}),
|
/* 0xfc CALL M */ CALL(TestM), /* 0xfd [FD page] */Program({MicroOp::SetInstructionPage, &fd_page_}),
|
||||||
/* 0xfe CP n */ Program(FETCH(temp8_, pc_), {MicroOp::CP8, &temp8_}),
|
/* 0xfe CP n */ Program(FETCH(temp8_, pc_), {MicroOp::CP8, &temp8_}),
|
||||||
/* 0xff RST 38h */ XX,
|
/* 0xff RST 38h */ XX,
|
||||||
};
|
};
|
||||||
@ -420,8 +455,8 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
void decode_operation(uint8_t operation) {
|
void decode_operation(uint8_t operation) {
|
||||||
if(current_instruction_page_[operation]->type == MicroOp::None) {
|
if(current_instruction_page_[operation]->type == MicroOp::None) {
|
||||||
uint8_t page = 0x00;
|
uint8_t page = 0x00;
|
||||||
if(current_instruction_page_ == ed_page_) page = 0xed;
|
if(current_instruction_page_ == ed_page_.instructions) page = 0xed;
|
||||||
if(current_instruction_page_ == fd_page_) page = 0xfd;
|
if(current_instruction_page_ == fd_page_.instructions) page = 0xfd;
|
||||||
printf("Unknown Z80 operation %02x %02x!!!\n", page, operation);
|
printf("Unknown Z80 operation %02x %02x!!!\n", page, operation);
|
||||||
}
|
}
|
||||||
schedule_program(current_instruction_page_[operation]);
|
schedule_program(current_instruction_page_[operation]);
|
||||||
@ -443,6 +478,8 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
@param number_of_cycles The number of cycles to run the Z80 for.
|
@param number_of_cycles The number of cycles to run the Z80 for.
|
||||||
*/
|
*/
|
||||||
void run_for_cycles(int number_of_cycles) {
|
void run_for_cycles(int number_of_cycles) {
|
||||||
|
// TODO: this can't legitimately be static and contain references to this via pc_ and operation_;
|
||||||
|
// make it something else that is built at instance construction.
|
||||||
static const MicroOp fetch_decode_execute[] = {
|
static const MicroOp fetch_decode_execute[] = {
|
||||||
{ MicroOp::BusOperation, nullptr, nullptr, {ReadOpcode, 4, &pc_.full, &operation_}},
|
{ MicroOp::BusOperation, nullptr, nullptr, {ReadOpcode, 4, &pc_.full, &operation_}},
|
||||||
{ MicroOp::DecodeOperation },
|
{ MicroOp::DecodeOperation },
|
||||||
@ -451,7 +488,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
|
|
||||||
#define checkSchedule() \
|
#define checkSchedule() \
|
||||||
if(!scheduled_programs_[schedule_programs_read_pointer_]) {\
|
if(!scheduled_programs_[schedule_programs_read_pointer_]) {\
|
||||||
current_instruction_page_ = base_page_;\
|
current_instruction_page_ = base_page_.instructions;\
|
||||||
schedule_program(fetch_decode_execute);\
|
schedule_program(fetch_decode_execute);\
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -801,7 +838,7 @@ template <class T> class Processor: public MicroOpScheduler<MicroOp> {
|
|||||||
|
|
||||||
case MicroOp::SetInstructionPage:
|
case MicroOp::SetInstructionPage:
|
||||||
schedule_program(fetch_decode_execute);
|
schedule_program(fetch_decode_execute);
|
||||||
current_instruction_page_ = (CPU::Z80::MicroOp **)operation->source;
|
current_instruction_page_ = ((InstructionPage *)operation->source)->instructions;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user