145 [[nodiscard]]
inline unsigned getMask()
const {
147 return effectiveBaseMask;
163 inline void setMask(
unsigned newBaseMask,
unsigned newIndexMask,
164 unsigned newSizeMask, EmuTime::param time) {
165 origBaseMask = newBaseMask;
166 newBaseMask &= newSizeMask;
168 (newBaseMask == effectiveBaseMask) &&
169 (newIndexMask == indexMask)) {
173 effectiveBaseMask = newBaseMask;
174 indexMask = newIndexMask;
175 baseAddr = effectiveBaseMask & indexMask;
176 combiMask = ~effectiveBaseMask | indexMask;
182 inline void setMask(
unsigned newBaseMask,
unsigned newIndexMask,
183 EmuTime::param time) {
184 setMask(newBaseMask, newIndexMask, sizeMask, time);
192 baseAddr = unsigned(-1);
200 unsigned endIndex = index +
size - 1;
202 if ((areaBits & effectiveBaseMask) != areaBits)
return false;
203 if ((areaBits & ~indexMask) != areaBits)
return false;
217 assert((mask & ~indexMask) == mask);
218 return (mask & effectiveBaseMask) == mask;
225 template<
size_t size>
226 [[nodiscard]]
inline std::span<const byte, size>
getReadArea(
unsigned index)
const {
228 return std::span<const byte, size>{
229 &data[effectiveBaseMask & (indexMask | index)],
241 template<
size_t size>
242 [[nodiscard]]
inline std::pair<std::span<
const byte,
size / 2>, std::span<
const byte,
size / 2>>
244 assert((index & 1) == 0);
245 assert((
size & 1) == 0);
246 unsigned endIndex = index +
size - 1;
248 areaBits = ((areaBits << 16) | (areaBits >> 1)) & 0x1FFFF & sizeMask;
250 assert((areaBits & effectiveBaseMask) == areaBits);
251 assert((areaBits & ~indexMask) == areaBits);
253 unsigned addr = effectiveBaseMask & (indexMask | (index >> 1));
254 const byte* ptr0 = &data[addr | 0x00000];
255 const byte* ptr1 = &data[addr | 0x10000];
256 return {std::span<
const byte,
size / 2>{ptr0,
size / 2},
263 [[nodiscard]]
inline byte readNP(
unsigned index)
const {
265 return data[effectiveBaseMask & index];
273 index = ((index & 1) << 16) | ((index & 0x1FFFE) >> 1);
274 unsigned addr = effectiveBaseMask & index;
281 return observer != &dummyObserver;
290 observer = newObserver;
296 observer = &dummyObserver;
306 [[nodiscard]]
inline bool isInside(
unsigned address)
const {
307 return (address & combiMask) == baseAddr;
315 inline void notify(
unsigned address, EmuTime::param time) {
317 observer->
updateVRAM(address - baseAddr, time);
327 setMask(origBaseMask, indexMask, newSizeMask, time);
330 sizeMask = newSizeMask;
333 template<
typename Archive>
334 void serialize(Archive& ar,
unsigned version);
337 [[nodiscard]]
inline bool isEnabled()
const {
338 return baseAddr != unsigned(-1);
363 unsigned origBaseMask = 0;
368 unsigned effectiveBaseMask = 0;
372 unsigned indexMask = 0;
377 unsigned baseAddr = unsigned(-1);
381 unsigned combiMask = 0;
412 inline void sync(EmuTime::param time) {
414 cmdEngine->
sync(time);
423 inline void cmdWrite(
unsigned address,
byte value, EmuTime::param time) {
426 assert(time >= vramTime);
432 if (address >= actualSize) [[unlikely]] {
434 assert(address < 0x30000);
440 writeCommon(address, value, time);
448 inline void cpuWrite(
unsigned address,
byte value, EmuTime::param time) {
451 assert(time >= vramTime);
457 if (address >= actualSize) [[unlikely]] {
459 assert(address < 0x30000);
472 cmdEngine->
sync(time);
474 writeCommon(address, value, time);
484 [[nodiscard]]
inline byte cpuRead(
unsigned address, EmuTime::param time) {
487 assert(time >= vramTime);
493 cmdEngine->
sync(time);
500 return data[address];
544 spriteChecker = newSpriteChecker;
550 cmdEngine = newCmdEngine;
558 template<
typename Archive>
559 void serialize(Archive& ar,
unsigned version);
564 inline void writeCommon(
unsigned address,
byte value, EmuTime::param time) {
566 assert(time >= vramTime);
574 if (data[address] == value)
return;
582 data[address] = value;
610 void setSizeMask(EmuTime::param time);
626 class LogicalVRAMDebuggable final :
public SimpleDebuggable {
628 explicit LogicalVRAMDebuggable(
VDP& vdp);
629 [[nodiscard]]
byte read(
unsigned address, EmuTime::param time)
override;
630 void write(
unsigned address,
byte value, EmuTime::param time)
override;
639 struct PhysicalVRAMDebuggable final : SimpleDebuggable {
640 PhysicalVRAMDebuggable(
VDP& vdp,
unsigned actualSize);
641 [[nodiscard]]
byte read(
unsigned address, EmuTime::param time)
override;
642 void write(
unsigned address,
byte value, EmuTime::param time)
override;
670 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)
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.
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.
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.
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
auto transform(InputRange &&range, OutputIter out, UnaryOperation op)
size_t size(std::string_view utf8)