147 [[nodiscard]]
inline unsigned getMask()
const {
149 return effectiveBaseMask;
165 inline void setMask(
unsigned newBaseMask,
unsigned newIndexMask,
166 unsigned newSizeMask, EmuTime::param time) {
167 origBaseMask = newBaseMask;
168 newBaseMask &= newSizeMask;
170 (newBaseMask == effectiveBaseMask) &&
171 (newIndexMask == indexMask)) {
175 effectiveBaseMask = newBaseMask;
176 indexMask = newIndexMask;
177 baseAddr = effectiveBaseMask & indexMask;
178 combiMask = ~effectiveBaseMask | indexMask;
184 inline void setMask(
unsigned newBaseMask,
unsigned newIndexMask,
185 EmuTime::param time) {
186 setMask(newBaseMask, newIndexMask, sizeMask, time);
194 baseAddr = unsigned(-1);
200 [[nodiscard]]
inline bool isContinuous(
unsigned index,
unsigned size)
const {
202 unsigned endIndex = index + size - 1;
204 if ((areaBits & effectiveBaseMask) != areaBits)
return false;
205 if ((areaBits & ~indexMask) != areaBits)
return false;
219 assert((mask & ~indexMask) == mask);
220 return (mask & effectiveBaseMask) == mask;
227 template<
size_t size>
228 [[nodiscard]]
inline std::span<const byte, size>
getReadArea(
unsigned index)
const {
230 return std::span<const byte, size>{
231 &data[effectiveBaseMask & (indexMask | index)],
243 template<
size_t size>
244 [[nodiscard]]
inline std::pair<std::span<
const byte, size / 2>, std::span<
const byte, size / 2>>
246 assert((index & 1) == 0);
247 assert((size & 1) == 0);
248 unsigned endIndex = index + size - 1;
250 areaBits = ((areaBits << 16) | (areaBits >> 1)) & 0x1FFFF & sizeMask;
252 assert((areaBits & effectiveBaseMask) == areaBits);
253 assert((areaBits & ~indexMask) == areaBits);
255 unsigned addr = effectiveBaseMask & (indexMask | (index >> 1));
256 const byte* ptr0 = &data[addr | 0x00000];
257 const byte* ptr1 = &data[addr | 0x10000];
258 return {std::span<
const byte, size / 2>{ptr0, size / 2},
259 std::span<
const byte, size / 2>{ptr1, size / 2}};
265 [[nodiscard]]
inline byte readNP(
unsigned index)
const {
267 return data[effectiveBaseMask & index];
275 index = ((index & 1) << 16) | ((index & 0x1FFFE) >> 1);
276 unsigned addr = effectiveBaseMask & index;
283 return observer != &dummyObserver;
292 observer = newObserver;
298 observer = &dummyObserver;
308 [[nodiscard]]
inline bool isInside(
unsigned address)
const {
309 return (address & combiMask) == baseAddr;
317 inline void notify(
unsigned address, EmuTime::param time) {
319 observer->
updateVRAM(address - baseAddr, time);
329 setMask(origBaseMask, indexMask, newSizeMask, time);
332 sizeMask = newSizeMask;
335 template<
typename Archive>
336 void serialize(Archive& ar,
unsigned version);
339 [[nodiscard]]
inline bool isEnabled()
const {
340 return baseAddr != unsigned(-1);
365 unsigned origBaseMask = 0;
370 unsigned effectiveBaseMask = 0;
374 unsigned indexMask = 0;
379 unsigned baseAddr = unsigned(-1);
383 unsigned combiMask = 0;
406 VDPVRAM(
VDP& vdp,
unsigned size, EmuTime::param time);
416 inline void sync(EmuTime::param time) {
418 cmdEngine->
sync(time);
427 inline void cmdWrite(
unsigned address,
byte value, EmuTime::param time) {
430 assert(time >= vramTime);
436 if (address >= actualSize) [[unlikely]] {
438 assert(address < 0x30000);
444 writeCommon(address, value, time);
452 inline void cpuWrite(
unsigned address,
byte value, EmuTime::param time) {
455 assert(time >= vramTime);
461 if (address >= actualSize) [[unlikely]] {
463 assert(address < 0x30000);
476 cmdEngine->
sync(time);
478 writeCommon(address, value, time);
488 [[nodiscard]]
inline byte cpuRead(
unsigned address, EmuTime::param time) {
491 assert(time >= vramTime);
497 cmdEngine->
sync(time);
504 return data[address];
548 spriteChecker = newSpriteChecker;
554 cmdEngine = newCmdEngine;
564 [[nodiscard]] std::span<const uint8_t>
getData()
const {
568 template<
typename Archive>
569 void serialize(Archive& ar,
unsigned version);
574 inline void writeCommon(
unsigned address,
byte value, EmuTime::param time) {
576 assert(time >= vramTime);
584 if (data[address] == value)
return;
592 data[address] = value;
620 void setSizeMask(EmuTime::param time);
636 class LogicalVRAMDebuggable final :
public SimpleDebuggable {
638 explicit LogicalVRAMDebuggable(
const VDP& vdp);
639 [[nodiscard]]
byte read(
unsigned address, EmuTime::param time)
override;
640 void write(
unsigned address,
byte value, EmuTime::param time)
override;
642 unsigned transform(
unsigned address);
649 struct PhysicalVRAMDebuggable final : SimpleDebuggable {
650 PhysicalVRAMDebuggable(
const VDP& vdp,
unsigned actualSize);
651 [[nodiscard]]
byte read(
unsigned address, EmuTime::param time)
override;
652 void write(
unsigned address,
byte value, EmuTime::param time)
override;
668 EmuTime vramTime = EmuTime::zero();
680 const unsigned actualSize;
Represents a VDP display mode.
void updateVRAM(unsigned, EmuTime::param) override
Informs the observer of a change in VRAM contents.
void updateWindow(bool, EmuTime::param) override
Informs the observer that the entire VRAM window will change.
Abstract base class for Renderers.
byte read(unsigned address) override
void write(unsigned address, byte value) override
VDP command engine by Alex Wulms.
void stealAccessSlot(EmuTime::param time)
Steal a VRAM access slot from the CmdEngine.
void sync(EmuTime::param time)
Synchronizes the command engine with the VDP.
Manages VRAM contents and synchronizes the various users of the VRAM.
void updateSpritesEnabled(bool enabled, EmuTime::param time)
Used by the VDP to signal sprites enabled changes.
VRAMWindow spriteAttribTable
void clear()
Initialize VRAM content to power-up state.
VDPVRAM(const VDPVRAM &)=delete
void cmdWrite(unsigned address, byte value, EmuTime::param time)
Write a byte from the command engine.
VDPVRAM & operator=(const VDPVRAM &)=delete
void setRenderer(Renderer *renderer, EmuTime::param time)
VDPVRAM & operator=(VDPVRAM &&)=delete
void updateVRMode(bool mode, EmuTime::param time)
Change between VR=0 and VR=1 mode.
VRAMWindow bitmapCacheWindow
void updateDisplayEnabled(bool enabled, EmuTime::param time)
Used by the VDP to signal display enabled changes.
void setSpriteChecker(SpriteChecker *newSpriteChecker)
Necessary because of circular dependencies.
void updateDisplayMode(DisplayMode mode, bool cmdBit, EmuTime::param time)
Used by the VDP to signal display mode changes.
VDPVRAM(VDPVRAM &&)=delete
VRAMWindow bitmapVisibleWindow
void sync(EmuTime::param time)
Update VRAM state to specified moment in time.
byte cpuRead(unsigned address, EmuTime::param time)
Read a byte from VRAM though the CPU interface.
void serialize(Archive &ar, unsigned version)
unsigned getSize() const
Returns the size of VRAM in bytes.
std::span< const uint8_t > getData() const
Only used by debugger.
VRAMWindow spritePatternTable
void cpuWrite(unsigned address, byte value, EmuTime::param time)
Write a byte to VRAM through the CPU interface.
VRAMWindow cmdWriteWindow
void setCmdEngine(VDPCmdEngine *newCmdEngine)
Necessary because of circular dependencies.
void change4k8kMapping(bool mapping8k)
TMS99x8 VRAM can be mapped in two ways.
Unified implementation of MSX Video Display Processors (VDPs).
bool isInsideFrame(EmuTime::param time) const
Is the given timestamp inside the current frame? Mainly useful for debugging, because relevant timest...
Interface that can be registered at VRAMWindow, to be called when the contents of the VRAM inside tha...
virtual void updateVRAM(unsigned offset, EmuTime::param time)=0
Informs the observer of a change in VRAM contents.
virtual void updateWindow(bool enabled, EmuTime::param time)=0
Informs the observer that the entire VRAM window will change.
Specifies an address range in the VRAM.
void setMask(unsigned newBaseMask, unsigned newIndexMask, unsigned newSizeMask, EmuTime::param time)
Sets the mask and enables this window.
void disable(EmuTime::param time)
Disable this window: no address will be considered inside.
VRAMWindow(VRAMWindow &&)=delete
VRAMWindow & operator=(VRAMWindow &&)=delete
bool isContinuous(unsigned index, unsigned size) const
Is the given index range continuous in VRAM (iow there's no mirroring) Only if the range is continuou...
void notify(unsigned address, EmuTime::param time)
Notifies the observer of this window of a VRAM change, if the changes address is inside this window.
byte readNP(unsigned index) const
Reads a byte from VRAM in its current state.
bool hasObserver() const
Is there an observer registered for this window?
VRAMWindow & operator=(const VRAMWindow &)=delete
bool isInside(unsigned address) const
Test whether an address is inside this window.
void serialize(Archive &ar, unsigned version)
void setMask(unsigned newBaseMask, unsigned newIndexMask, EmuTime::param time)
Same as above, but 'sizeMask' doesn't change.
bool isContinuous(unsigned mask) const
Alternative version to check whether a region is continuous in VRAM.
void setSizeMask(unsigned newSizeMask, EmuTime::param time)
Inform VRAMWindow of changed sizeMask.
byte readPlanar(unsigned index) const
Similar to readNP, but now with planar addressing.
VRAMWindow(const VRAMWindow &)=delete
unsigned getMask() const
Gets the mask for this window.
std::pair< std::span< const byte, size/2 >, std::span< const byte, size/2 > > getReadAreaPlanar(unsigned index) const
Similar to getReadArea(), but now with planar addressing mode.
void setObserver(VRAMObserver *newObserver)
Register an observer on this VRAM window.
std::span< const byte, size > getReadArea(unsigned index) const
Gets a span of a contiguous part of the VRAM.
void resetObserver()
Unregister the observer of this VRAM window.
constexpr auto floodRight(std::unsigned_integral auto x) noexcept
Returns the smallest number of the form 2^n-1 that is greater or equal to the given number.
This file implemented 3 utility functions:
uint8_t byte
8 bit unsigned integer