David Rimer
/
Gigatron_Emulator
A small emulator for the gigatron created for the STM32F746G-DISCO and an NES wii controller
GigatronCPU.cpp@0:72d8735c099e, 2020-03-05 (annotated)
- Committer:
- davidr99
- Date:
- Thu Mar 05 01:07:01 2020 +0000
- Revision:
- 0:72d8735c099e
Code for the gigatron emulator
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
davidr99 | 0:72d8735c099e | 1 | #include<GigatronCPU.h> |
davidr99 | 0:72d8735c099e | 2 | |
davidr99 | 0:72d8735c099e | 3 | CPUStates GigatronCPU::CpuCycle(CPUStates states) |
davidr99 | 0:72d8735c099e | 4 | { |
davidr99 | 0:72d8735c099e | 5 | CPUState *T = states.New; |
davidr99 | 0:72d8735c099e | 6 | CPUState *state = states.Current; |
davidr99 | 0:72d8735c099e | 7 | |
davidr99 | 0:72d8735c099e | 8 | //states.CopyToNew(); |
davidr99 | 0:72d8735c099e | 9 | //memcpy(T, state, sizeof(CPUState)); // 1us |
davidr99 | 0:72d8735c099e | 10 | |
davidr99 | 0:72d8735c099e | 11 | // --- 25us |
davidr99 | 0:72d8735c099e | 12 | int data = this->ROM[state->PC]; |
davidr99 | 0:72d8735c099e | 13 | |
davidr99 | 0:72d8735c099e | 14 | |
davidr99 | 0:72d8735c099e | 15 | // --- 21us |
davidr99 | 0:72d8735c099e | 16 | T->IR = data; // GetAddressL(this->ROM, state->PC); |
davidr99 | 0:72d8735c099e | 17 | T->D = (data >> 8); // GetAddressH(this->ROM, state->PC); // 4us |
davidr99 | 0:72d8735c099e | 18 | |
davidr99 | 0:72d8735c099e | 19 | // --- 17us |
davidr99 | 0:72d8735c099e | 20 | |
davidr99 | 0:72d8735c099e | 21 | int ins = state->IR >> 5; // Instruction |
davidr99 | 0:72d8735c099e | 22 | int mod = (state->IR >> 2) & 7; // Addressing mode (or condition) |
davidr99 | 0:72d8735c099e | 23 | int bus = state->IR & 3; // Busmode |
davidr99 | 0:72d8735c099e | 24 | bool W = (ins == 6); // Write instruction? |
davidr99 | 0:72d8735c099e | 25 | bool J = (ins == 7); // Jump instruction? |
davidr99 | 0:72d8735c099e | 26 | |
davidr99 | 0:72d8735c099e | 27 | char lo = state->D; |
davidr99 | 0:72d8735c099e | 28 | char hi = 0; |
davidr99 | 0:72d8735c099e | 29 | |
davidr99 | 0:72d8735c099e | 30 | //uint32_t t0 = micros(); |
davidr99 | 0:72d8735c099e | 31 | |
davidr99 | 0:72d8735c099e | 32 | // --- 17us |
davidr99 | 0:72d8735c099e | 33 | |
davidr99 | 0:72d8735c099e | 34 | // Load address to read from |
davidr99 | 0:72d8735c099e | 35 | bool incX = false; |
davidr99 | 0:72d8735c099e | 36 | if (!J) // If we are not jumping |
davidr99 | 0:72d8735c099e | 37 | { |
davidr99 | 0:72d8735c099e | 38 | switch (mod) |
davidr99 | 0:72d8735c099e | 39 | { |
davidr99 | 0:72d8735c099e | 40 | case 0: // From 0D, _AC |
davidr99 | 0:72d8735c099e | 41 | break; |
davidr99 | 0:72d8735c099e | 42 | |
davidr99 | 0:72d8735c099e | 43 | case 1: // From OX, _AC |
davidr99 | 0:72d8735c099e | 44 | lo = state->X; |
davidr99 | 0:72d8735c099e | 45 | break; |
davidr99 | 0:72d8735c099e | 46 | |
davidr99 | 0:72d8735c099e | 47 | case 2: // From YD, _AC |
davidr99 | 0:72d8735c099e | 48 | hi = state->Y; |
davidr99 | 0:72d8735c099e | 49 | break; |
davidr99 | 0:72d8735c099e | 50 | |
davidr99 | 0:72d8735c099e | 51 | case 3: // From YX, _AC |
davidr99 | 0:72d8735c099e | 52 | lo = state->X; |
davidr99 | 0:72d8735c099e | 53 | hi = state->Y; |
davidr99 | 0:72d8735c099e | 54 | break; |
davidr99 | 0:72d8735c099e | 55 | |
davidr99 | 0:72d8735c099e | 56 | case 4: // From 0D, X |
davidr99 | 0:72d8735c099e | 57 | break; |
davidr99 | 0:72d8735c099e | 58 | |
davidr99 | 0:72d8735c099e | 59 | case 5: // From 0D, Y |
davidr99 | 0:72d8735c099e | 60 | break; |
davidr99 | 0:72d8735c099e | 61 | |
davidr99 | 0:72d8735c099e | 62 | case 6: // From 0D, OUT |
davidr99 | 0:72d8735c099e | 63 | break; |
davidr99 | 0:72d8735c099e | 64 | |
davidr99 | 0:72d8735c099e | 65 | case 7: // From Y,X++, OUT |
davidr99 | 0:72d8735c099e | 66 | lo = state->X; |
davidr99 | 0:72d8735c099e | 67 | hi = state->Y; |
davidr99 | 0:72d8735c099e | 68 | incX = true; |
davidr99 | 0:72d8735c099e | 69 | break; |
davidr99 | 0:72d8735c099e | 70 | } |
davidr99 | 0:72d8735c099e | 71 | } |
davidr99 | 0:72d8735c099e | 72 | |
davidr99 | 0:72d8735c099e | 73 | // --- 18 |
davidr99 | 0:72d8735c099e | 74 | uint16_t addr = (uint16_t)((hi << 8) | lo); //1us |
davidr99 | 0:72d8735c099e | 75 | // --- 17 |
davidr99 | 0:72d8735c099e | 76 | |
davidr99 | 0:72d8735c099e | 77 | // Feed to Data bus |
davidr99 | 0:72d8735c099e | 78 | uint8_t B = state->undef; // Data Bus |
davidr99 | 0:72d8735c099e | 79 | switch (bus) |
davidr99 | 0:72d8735c099e | 80 | { |
davidr99 | 0:72d8735c099e | 81 | case 0: |
davidr99 | 0:72d8735c099e | 82 | B = state->D; |
davidr99 | 0:72d8735c099e | 83 | break; |
davidr99 | 0:72d8735c099e | 84 | |
davidr99 | 0:72d8735c099e | 85 | case 1: |
davidr99 | 0:72d8735c099e | 86 | if (!W) |
davidr99 | 0:72d8735c099e | 87 | { |
davidr99 | 0:72d8735c099e | 88 | B = this->RAM[addr & 0x7fff]; |
davidr99 | 0:72d8735c099e | 89 | break; |
davidr99 | 0:72d8735c099e | 90 | } |
davidr99 | 0:72d8735c099e | 91 | break; |
davidr99 | 0:72d8735c099e | 92 | |
davidr99 | 0:72d8735c099e | 93 | case 2: |
davidr99 | 0:72d8735c099e | 94 | B = state->_AC; |
davidr99 | 0:72d8735c099e | 95 | break; |
davidr99 | 0:72d8735c099e | 96 | |
davidr99 | 0:72d8735c099e | 97 | case 3: |
davidr99 | 0:72d8735c099e | 98 | B = T->IN; |
davidr99 | 0:72d8735c099e | 99 | break; |
davidr99 | 0:72d8735c099e | 100 | } |
davidr99 | 0:72d8735c099e | 101 | |
davidr99 | 0:72d8735c099e | 102 | // --- 13us |
davidr99 | 0:72d8735c099e | 103 | |
davidr99 | 0:72d8735c099e | 104 | if (W) |
davidr99 | 0:72d8735c099e | 105 | { |
davidr99 | 0:72d8735c099e | 106 | this->RAM[addr & 0x7fff] = B; // Random Access Memory |
davidr99 | 0:72d8735c099e | 107 | } |
davidr99 | 0:72d8735c099e | 108 | |
davidr99 | 0:72d8735c099e | 109 | // ALU |
davidr99 | 0:72d8735c099e | 110 | uint8_t ALU = 0; // Arithmetic and Logic Unit |
davidr99 | 0:72d8735c099e | 111 | switch (ins) |
davidr99 | 0:72d8735c099e | 112 | { |
davidr99 | 0:72d8735c099e | 113 | case 0: |
davidr99 | 0:72d8735c099e | 114 | ALU = (uint8_t) B; |
davidr99 | 0:72d8735c099e | 115 | break; // LD |
davidr99 | 0:72d8735c099e | 116 | |
davidr99 | 0:72d8735c099e | 117 | case 1: |
davidr99 | 0:72d8735c099e | 118 | ALU = (uint8_t)(state->_AC & B); |
davidr99 | 0:72d8735c099e | 119 | break; // ANDA |
davidr99 | 0:72d8735c099e | 120 | |
davidr99 | 0:72d8735c099e | 121 | case 2: |
davidr99 | 0:72d8735c099e | 122 | ALU = (uint8_t)(state->_AC | B); |
davidr99 | 0:72d8735c099e | 123 | break; // ORA |
davidr99 | 0:72d8735c099e | 124 | |
davidr99 | 0:72d8735c099e | 125 | case 3: |
davidr99 | 0:72d8735c099e | 126 | ALU = (uint8_t)(state->_AC ^ B); |
davidr99 | 0:72d8735c099e | 127 | break; // XORA |
davidr99 | 0:72d8735c099e | 128 | |
davidr99 | 0:72d8735c099e | 129 | case 4: |
davidr99 | 0:72d8735c099e | 130 | ALU = (uint8_t)(state->_AC + B); |
davidr99 | 0:72d8735c099e | 131 | break; // ADDA |
davidr99 | 0:72d8735c099e | 132 | |
davidr99 | 0:72d8735c099e | 133 | case 5: |
davidr99 | 0:72d8735c099e | 134 | ALU = (uint8_t) (state->_AC - B); |
davidr99 | 0:72d8735c099e | 135 | break; // SUBA |
davidr99 | 0:72d8735c099e | 136 | |
davidr99 | 0:72d8735c099e | 137 | case 6: |
davidr99 | 0:72d8735c099e | 138 | ALU = state->_AC; |
davidr99 | 0:72d8735c099e | 139 | break; // ST |
davidr99 | 0:72d8735c099e | 140 | |
davidr99 | 0:72d8735c099e | 141 | case 7: |
davidr99 | 0:72d8735c099e | 142 | ALU = (uint8_t) -state->_AC; |
davidr99 | 0:72d8735c099e | 143 | break; // Bcc/JMP |
davidr99 | 0:72d8735c099e | 144 | } |
davidr99 | 0:72d8735c099e | 145 | |
davidr99 | 0:72d8735c099e | 146 | |
davidr99 | 0:72d8735c099e | 147 | // Output to where it needs to go |
davidr99 | 0:72d8735c099e | 148 | if (!J) // If we are not jumping & not writing |
davidr99 | 0:72d8735c099e | 149 | { |
davidr99 | 0:72d8735c099e | 150 | switch (mod) |
davidr99 | 0:72d8735c099e | 151 | { |
davidr99 | 0:72d8735c099e | 152 | case 0: // To _AC |
davidr99 | 0:72d8735c099e | 153 | case 1: |
davidr99 | 0:72d8735c099e | 154 | case 2: |
davidr99 | 0:72d8735c099e | 155 | case 3: |
davidr99 | 0:72d8735c099e | 156 | if (!W) |
davidr99 | 0:72d8735c099e | 157 | { |
davidr99 | 0:72d8735c099e | 158 | T->_AC = ALU; |
davidr99 | 0:72d8735c099e | 159 | } |
davidr99 | 0:72d8735c099e | 160 | break; |
davidr99 | 0:72d8735c099e | 161 | |
davidr99 | 0:72d8735c099e | 162 | case 4: // To X |
davidr99 | 0:72d8735c099e | 163 | T->X = ALU; |
davidr99 | 0:72d8735c099e | 164 | break; |
davidr99 | 0:72d8735c099e | 165 | |
davidr99 | 0:72d8735c099e | 166 | case 5: // To Y |
davidr99 | 0:72d8735c099e | 167 | T->Y = ALU; |
davidr99 | 0:72d8735c099e | 168 | break; |
davidr99 | 0:72d8735c099e | 169 | |
davidr99 | 0:72d8735c099e | 170 | case 6: // To OUT |
davidr99 | 0:72d8735c099e | 171 | case 7: // To OUT |
davidr99 | 0:72d8735c099e | 172 | if (!W) |
davidr99 | 0:72d8735c099e | 173 | { |
davidr99 | 0:72d8735c099e | 174 | T->OUT = ALU; |
davidr99 | 0:72d8735c099e | 175 | |
davidr99 | 0:72d8735c099e | 176 | int rising = (~state->OUT & ALU); |
davidr99 | 0:72d8735c099e | 177 | |
davidr99 | 0:72d8735c099e | 178 | if ((rising & 0x40) > 0) // hSync rising |
davidr99 | 0:72d8735c099e | 179 | { |
davidr99 | 0:72d8735c099e | 180 | T->OUTX = T->_AC; |
davidr99 | 0:72d8735c099e | 181 | } |
davidr99 | 0:72d8735c099e | 182 | } |
davidr99 | 0:72d8735c099e | 183 | break; |
davidr99 | 0:72d8735c099e | 184 | } |
davidr99 | 0:72d8735c099e | 185 | } |
davidr99 | 0:72d8735c099e | 186 | |
davidr99 | 0:72d8735c099e | 187 | if (incX) |
davidr99 | 0:72d8735c099e | 188 | { |
davidr99 | 0:72d8735c099e | 189 | T->X = (uint8_t)(state->X + 1); // Increment X |
davidr99 | 0:72d8735c099e | 190 | } |
davidr99 | 0:72d8735c099e | 191 | |
davidr99 | 0:72d8735c099e | 192 | if (J) |
davidr99 | 0:72d8735c099e | 193 | { |
davidr99 | 0:72d8735c099e | 194 | if (mod != 0) |
davidr99 | 0:72d8735c099e | 195 | { |
davidr99 | 0:72d8735c099e | 196 | // Conditional branch within page |
davidr99 | 0:72d8735c099e | 197 | int cond = (state->_AC >> 7) + 2 * (state->_AC == 0 ? 1 : 0); |
davidr99 | 0:72d8735c099e | 198 | if ((mod & (1 << cond)) > 0) // 74153 |
davidr99 | 0:72d8735c099e | 199 | { |
davidr99 | 0:72d8735c099e | 200 | T->PC = (uint16_t)((state->PC & 0xff00) | B); |
davidr99 | 0:72d8735c099e | 201 | } |
davidr99 | 0:72d8735c099e | 202 | else |
davidr99 | 0:72d8735c099e | 203 | { |
davidr99 | 0:72d8735c099e | 204 | T->PC = (uint16_t) (state->PC + 1); // Next instruction |
davidr99 | 0:72d8735c099e | 205 | } |
davidr99 | 0:72d8735c099e | 206 | } |
davidr99 | 0:72d8735c099e | 207 | else |
davidr99 | 0:72d8735c099e | 208 | { |
davidr99 | 0:72d8735c099e | 209 | T->PC = (uint16_t)((state->Y << 8) | B); // Unconditional far jump |
davidr99 | 0:72d8735c099e | 210 | } |
davidr99 | 0:72d8735c099e | 211 | } |
davidr99 | 0:72d8735c099e | 212 | else |
davidr99 | 0:72d8735c099e | 213 | { |
davidr99 | 0:72d8735c099e | 214 | T->PC = (uint16_t) (state->PC + 1); // Next instruction |
davidr99 | 0:72d8735c099e | 215 | } |
davidr99 | 0:72d8735c099e | 216 | |
davidr99 | 0:72d8735c099e | 217 | //uint32_t t1 = micros(); |
davidr99 | 0:72d8735c099e | 218 | //uint32_t delta_t = t1 - t0; |
davidr99 | 0:72d8735c099e | 219 | //Serial.printf( "Delta = %u\n", delta_t ); // this prints around 51 on my system. |
davidr99 | 0:72d8735c099e | 220 | |
davidr99 | 0:72d8735c099e | 221 | |
davidr99 | 0:72d8735c099e | 222 | memcpy(state, T, sizeof(CPUState)); // 2us |
davidr99 | 0:72d8735c099e | 223 | //states.CopyNewToCurrent(); |
davidr99 | 0:72d8735c099e | 224 | |
davidr99 | 0:72d8735c099e | 225 | return states; |
davidr99 | 0:72d8735c099e | 226 | } |