David Rimer
/
Gigatron_Emulator
A small emulator for the gigatron created for the STM32F746G-DISCO and an NES wii controller
Diff: GigatronCPU.cpp
- Revision:
- 0:72d8735c099e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/GigatronCPU.cpp Thu Mar 05 01:07:01 2020 +0000 @@ -0,0 +1,226 @@ +#include<GigatronCPU.h> + +CPUStates GigatronCPU::CpuCycle(CPUStates states) +{ + CPUState *T = states.New; + CPUState *state = states.Current; + + //states.CopyToNew(); + //memcpy(T, state, sizeof(CPUState)); // 1us + + // --- 25us + int data = this->ROM[state->PC]; + + + // --- 21us + T->IR = data; // GetAddressL(this->ROM, state->PC); + T->D = (data >> 8); // GetAddressH(this->ROM, state->PC); // 4us + + // --- 17us + + int ins = state->IR >> 5; // Instruction + int mod = (state->IR >> 2) & 7; // Addressing mode (or condition) + int bus = state->IR & 3; // Busmode + bool W = (ins == 6); // Write instruction? + bool J = (ins == 7); // Jump instruction? + + char lo = state->D; + char hi = 0; + + //uint32_t t0 = micros(); + + // --- 17us + + // Load address to read from + bool incX = false; + if (!J) // If we are not jumping + { + switch (mod) + { + case 0: // From 0D, _AC + break; + + case 1: // From OX, _AC + lo = state->X; + break; + + case 2: // From YD, _AC + hi = state->Y; + break; + + case 3: // From YX, _AC + lo = state->X; + hi = state->Y; + break; + + case 4: // From 0D, X + break; + + case 5: // From 0D, Y + break; + + case 6: // From 0D, OUT + break; + + case 7: // From Y,X++, OUT + lo = state->X; + hi = state->Y; + incX = true; + break; + } + } + + // --- 18 + uint16_t addr = (uint16_t)((hi << 8) | lo); //1us + // --- 17 + + // Feed to Data bus + uint8_t B = state->undef; // Data Bus + switch (bus) + { + case 0: + B = state->D; + break; + + case 1: + if (!W) + { + B = this->RAM[addr & 0x7fff]; + break; + } + break; + + case 2: + B = state->_AC; + break; + + case 3: + B = T->IN; + break; + } + + // --- 13us + + if (W) + { + this->RAM[addr & 0x7fff] = B; // Random Access Memory + } + + // ALU + uint8_t ALU = 0; // Arithmetic and Logic Unit + switch (ins) + { + case 0: + ALU = (uint8_t) B; + break; // LD + + case 1: + ALU = (uint8_t)(state->_AC & B); + break; // ANDA + + case 2: + ALU = (uint8_t)(state->_AC | B); + break; // ORA + + case 3: + ALU = (uint8_t)(state->_AC ^ B); + break; // XORA + + case 4: + ALU = (uint8_t)(state->_AC + B); + break; // ADDA + + case 5: + ALU = (uint8_t) (state->_AC - B); + break; // SUBA + + case 6: + ALU = state->_AC; + break; // ST + + case 7: + ALU = (uint8_t) -state->_AC; + break; // Bcc/JMP + } + + + // Output to where it needs to go + if (!J) // If we are not jumping & not writing + { + switch (mod) + { + case 0: // To _AC + case 1: + case 2: + case 3: + if (!W) + { + T->_AC = ALU; + } + break; + + case 4: // To X + T->X = ALU; + break; + + case 5: // To Y + T->Y = ALU; + break; + + case 6: // To OUT + case 7: // To OUT + if (!W) + { + T->OUT = ALU; + + int rising = (~state->OUT & ALU); + + if ((rising & 0x40) > 0) // hSync rising + { + T->OUTX = T->_AC; + } + } + break; + } + } + + if (incX) + { + T->X = (uint8_t)(state->X + 1); // Increment X + } + + if (J) + { + if (mod != 0) + { + // Conditional branch within page + int cond = (state->_AC >> 7) + 2 * (state->_AC == 0 ? 1 : 0); + if ((mod & (1 << cond)) > 0) // 74153 + { + T->PC = (uint16_t)((state->PC & 0xff00) | B); + } + else + { + T->PC = (uint16_t) (state->PC + 1); // Next instruction + } + } + else + { + T->PC = (uint16_t)((state->Y << 8) | B); // Unconditional far jump + } + } + else + { + T->PC = (uint16_t) (state->PC + 1); // Next instruction + } + + //uint32_t t1 = micros(); + //uint32_t delta_t = t1 - t0; + //Serial.printf( "Delta = %u\n", delta_t ); // this prints around 51 on my system. + + + memcpy(state, T, sizeof(CPUState)); // 2us + //states.CopyNewToCurrent(); + + return states; +}