1 #pragma once
2 #include "Snapshotable.h"
3 #include "CPU.h"
4 
5 class VrcIrq : public Snapshotable
6 {
7 private:
8 	shared_ptr<Console> _console;
9 	uint8_t _irqReloadValue;
10 	uint8_t _irqCounter;
11 	int16_t _irqPrescalerCounter;
12 	bool _irqEnabled;
13 	bool _irqEnabledAfterAck;
14 	bool _irqCycleMode;
15 
16 protected:
StreamState(bool saving)17 	void StreamState(bool saving) override
18 	{
19 		Stream(_irqReloadValue, _irqCounter, _irqPrescalerCounter, _irqEnabled, _irqEnabledAfterAck, _irqCycleMode);
20 	}
21 
22 public:
VrcIrq(shared_ptr<Console> console)23 	VrcIrq(shared_ptr<Console> console)
24 	{
25 		_console = console;
26 	}
27 
Reset()28 	void Reset()
29 	{
30 		_irqPrescalerCounter = 0;
31 		_irqReloadValue = 0;
32 		_irqCounter = 0;
33 		_irqEnabled = false;
34 		_irqEnabledAfterAck = false;
35 		_irqCycleMode = false;
36 	}
37 
ProcessCpuClock()38 	void ProcessCpuClock()
39 	{
40 		if(_irqEnabled) {
41 			_irqPrescalerCounter -= 3;
42 
43 			if(_irqCycleMode || (_irqPrescalerCounter <= 0 && !_irqCycleMode)) {
44 				if(_irqCounter == 0xFF) {
45 					_irqCounter = _irqReloadValue;
46 					_console->GetCpu()->SetIrqSource(IRQSource::External);
47 				} else {
48 					_irqCounter++;
49 				}
50 				_irqPrescalerCounter += 341;
51 			}
52 		}
53 	}
54 
SetReloadValue(uint8_t value)55 	void SetReloadValue(uint8_t value)
56 	{
57 		_irqReloadValue = value;
58 	}
59 
SetReloadValueNibble(uint8_t value,bool highBits)60 	void SetReloadValueNibble(uint8_t value, bool highBits)
61 	{
62 		if(highBits) {
63 			_irqReloadValue = (_irqReloadValue & 0x0F) | ((value & 0x0F) << 4);
64 		} else {
65 			_irqReloadValue = (_irqReloadValue & 0xF0) | (value & 0x0F);
66 		}
67 	}
68 
SetControlValue(uint8_t value)69 	void SetControlValue(uint8_t value)
70 	{
71 		_irqEnabledAfterAck = (value & 0x01) == 0x01;
72 		_irqEnabled = (value & 0x02) == 0x02;
73 		_irqCycleMode = (value & 0x04) == 0x04;
74 
75 		if(_irqEnabled) {
76 			_irqCounter = _irqReloadValue;
77 			_irqPrescalerCounter = 341;
78 		}
79 
80 		_console->GetCpu()->ClearIrqSource(IRQSource::External);
81 	}
82 
AcknowledgeIrq()83 	void AcknowledgeIrq()
84 	{
85 		_irqEnabled = _irqEnabledAfterAck;
86 		_console->GetCpu()->ClearIrqSource(IRQSource::External);
87 	}
88 };