// Definindo os pinos de endereço, dados e controle
const int addressPins[] = {22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37};
const int dataPins[] = {38, 39, 40, 41, 42, 43, 44, 45};
const int RW = 46;
const int PHI2 = 47;
const int RESET = 48;

// Exemplo de programa binário (8 bytes)
const byte program[] = {0xA9, 0x42, 0x8D, 0x80, 0x00};

// Função para configurar o Timer 3 para gerar o sinal de clock
void setupClockSignal() {
  // Configurar o pino 47 como saída
  pinMode(47, OUTPUT);

  // Configurar o Timer 3 no modo Fast PWM, com prescaler de 1
  TCCR3A = (1 << COM3B0) | (1 << WGM31) | (1 << WGM30);
  TCCR3B = (1 << WGM33) | (1 << WGM32) | (1 << CS30);

  // Definir o valor do registrador de comparação para obter um clock de ~1 MHz
  OCR3B = 7;
}

void setup() {
  // Inicialize a comunicação serial
  Serial.begin(9600);

  // Configurando pinos de endereço, dados e controle
  for (int i = 0; i < 16; i++) {
    pinMode(addressPins[i], OUTPUT);
  }

  for (int i = 0; i < 8; i++) {
    pinMode(dataPins[i], OUTPUT);
  }

  pinMode(RW, OUTPUT);
  pinMode(PHI2, OUTPUT);
  pinMode(RESET, OUTPUT);

  // Configurar o sinal de clock
  setupClockSignal();

  // Reset no 6502
  digitalWrite(RESET, LOW);
  delay(10);
  digitalWrite(RESET, HIGH);
  delay(10);

  // Enviando o programa para o 6502
  for (int i = 0; i < sizeof(program); i++) {
    setAddress(i);
    setData(program[i]);
    digitalWrite(RW, LOW); // Escrever na memória
    digitalWrite(PHI2, HIGH);
    delayMicroseconds(1);
    digitalWrite(PHI2, LOW);
    delayMicroseconds(1);
  }

  // Aguarde um momento para o 6502 executar o programa
  delay(1000);

  // Definindo o endereço de memória que você deseja ler
  unsigned int memoryAddressToRead = 0x80; // Substitua este valor pelo endereço de memória que você deseja ler

  // Configurando os pinos de dados como entrada
  for (int i = 0; i < 8; i++) {
    pinMode(dataPins[i], INPUT);
  }

  // Lendo o valor no endereço de memória especificado
  setAddress(memoryAddressToRead);
  digitalWrite(RW, HIGH); // Ler da memória
  digitalWrite(PHI2, HIGH);
  delayMicroseconds(1);
  byte valueRead = getData();
  digitalWrite(PHI2, LOW);
  delayMicroseconds(1);

  // Imprimindo o valor lido usando Serial.print()
  Serial.print("Valor lido no endereço 0x");
  Serial.print(memoryAddressToRead, HEX);
  Serial.print(": 0x");
  Serial.println(valueRead, HEX);
}

void loop() {
  // Neste exemplo, o loop principal não faz nada.
}

void setAddress(unsigned int address) {
  for (int i = 0; i < 16; i++) {
    digitalWrite(addressPins[i], (address >> i) & 0x01);
  }
}

void setData(byte data) {
  for (int i = 0; i < 8; i++) {
    digitalWrite(dataPins[i], (data >> i) & 0x01);
  }
}

byte getData() {
  byte data = 0;
  for (int i = 0; i < 8; i++) {
    data |= digitalRead(dataPins[i]) << i;
  }
  return data;
}
mega:SCL
mega:SDA
mega:AREF
mega:GND.1
mega:13
mega:12
mega:11
mega:10
mega:9
mega:8
mega:7
mega:6
mega:5
mega:4
mega:3
mega:2
mega:1
mega:0
mega:14
mega:15
mega:16
mega:17
mega:18
mega:19
mega:20
mega:21
mega:5V.1
mega:5V.2
mega:22
mega:23
mega:24
mega:25
mega:26
mega:27
mega:28
mega:29
mega:30
mega:31
mega:32
mega:33
mega:34
mega:35
mega:36
mega:37
mega:38
mega:39
mega:40
mega:41
mega:42
mega:43
mega:44
mega:45
mega:46
mega:47
mega:48
mega:49
mega:50
mega:51
mega:52
mega:53
mega:GND.4
mega:GND.5
mega:IOREF
mega:RESET
mega:3.3V
mega:5V
mega:GND.2
mega:GND.3
mega:VIN
mega:A0
mega:A1
mega:A2
mega:A3
mega:A4
mega:A5
mega:A6
mega:A7
mega:A8
mega:A9
mega:A10
mega:A11
mega:A12
mega:A13
mega:A14
mega:A15
$abcdeabcde151015202530354045505560fghijfghij
MOS 6502 CPUBreakout
chip1:RDY
chip1:clk
chip1:AB0
chip1:AB1
chip1:AB2
chip1:AB3
chip1:AB4
chip1:AB5
chip1:AB6
chip1:AB7
chip1:AB8
chip1:AB9
chip1:AB10
chip1:AB11
chip1:AB12
chip1:AB13
chip1:AB14
chip1:AB15
chip1:DI7
chip1:DI6
chip1:DI5
chip1:DI4
chip1:DI3
chip1:DI2
chip1:DI1
chip1:DI0
chip1:DO7
chip1:DO6
chip1:DO5
chip1:DO4
chip1:DO3
chip1:DO2
chip1:DO1
chip1:DO0
chip1:WE
chip1:IRQ
chip1:NMI
chip1:reset