1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#ifndef M6532_HXX
19#define M6532_HXX
20
21class ConsoleIO;
22class RiotDebug;
23class System;
24class Settings;
25
26#include "bspf.hxx"
27#include "Device.hxx"
28
29/**
30 This class models the M6532 RAM-I/O-Timer (aka RIOT) chip in the 2600
31 console. Note that since the M6507 CPU doesn't contain an interrupt line,
32 the following functionality relating to the RIOT IRQ line is not emulated:
33
34 - A3 to enable/disable interrupt from timer to IRQ
35 - A1 to enable/disable interrupt from PA7 to IRQ
36
37 @author Bradford W. Mott and Stephen Anthony
38*/
39class M6532 : public Device
40{
41 public:
42 /**
43 The RIOT debugger class is a friend who needs special access
44 */
45 friend class RiotDebug;
46
47 public:
48 /**
49 Create a new 6532 for the specified console
50
51 @param console The console the 6532 is associated with
52 @param settings The settings used by the system
53 */
54 M6532(const ConsoleIO& console, const Settings& settings);
55 virtual ~M6532() = default;
56
57 public:
58 /**
59 Reset cartridge to its power-on state
60 */
61 void reset() override;
62
63 /**
64 Update the entire digital and analog pin state of ports A and B.
65 */
66 void update();
67
68 /**
69 Install 6532 in the specified system. Invoked by the system
70 when the 6532 is attached to it.
71
72 @param system The system the device should install itself in
73 */
74 void install(System& system) override;
75
76 /**
77 Install 6532 in the specified system and device. Invoked by
78 the system when the 6532 is attached to it. All devices
79 which invoke this method take responsibility for chaining
80 requests back to *this* device.
81
82 @param system The system the device should install itself in
83 @param device The device responsible for this address space
84 */
85 void installDelegate(System& system, Device& device);
86
87 /**
88 Save the current state of this device to the given Serializer.
89
90 @param out The Serializer object to use
91 @return False on any errors, else true
92 */
93 bool save(Serializer& out) const override;
94
95 /**
96 Load the current state of this device from the given Serializer.
97
98 @param in The Serializer object to use
99 @return False on any errors, else true
100 */
101 bool load(Serializer& in) override;
102
103 public:
104 /**
105 Get the byte at the specified address
106
107 @return The byte at the specified address
108 */
109 uInt8 peek(uInt16 address) override;
110
111 /**
112 Change the byte at the specified address to the given value
113
114 @param address The address where the value should be stored
115 @param value The value to be stored at the address
116
117 @return True if the poke changed the device address space, else false
118 */
119 bool poke(uInt16 address, uInt8 value) override;
120
121 /**
122 * Update RIOT state to the current timestamp.
123 */
124 void updateEmulation();
125
126 /**
127 Get a pointer to the RAM contents.
128
129 @return Pointer to RAM array.
130 */
131 const uInt8* getRAM() const { return myRAM.data(); }
132
133 private:
134
135 void setTimerRegister(uInt8 data, uInt8 interval);
136 void setPinState(bool shcha);
137
138 // The following are used by the debugger to read INTIM/TIMINT
139 // We need separate methods to do this, so the state of the system
140 // isn't changed
141 uInt8 intim();
142 uInt8 timint();
143 Int32 intimClocks();
144 uInt32 timerClocks() const;
145
146 #ifdef DEBUGGER_SUPPORT
147 void createAccessBases();
148
149 /**
150 Query the given address type for the associated disassembly flags.
151
152 @param address The address to query
153 */
154 uInt8 getAccessFlags(uInt16 address) const override;
155 /**
156 Change the given address to use the given disassembly flags.
157
158 @param address The address to modify
159 @param flags A bitfield of DisasmType directives for the given address
160 */
161 void setAccessFlags(uInt16 address, uInt8 flags) override;
162 #endif // DEBUGGER_SUPPORT
163
164 private:
165 // Reference to the console
166 const ConsoleIO& myConsole;
167
168 // Reference to the settings
169 const Settings& mySettings;
170
171 // An amazing 128 bytes of RAM
172 std::array<uInt8, 128> myRAM;
173
174 // Current value of the timer
175 uInt8 myTimer;
176
177 // Current number of clocks "queued" for the divider
178 uInt32 mySubTimer;
179
180 // The divider
181 uInt32 myDivider;
182
183 // Has the timer wrapped?
184 bool myTimerWrapped;
185 bool myWrappedThisCycle;
186
187 // Cycle when the timer set. Debugging only.
188 uInt64 mySetTimerCycle;
189
190 // Last cycle considered in emu updates
191 uInt64 myLastCycle;
192
193 // Data Direction Register for Port A
194 uInt8 myDDRA;
195
196 // Data Direction Register for Port B
197 uInt8 myDDRB;
198
199 // Last value written to Port A
200 uInt8 myOutA;
201
202 // Last value written to Port B
203 uInt8 myOutB;
204
205 // Interrupt Flag Register
206 uInt8 myInterruptFlag;
207
208 // Used to determine whether an active transition on PA7 has occurred
209 // True is positive edge-detect, false is negative edge-detect
210 bool myEdgeDetectPositive;
211
212 // Last value written to the timer registers
213 std::array<uInt8, 4> myOutTimer;
214
215 // Accessible bits in the interrupt flag register
216 // All other bits are always zeroed
217 static constexpr uInt8 TimerBit = 0x80, PA7Bit = 0x40;
218
219#ifdef DEBUGGER_SUPPORT
220 static constexpr uInt16
221 RAM_SIZE = 0x80, RAM_MASK = RAM_SIZE - 1,
222 STACK_SIZE = RAM_SIZE, STACK_MASK = RAM_MASK, STACK_BIT = 0x100,
223 IO_SIZE = 0x20, IO_MASK = IO_SIZE - 1, IO_BIT = 0x200,
224 ZP_DELAY = 1;
225
226 // The arrays containing information about every byte of RIOT
227 // indicating whether and how (RW) it is used.
228 std::array<uInt8, RAM_SIZE> myRAMAccessBase;
229 std::array<uInt8, STACK_SIZE> myStackAccessBase;
230 std::array<uInt8, IO_SIZE> myIOAccessBase;
231 // The array used to skip the first ZP access tracking
232 std::array<uInt8, RAM_SIZE> myZPAccessDelay;
233#endif // DEBUGGER_SUPPORT
234
235 private:
236 // Following constructors and assignment operators not supported
237 M6532() = delete;
238 M6532(const M6532&) = delete;
239 M6532(M6532&&) = delete;
240 M6532& operator=(const M6532&) = delete;
241 M6532& operator=(M6532&&) = delete;
242};
243
244#endif
245