1 //============================================================================
2 //
3 // MM     MM  6666  555555  0000   2222
4 // MMMM MMMM 66  66 55     00  00 22  22
5 // MM MMM MM 66     55     00  00     22
6 // MM  M  MM 66666  55555  00  00  22222  --  "A 6502 Microprocessor Emulator"
7 // MM     MM 66  66     55 00  00 22
8 // MM     MM 66  66 55  55 00  00 22
9 // MM     MM  6666   5555   0000  222222
10 //
11 // Copyright (c) 1995-2021 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 SYSTEM_HXX
19 #define SYSTEM_HXX
20 
21 class M6502;
22 class M6532;
23 class TIA;
24 class Cartridge;
25 
26 #include "bspf.hxx"
27 #include "Device.hxx"
28 #include "NullDev.hxx"
29 #include "Random.hxx"
30 #include "Serializable.hxx"
31 
32 /**
33   This class represents a system consisting of a 6502 microprocessor
34   and a set of devices.  The devices are mapped into an addressing
35   space of 2^n bytes (1 <= n <= 16).  The addressing space is broken
36   into 2^m byte pages (1 <= m <= n), where a page is the smallest unit
37   a device can use when installing itself in the system.
38 
39   In general the addressing space will be 8192 (2^13) bytes for a
40   6507 based system and 65536 (2^16) bytes for a 6502 based system.
41 
42   @author  Bradford W. Mott
43 */
44 class System : public Serializable
45 {
46   public:
47     /**
48       Create a new system with an addressing space of 2^13 bytes and
49       pages of 2^6 bytes.
50     */
51     System(Random& random, M6502& m6502, M6532& m6532,
52            TIA& mTIA, Cartridge& mCart);
53     ~System() override = default;
54 
55     // Mask to apply to an address before accessing memory
56     static constexpr uInt16 ADDRESS_MASK = (1 << 13) - 1;
57 
58     // Amount to shift an address by to determine what page it's on
59     static constexpr uInt16 PAGE_SHIFT = 6;
60 
61     // Size of a page
62     static constexpr uInt16 PAGE_SIZE = (1 << PAGE_SHIFT);
63 
64     // Mask to apply to an address to obtain its page offset
65     static constexpr uInt16 PAGE_MASK = PAGE_SIZE - 1;
66 
67     // Number of pages in the system
68     static constexpr uInt16 NUM_PAGES = 1 << (13 - PAGE_SHIFT);
69 
70   public:
71     /**
72       Initialize system and all attached devices to known state.
73     */
74     void initialize();
75 
76     /**
77       Reset the system cycle counter, the attached devices, and the
78       attached processor of the system.
79 
80       @param autodetect  A hint to devices that the system is currently
81                          in autodetect mode.  That is, the system is being
82                          run to autodetect certain device settings before
83                          actual emulation will begin.  Certain devices may
84                          use this hint to act differently under those
85                          circumstances.
86     */
87     void reset(bool autodetect = false);
88 
89   public:
90     /**
91       Answer the 6502 microprocessor attached to the system.  If a
92       processor has not been attached calling this function will fail.
93 
94       @return The attached 6502 microprocessor
95     */
m6502() const96     M6502& m6502() const { return myM6502; }
97 
98     /**
99       Answer the 6532 processor attached to the system.  If a
100       processor has not been attached calling this function will fail.
101 
102       @return The attached 6532 microprocessor
103     */
m6532() const104     M6532& m6532() const { return myM6532; }
105 
106     /**
107       Answer the TIA device attached to the system.
108 
109       @return The attached TIA device
110     */
tia() const111     TIA& tia() const { return myTIA; }
112 
113     /**
114       Answer the Cart attached to the system.
115 
116       @return The attached cartridge
117     */
cart() const118     Cartridge& cart() const { return myCart; }
119 
120     /**
121       Answer the random generator attached to the system.
122 
123       @return The random generator
124     */
randGenerator() const125     Random& randGenerator() const { return myRandom; }
126 
127     /**
128       Get the null device associated with the system.  Every system
129       has a null device associated with it that's used by pages which
130       aren't mapped to "real" devices.
131 
132       @return The null device associated with the system
133     */
nullDevice() const134     const NullDevice& nullDevice() const { return myNullDevice; }
135 
136   public:
137     /**
138       Get the number of system cycles which have passed since the
139       system was created.
140 
141       @return The number of system cycles which have passed
142     */
cycles() const143     uInt64 cycles() const { return myCycles; }
144 
145     /**
146       Increment the system cycles by the specified number of cycles.
147 
148       @param amount The amount to add to the system cycles counter
149     */
incrementCycles(uInt32 amount)150     void incrementCycles(uInt32 amount) { myCycles += amount; }
151 
152     /**
153       Informs all attached devices that the console type has changed.
154     */
155     void consoleChanged(ConsoleTiming timing);
156 
157     /**
158       Answers whether the system is currently in device autodetect mode.
159     */
autodetectMode() const160     bool autodetectMode() const { return mySystemInAutodetect; }
161 
162   public:
163     /**
164       Get the current state of the data bus in the system.  The current
165       state is the last data that was accessed by the system.
166 
167       @return  The data bus state
168     */
getDataBusState() const169     uInt8 getDataBusState() const { return myDataBusState; }
170 
171     /**
172       Get the byte at the specified address.  No masking of the
173       address occurs before it's sent to the device mapped at
174       the address.
175 
176       @param address  The address from which the value should be loaded
177       @param flags    Indicates that this address has the given flags
178                       for type of access (CODE, DATA, GFX, etc)
179 
180       @return The byte at the specified address
181     */
182     uInt8 peek(uInt16 address, Device::AccessFlags flags = Device::NONE);
183 
184     /**
185       Change the byte at the specified address to the given value.
186       No masking of the address occurs before it's sent to the device
187       mapped at the address.
188 
189       This method sets the 'page dirty' if the write succeeds.  In the
190       case of direct-access pokes, the write always succeeds.  Otherwise,
191       if the device is handling the poke, we depend on its return value
192       for this information.
193 
194       @param address  The address where the value should be stored
195       @param value    The value to be stored at the address
196     */
197     void poke(uInt16 address, uInt8 value, Device::AccessFlags flags = Device::NONE);
198 
199     /**
200       Lock/unlock the data bus. When the bus is locked, peek() and
201       poke() don't update the bus state. The bus should be unlocked
202       while the CPU is running (normal emulation, or when the debugger
203       is stepping/advancing). It should be locked while the debugger
204       is active but not running the CPU. This is so the debugger can
205       use System.peek() to examine memory/registers without changing
206       the state of the system.
207     */
lockDataBus()208     void lockDataBus()   { myDataBusLocked = true;  }
unlockDataBus()209     void unlockDataBus() { myDataBusLocked = false; }
210 
211   #ifdef DEBUGGER_SUPPORT
212     /**
213       Access and modify the access type flags for the given
214       address.  Note that while any flag can be used, the disassembly
215       only really acts on CODE/GFX/PGFX/COL/PCOL/BCOL/AUD/DATA/ROW.
216     */
217     Device::AccessFlags getAccessFlags(uInt16 address) const;
218     void setAccessFlags(uInt16 address, Device::AccessFlags flags);
219 
220     /**
221       Increase the given address's access counter
222 
223       @param address The address to modify
224     */
225     void increaseAccessCounter(uInt16 address, bool isWrite);
226   #endif
227 
228   public:
229     /**
230       Describes how a page can be accessed
231     */
232     enum class PageAccessType : uInt8 {
233       READ      = 1 << 0,
234       WRITE     = 1 << 1,
235       READWRITE = READ | WRITE
236     };
237 
238     /**
239       Structure used to specify access methods for a page
240     */
241     struct PageAccess
242     {
243       /**
244         Pointer to a block of memory or the null pointer.  The null pointer
245         indicates that the device's peek method should be invoked for reads
246         to this page, while other values are the base address of an array
247         to directly access for reads to this page.
248       */
249       uInt8* directPeekBase{nullptr};
250 
251       /**
252         Pointer to a block of memory or the null pointer.  The null pointer
253         indicates that the device's poke method should be invoked for writes
254         to this page, while other values are the base address of an array
255         to directly access for pokes to this page.
256       */
257       uInt8* directPokeBase{nullptr};
258 
259       /**
260         Pointer to a lookup table for marking an address as CODE, DATA, GFX,
261         COL etc.
262         A CODE section is defined as any address that appears in the program
263         counter.  Currently, this is used by the debugger/disassembler to
264         conclusively determine if a section of address space is CODE, even
265         if the disassembler failed to mark it as such.
266         A DATA, GFX, COL etc. section is defined as any ROM address from which
267         data is read. This is used by the debugger/disassembler to format
268         address sections accordingly.
269       */
270       Device::AccessFlags* romAccessBase{nullptr};
271 
272       /**
273         TODO
274       */
275       Device::AccessCounter* romPeekCounter{nullptr};
276 
277       /**
278         TODO
279       */
280       Device::AccessCounter* romPokeCounter{nullptr};
281 
282       /**
283         Pointer to the device associated with this page or to the system's
284         null device if the page hasn't been mapped to a device.
285       */
286       Device* device{nullptr};
287 
288       /**
289         The manner in which the pages are accessed by the system
290         (READ, WRITE, READWRITE)
291       */
292       PageAccessType type{PageAccessType::READ};
293 
294       // Constructors
295       PageAccess() = default;
PageAccessSystem::PageAccess296       PageAccess(Device* dev, PageAccessType access) : device{dev}, type{access} { }
297     };
298 
299     /**
300       Set the page accessing method for the specified address.
301 
302       @param addr   The address/page accessing methods should be set for
303       @param access The accessing methods to be used by the page
304     */
setPageAccess(uInt16 addr,const PageAccess & access)305     void setPageAccess(uInt16 addr, const PageAccess& access) {
306       myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT] = access;
307     }
308 
309     /**
310       Get the page accessing method for the specified address.
311 
312       @param addr  The address/page to get accessing methods for
313       @return The accessing methods used by the page
314     */
getPageAccess(uInt16 addr) const315     const PageAccess& getPageAccess(uInt16 addr) const {
316       return myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT];
317     }
318 
319     /**
320       Get the page type for the given address.
321 
322       @param addr  The address contained in the page in questions
323       @return  The type of page that contains the given address
324     */
getPageAccessType(uInt16 addr) const325     System::PageAccessType getPageAccessType(uInt16 addr) const {
326       return myPageAccessTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT].type;
327     }
328 
329     /**
330       Mark the page containing this address as being dirty.
331 
332       @param addr  Determines the page that is dirty
333     */
setDirtyPage(uInt16 addr)334     void setDirtyPage(uInt16 addr) {
335       myPageIsDirtyTable[(addr & ADDRESS_MASK) >> PAGE_SHIFT] = true;
336     }
337 
338     /**
339       Answer whether any pages in given range of addresses have been
340       marked as dirty.
341 
342       @param start_addr The start address; determines the start page
343       @param end_addr   The end address; determines the end page
344     */
345     bool isPageDirty(uInt16 start_addr, uInt16 end_addr) const;
346 
347     /**
348       Mark all pages as clean (ie, turn off the dirty flag).
349     */
350     void clearDirtyPages();
351 
352     /**
353       Save the current state of this system to the given Serializer.
354 
355       @param out  The Serializer object to use
356       @return  False on any errors, else true
357     */
358     bool save(Serializer& out) const override;
359 
360     /**
361       Load the current state of this system from the given Serializer.
362 
363       @param in  The Serializer object to use
364       @return  False on any errors, else true
365     */
366     bool load(Serializer& in) override;
367 
368   private:
369     // The system RNG
370     Random& myRandom;
371 
372     // 6502 processor attached to the system
373     M6502& myM6502;
374 
375     // 6532 processor attached to the system
376     M6532& myM6532;
377 
378     // TIA device attached to the system
379     TIA& myTIA;
380 
381     // Cartridge device attached to the system
382     Cartridge& myCart;
383 
384     // Number of system cycles executed since last reset
385     uInt64 myCycles{0};
386 
387     // Null device to use for page which are not installed
388     NullDevice myNullDevice;
389 
390     // The list of PageAccess structures
391     std::array<PageAccess, NUM_PAGES> myPageAccessTable;
392 
393     // The list of dirty pages
394     std::array<bool, NUM_PAGES> myPageIsDirtyTable;
395 
396     // The current state of the Data Bus
397     uInt8 myDataBusState{0};
398 
399     // Whether or not peek() updates the data bus state. This
400     // is true during normal emulation, and false when the
401     // debugger is active.
402     bool myDataBusLocked{false};
403 
404     // Whether autodetection is currently running (ie, the emulation
405     // core is attempting to autodetect display settings, cart modes, etc)
406     // Some parts of the codebase need to act differently in such a case
407     bool mySystemInAutodetect{false};
408 
409   private:
410     // Following constructors and assignment operators not supported
411     System() = delete;
412     System(const System&) = delete;
413     System(System&&) = delete;
414     System& operator=(const System&) = delete;
415     System& operator=(System&&) = delete;
416 };
417 
418 #endif
419