-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinterrupt_demo.cpp
More file actions
166 lines (131 loc) · 5.99 KB
/
interrupt_demo.cpp
File metadata and controls
166 lines (131 loc) · 5.99 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
/**
* @file interrupt_demo.cpp
* @brief Demonstration of the IRQ/NMI interrupt system
*
* This example shows how to set up and use the interrupt system
* with a timer that triggers IRQs periodically.
*/
#include <iostream>
#include <iomanip>
#include "cpu.hpp"
#include "mem.hpp"
#include "interrupt_controller.hpp"
#include "devices/basic_timer.hpp"
void printCPUState(const CPU& cpu, const std::string& context) {
std::cout << " [" << context << "] PC: 0x"
<< std::hex << std::setw(4) << std::setfill('0') << cpu.PC
<< ", SP: 0x" << std::setw(2) << (int)cpu.SP
<< ", I: " << (int)cpu.I
<< std::dec << "\n";
}
int main() {
std::cout << "=== Demostración del Sistema de Interrupciones ===" << std::endl;
std::cout << std::endl;
// Inicializar componentes
Mem mem;
CPU cpu;
InterruptController intCtrl;
mem.Initialize();
cpu.Reset(mem);
std::cout << "1. Configurando vectores de interrupción..." << std::endl;
// Configurar vector de IRQ apuntando a 0x8000
mem[Mem::IRQ_VECTOR] = 0x00;
mem[Mem::IRQ_VECTOR + 1] = 0x80;
std::cout << " - Vector IRQ: 0x8000" << std::endl;
// Configurar vector de NMI apuntando a 0x9000
mem[Mem::NMI_VECTOR] = 0x00;
mem[Mem::NMI_VECTOR + 1] = 0x90;
std::cout << " - Vector NMI: 0x9000" << std::endl;
std::cout << std::endl;
// Rutina de manejo de interrupción simple (RTI - Return from Interrupt)
// En un programa real, aquí habría código para manejar la interrupción
mem[0x8000] = 0x40; // RTI en el handler de IRQ
mem[0x9000] = 0x40; // RTI en el handler de NMI
// Conectar el controlador de interrupciones a la CPU
cpu.setInterruptController(&intCtrl);
std::cout << "2. Controlador de interrupciones conectado a la CPU" << std::endl;
std::cout << std::endl;
// Crear y configurar timer
auto timer = std::make_shared<BasicTimer>();
timer->initialize();
cpu.registerIODevice(timer);
intCtrl.registerSource(timer);
std::cout << "3. Timer registrado como fuente de interrupciones" << std::endl;
std::cout << " - Fuentes registradas: " << intCtrl.getSourceCount() << std::endl;
std::cout << std::endl;
// Configurar timer para disparar IRQ cada 100 ciclos
timer->setLimit(100);
timer->write(0xFC08, 0x03); // Enable | IRQ Enable
std::cout << "4. Timer configurado:" << std::endl;
std::cout << " - Límite: 100 ciclos" << std::endl;
std::cout << " - IRQ habilitada: " << (timer->isIRQEnabled() ? "Sí" : "No") << std::endl;
std::cout << " - Auto-reload: " << (timer->isAutoReload() ? "Sí" : "No") << std::endl;
std::cout << std::endl;
std::cout << "5. Ejecutando simulación..." << std::endl;
std::cout << std::string(60, '-') << std::endl;
// Estado inicial
printCPUState(cpu, "Estado inicial");
// Simular varios ciclos y manejar interrupciones
int totalCycles = 0;
int irqCount = 0;
for (int i = 0; i < 6; i++) {
int cyclesThisIteration = 50;
totalCycles += cyclesThisIteration;
std::cout << "\n--- Iteración " << (i + 1) << " (Ciclos totales: " << totalCycles << ") ---" << std::endl;
// Ejecutar timer
timer->tick(cyclesThisIteration);
std::cout << " Timer tick: +" << cyclesThisIteration << " ciclos" << std::endl;
std::cout << " Contador del timer: " << timer->getCounter() << std::endl;
// Verificar y manejar interrupciones
if (intCtrl.hasIRQ()) {
irqCount++;
std::cout << "\n *** IRQ #" << irqCount << " DETECTADA ***" << std::endl;
printCPUState(cpu, "Antes de IRQ");
cpu.checkAndHandleInterrupts(mem);
printCPUState(cpu, "Después de IRQ");
std::cout << " Pila afectada: " << (cpu.SP != 0xFF ? "Sí" : "No") << std::endl;
// Resetear PC para la siguiente iteración (en un programa real, RTI lo haría)
cpu.PC = 0xFFFC;
cpu.I = 0; // Habilitar interrupciones nuevamente
} else {
std::cout << " No hay interrupciones pendientes" << std::endl;
}
}
std::cout << std::string(60, '-') << std::endl;
std::cout << "\n6. Resumen de la simulación:" << std::endl;
std::cout << " - Total de ciclos ejecutados: " << totalCycles << std::endl;
std::cout << " - IRQs disparadas: " << irqCount << std::endl;
std::cout << " - Contador final del timer: " << timer->getCounter() << std::endl;
std::cout << std::endl;
std::cout << "7. Demostrando NMI (no enmascarable)..." << std::endl;
// Crear una fuente mock de NMI
class MockNMISource : public InterruptSource {
public:
bool hasIRQ() const override { return false; }
bool hasNMI() const override { return nmiActive; }
void clearIRQ() override {}
void clearNMI() override { nmiActive = false; }
void triggerNMI() { nmiActive = true; }
private:
bool nmiActive = false;
};
auto nmiSource = std::make_shared<MockNMISource>();
intCtrl.registerSource(nmiSource);
// Establecer flag I para intentar bloquear interrupciones
cpu.I = 1;
std::cout << " - Flag I establecido (interrupciones deshabilitadas)" << std::endl;
// Disparar NMI
nmiSource->triggerNMI();
std::cout << " - NMI disparada" << std::endl;
printCPUState(cpu, "Antes de NMI");
cpu.checkAndHandleInterrupts(mem);
printCPUState(cpu, "Después de NMI");
std::cout << " - NMI se ejecutó a pesar del flag I (no enmascarable)" << std::endl;
std::cout << " - PC apunta a: 0x" << std::hex << cpu.PC << std::dec << " (vector de NMI)" << std::endl;
std::cout << std::endl;
// Limpiar
cpu.unregisterIODevice(timer);
timer->cleanup();
std::cout << "=== Demostración completada exitosamente ===" << std::endl;
return 0;
}