A small emulator for the gigatron created for the STM32F746G-DISCO and an NES wii controller

GigatronCPU.cpp

Committer:
davidr99
Date:
2020-03-05
Revision:
0:72d8735c099e

File content as of revision 0:72d8735c099e:

#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;
}