Code: Select all
#include <Arduino.h>
#include <esp_task_wdt.h>
#include "driver/ledc.h"
byte pinDados[8] = {13, 12, 14, 27, 26, 25, 33, 32};
byte pinEndereco[8] = {35, 34, 39, 36, 15, 2, 4, 16};
byte pinIORQ = 22;
byte pinRST = 21;
byte pinWR = 19;
byte pinRD = 18;
byte pinMREQ = 5;
byte pinZ80 = 23;
byte memory[0x100];
byte program[] = {
0x21, 0x0a, 0x00, // ld hl, ??
0x0e, 0x00, // ld c, 0
0x06, 0x26, // ld b, 38
0xed, 0xb3, // otir
0x76, // halt
'\x1B', '[', '3', '8', ';', '2', ';', '0', '7', '0', ';', '2', '0', '0', ';', '1', '8', '0', 'm',
'O', 'i', ' ', 'Z', '8', '0', '!', '\n',
'T', 'c', 'h', 'a', 'u', '!', '\n',
'\x1B', '[', '0', 'm'};
const int timerPin = 17;
String portaZ80_buf;
#define RESETAR(estado) estado ? digitalWrite(pinRST, 0) : digitalWrite(pinRST, 1);
bool running = false;
void IRAM_ATTR intWriteCPU();
void IRAM_ATTR intReadCPU();
void IRAM_ATTR interrupcoes();
uint16_t readAddress();
void writeData(byte data);
byte readData();
void setDataDir(int dir)
{
for (int i = 0; i < sizeof(pinDados); i++)
{
pinMode(pinDados[i], dir);
}
}
uint16_t readAddress()
{
uint16_t address = 0;
for (int i = 0; i < sizeof(pinEndereco); i++)
{
address |= (digitalRead(pinEndereco[i]) & 1) << i;
}
return address;
}
void writeData(byte data)
{
setDataDir(OUTPUT);
for (int i = 0; i < sizeof(pinDados); i++)
{
digitalWrite(pinDados[i], (data >> i) & 1);
}
}
byte readData()
{
byte data = 0;
setDataDir(INPUT);
for (int i = 0; i < sizeof(pinDados); i++)
{
data |= (digitalRead(pinDados[i]) & 1) << i;
}
return data;
}
uint32_t oscilador = 10000; // Frequencia inicial do oscilador - 12543 Hz
uint32_t mDuty = 0; // Valor calculado do ciclo de trabalho
uint32_t resolucao = 0; // Valor calculado da resolucao
void setup()
{
Serial.begin(115200);
while (!Serial)
;
memset(memory, 0, sizeof(memory));
memcpy(memory, program, sizeof(program));
for (int i = 0; i < sizeof(pinEndereco); i++)
{
pinMode(pinEndereco[i], INPUT);
}
writeData(0x00);
pinMode(timerPin, OUTPUT);
pinMode(pinRST, OUTPUT);
pinMode(pinZ80, OUTPUT);
pinMode(pinWR, INPUT_PULLUP);
pinMode(pinRD, INPUT_PULLUP);
pinMode(pinMREQ, INPUT_PULLUP);
pinMode(pinIORQ, INPUT_PULLUP);
digitalWrite(pinZ80, LOW);
/*esp_timer_create_args_t timerConfig = {
.callback = onTimer,
.arg = NULL,
.name = "clock_timer"};
esp_timer_handle_t timer;
esp_timer_create(&timerConfig, &timer);
esp_timer_start_periodic(timer, 90);*/
resolucao = (log(80000000 / oscilador) / log(2)) / 2; // Calculo da resolucao para o oscilador
if (resolucao < 1)
resolucao = 1; // Resoluçao mínima
// Serial.println(resolucao); // Print
mDuty = (pow(2, resolucao)) / 2; // Calculo do ciclo de trabalho 50% do pulso
// Serial.println(mDuty); // Print
ledc_timer_config_t ledc_timer = {}; // Instancia a configuracao do timer do LEDC
ledc_timer.duty_resolution = ledc_timer_bit_t(resolucao); // Configura resolucao
ledc_timer.freq_hz = oscilador; // Configura a frequencia do oscilador
ledc_timer.speed_mode = LEDC_HIGH_SPEED_MODE; // Modo de operacao em alta velocidade
ledc_timer.timer_num = LEDC_TIMER_0; // Usar timer0 do LEDC
ledc_timer_config(&ledc_timer); // Configura o timer do LEDC
ledc_channel_config_t ledc_channel = {}; // Instancia a configuracao canal do LEDC
ledc_channel.channel = LEDC_CHANNEL_0; // Configura canal 0
ledc_channel.duty = mDuty; // Configura o ciclo de trabalho
ledc_channel.gpio_num = timerPin; // Configura GPIO da saida do LEDC - oscilador
ledc_channel.intr_type = LEDC_INTR_DISABLE; // Desabilita interrupção do LEDC
ledc_channel.speed_mode = LEDC_HIGH_SPEED_MODE; // Modo de operacao do canal em alta velocidade
ledc_channel.timer_sel = LEDC_TIMER_0; // Seleciona timer 0 do LEDC
ledc_channel_config(&ledc_channel); // Configura o canal do LEDC
interrupcoes();
printf("\x1B[32mBem-vindo ao Subsistema Z80!\x1B[0m\n");
printf("Pressione a tecla Enter para ligar o Z80...\n");
}
void loop()
{
if (Serial.available())
{
char keyPressed = Serial.read();
switch (keyPressed)
{
case 0x1B:
if (running)
{
running = false;
printf("Resetando Z80...\n");
RESETAR(1);
delay(1);
RESETAR(0);
running = true;
}
break;
case 0x0D:
if (!running)
{
running = true;
printf("Ligando Z80...\n");
digitalWrite(pinZ80, HIGH);
RESETAR(1);
delay(1);
RESETAR(0);
}
break;
case 0x70:
printf("Imprimindo dados da porta...\n");
printf(portaZ80_buf.c_str());
portaZ80_buf = "";
break;
default:
break;
}
}
}
void IRAM_ATTR interrupcoes()
{
attachInterrupt(pinWR, intWriteCPU, FALLING);
attachInterrupt(pinRD, intReadCPU, FALLING);
}
void IRAM_ATTR intWriteCPU()
{
int MREQ = !gpio_get_level((gpio_num_t)pinMREQ);
int IORQ = !gpio_get_level((gpio_num_t)pinIORQ);
if (MREQ && running)
{
memory[readAddress()] = readData();
}
else if (IORQ && running)
{
portaZ80_buf += (char)readData();
}
}
void IRAM_ATTR intReadCPU()
{
int MREQ = !gpio_get_level((gpio_num_t)pinMREQ);
// int IORQ = !gpio_get_level((gpio_num_t)pinIORQ);
if (MREQ && running)
{
// ets_printf("%d\n", memory[readAddress()]);
writeData(memory[readAddress()]);
}
}