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