604 lines
No EOL
17 KiB
C++
604 lines
No EOL
17 KiB
C++
#include "VirtualIODevices.hpp"
|
|
#include <ostd/Utils.hpp>
|
|
|
|
#include "VirtualHardDrive.hpp"
|
|
#include "MemoryMapper.hpp"
|
|
#include "VirtualCPU.hpp"
|
|
#include "VirtualRAM.hpp"
|
|
|
|
namespace dragon
|
|
{
|
|
namespace hw
|
|
{
|
|
void VirtualBIOS::init(const ostd::String& biosFilePath)
|
|
{
|
|
bool loaded = ostd::Utils::loadByteStreamFromFile(biosFilePath, m_bios);
|
|
if (!loaded)
|
|
data::ErrorHandler::pushError(data::ErrorCodes::BIOS_FailedToLoad, "Failed to load BIOS data.");
|
|
if (m_bios.size() != 4096) //TODO: Hardcoded
|
|
data::ErrorHandler::pushError(data::ErrorCodes::BIOS_InvalidSize, ostd::String("Invalid BIOS size: ").add(ostd::Utils::getHexStr(m_bios.size(), true, 2)));
|
|
m_initialized = true;
|
|
}
|
|
|
|
int8_t VirtualBIOS::read8(uint16_t addr)
|
|
{
|
|
if (addr >= m_bios.size())
|
|
data::ErrorHandler::pushError(data::ErrorCodes::BIOS_InvalidAddress, ostd::String("Invalid Byte BIOS location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return m_bios[addr];
|
|
}
|
|
|
|
int16_t VirtualBIOS::read16(uint16_t addr)
|
|
{
|
|
if (addr >= m_bios.size() - 1)
|
|
data::ErrorHandler::pushError(data::ErrorCodes::BIOS_InvalidAddress, ostd::String("Invalid Word BIOS location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return ((m_bios[addr + 0] << 8) & 0xFF00U)
|
|
| ( m_bios[addr + 1] & 0x00FFU);
|
|
}
|
|
|
|
int8_t VirtualBIOS::write8(uint16_t addr, int8_t value)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::BIOS_WriteAttempt, "Attempting to write to BIOS memory map.");
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t VirtualBIOS::write16(uint16_t addr, int16_t value)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::BIOS_WriteAttempt, "Attempting to write to BIOS memory map.");
|
|
return 0x0000;
|
|
}
|
|
|
|
ostd::ByteStream* VirtualBIOS::getByteStream(void)
|
|
{
|
|
return &m_bios;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
InterruptVector::InterruptVector(void)
|
|
{
|
|
uint32_t dataSize = data::MemoryMapAddresses::IntVector_End - data::MemoryMapAddresses::IntVector_Start;
|
|
for (int32_t i = 0; i < dataSize; i++)
|
|
m_data.push_back(0x00);
|
|
}
|
|
|
|
int8_t InterruptVector::read8(uint16_t addr)
|
|
{
|
|
if (addr >= m_data.size())
|
|
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Byte IntVector location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return m_data[addr];
|
|
}
|
|
|
|
int16_t InterruptVector::read16(uint16_t addr)
|
|
{
|
|
if (addr >= m_data.size() - 1)
|
|
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Word IntVector location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return ((m_data[addr + 0] << 8) & 0xFF00U)
|
|
| ( m_data[addr + 1] & 0x00FFU);
|
|
}
|
|
|
|
int8_t InterruptVector::write8(uint16_t addr, int8_t value)
|
|
{
|
|
if (addr >= m_data.size())
|
|
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Word IntVector location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
m_data[addr] = value;
|
|
return value;
|
|
}
|
|
|
|
int16_t InterruptVector::write16(uint16_t addr, int16_t value)
|
|
{
|
|
if (addr >= m_data.size() - 1)
|
|
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Word IntVector location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
m_data[addr + 0] = (value >> 8) & 0xFF;
|
|
m_data[addr + 1] = value & 0xFF;
|
|
return value;
|
|
}
|
|
|
|
ostd::ByteStream* InterruptVector::getByteStream(void)
|
|
{
|
|
return &m_data;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VirtualKeyboard::VirtualKeyboard(void)
|
|
{
|
|
}
|
|
|
|
int8_t VirtualKeyboard::read8(uint16_t addr)
|
|
{
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t VirtualKeyboard::read16(uint16_t addr)
|
|
{
|
|
return 0x0000;
|
|
}
|
|
|
|
int8_t VirtualKeyboard::write8(uint16_t addr, int8_t value)
|
|
{
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t VirtualKeyboard::write16(uint16_t addr, int16_t value)
|
|
{
|
|
return 0x0000;
|
|
}
|
|
|
|
ostd::ByteStream* VirtualKeyboard::getByteStream(void)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VirtualMouse::VirtualMouse(void)
|
|
{
|
|
}
|
|
|
|
int8_t VirtualMouse::read8(uint16_t addr)
|
|
{
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t VirtualMouse::read16(uint16_t addr)
|
|
{
|
|
return 0x0000;
|
|
}
|
|
|
|
int8_t VirtualMouse::write8(uint16_t addr, int8_t value)
|
|
{
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t VirtualMouse::write16(uint16_t addr, int16_t value)
|
|
{
|
|
return 0x0000;
|
|
}
|
|
|
|
ostd::ByteStream* VirtualMouse::getByteStream(void)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VirtualBootloader::VirtualBootloader(void)
|
|
{
|
|
for (int32_t i = 0; i < 512; i++)
|
|
m_mbr.push_back(0);
|
|
}
|
|
|
|
int8_t VirtualBootloader::read8(uint16_t addr)
|
|
{
|
|
if (addr >= m_mbr.size())
|
|
data::ErrorHandler::pushError(data::ErrorCodes::BIOS_InvalidAddress, ostd::String("Invalid Byte MBR location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return m_mbr[addr];
|
|
}
|
|
|
|
int16_t VirtualBootloader::read16(uint16_t addr)
|
|
{
|
|
if (addr >= m_mbr.size() - 1)
|
|
data::ErrorHandler::pushError(data::ErrorCodes::BIOS_InvalidAddress, ostd::String("Invalid Word MBR location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return ((m_mbr[addr + 0] << 8) & 0xFF00U)
|
|
| ( m_mbr[addr + 1] & 0x00FFU);
|
|
}
|
|
|
|
int8_t VirtualBootloader::write8(uint16_t addr, int8_t value)
|
|
{
|
|
if (addr >= m_mbr.size())
|
|
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Word IntVector location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
m_mbr[addr] = value;
|
|
return value;
|
|
}
|
|
|
|
int16_t VirtualBootloader::write16(uint16_t addr, int16_t value)
|
|
{
|
|
if (addr >= m_mbr.size() - 1)
|
|
data::ErrorHandler::pushError(data::ErrorCodes::IntVector_InvalidAddress, ostd::String("Invalid Word IntVector location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
m_mbr[addr + 0] = (value >> 8) & 0xFF;
|
|
m_mbr[addr + 1] = value & 0xFF;
|
|
return value;
|
|
}
|
|
|
|
ostd::ByteStream* VirtualBootloader::getByteStream(void)
|
|
{
|
|
return &m_mbr;
|
|
}
|
|
|
|
|
|
|
|
|
|
namespace interface
|
|
{
|
|
Disk::Disk(MemoryMapper& memory, VirtualCPU& cpu) : m_memory(memory), m_cpu(cpu)
|
|
{
|
|
m_data.w_Byte(tRegisters::Signal, tSignalValues::Ignore);
|
|
}
|
|
|
|
int8_t Disk::read8(uint16_t addr)
|
|
{
|
|
int8_t value = 0;
|
|
if (!m_data.r_Byte(addr, value))
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_ControllerReadFailed, "Failed to read byte from HardDrive Controller");
|
|
return 0;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
int16_t Disk::read16(uint16_t addr)
|
|
{
|
|
int16_t value = 0;
|
|
if (!m_data.r_Word(addr, value))
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_ControllerReadFailed, "Failed to read word from HardDrive Controller");
|
|
return 0;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
int8_t Disk::write8(uint16_t addr, int8_t value)
|
|
{
|
|
if (addr >= tRegisters::FirstReadOnly)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_ControllerWriteFailed, "Attempt to write byte to ReadOnly part of HardDrive Controller");
|
|
return 0;
|
|
}
|
|
if (!m_data.w_Byte(addr, value))
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_ControllerWriteFailed, "Failed to write byte to HardDrive Controller");
|
|
return 0;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
int16_t Disk::write16(uint16_t addr, int16_t value)
|
|
{
|
|
if (addr >= tRegisters::FirstReadOnly)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_ControllerWriteFailed, "Attempt to write word to ReadOnly part of HardDrive Controller");
|
|
return 0;
|
|
}
|
|
if (!m_data.w_Word(addr, value))
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_ControllerWriteFailed, "Failed to write word to HardDrive Controller");
|
|
return 0;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
ostd::ByteStream* Disk::getByteStream(void)
|
|
{
|
|
return &m_data.getData();
|
|
}
|
|
|
|
void Disk::cycleStep(void)
|
|
{
|
|
uint8_t signal = tSignalValues::Ignore;
|
|
m_data.r_Byte(tRegisters::Signal, (int8_t&)signal);
|
|
if (m_busy)
|
|
{
|
|
if (signal == tSignalValues::Cancel)
|
|
{
|
|
m_data.w_Byte(tRegisters::Status, tStatusValues::Free);
|
|
m_data.w_Byte(tRegisters::Signal, tSignalValues::Ignore);
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
if (signal != tSignalValues::Ignore)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_InvalidConfiguration, "Invalid HardDrive configuration: <signal> register must be set to <ignore> while busy.");
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
uint8_t status = 0;
|
|
m_data.r_Byte(tRegisters::Status, (int8_t&)status);
|
|
if (status == tStatusValues::Free)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_InvalidConfiguration, "Invalid HardDrive configuration: <status> register set to <free> while busy.");
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
uint8_t currentDisk = 0;
|
|
uint16_t currentSector = 0, currentAddress = 0, restDataSize = 0, memoryAddress = 0;
|
|
m_data.r_Byte(tRegisters::CurrentDisk, (int8_t&)currentDisk);
|
|
m_data.r_Word(tRegisters::CurrentSector, (int16_t&)currentSector);
|
|
m_data.r_Word(tRegisters::CurrentAddress, (int16_t&)currentAddress);
|
|
m_data.r_Word(tRegisters::RestDataSize, (int16_t&)restDataSize);
|
|
m_data.r_Word(tRegisters::SourceData, (int16_t&)memoryAddress);
|
|
if (m_connectedDisks.count((data::VDiskID)currentDisk) == 0)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_InvalidDiskSelected, "Invalid HardDrive configuration: selected Disk not found.");
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
auto& disk = *m_connectedDisks[currentDisk];
|
|
uint32_t hddAddress = 0;
|
|
if (currentAddress == 0xFFFF)
|
|
{
|
|
if (currentSector == 0xFFFF)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_EndOfDisk, "HardDrive Error: Reached end of selected Disk.");
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
currentSector++;
|
|
currentAddress = 0x0000;
|
|
}
|
|
hddAddress = (currentSector << 16) | currentAddress;
|
|
if (status == tStatusValues::Reading)
|
|
{
|
|
ostd::ByteStream _data;
|
|
if (!disk.read(hddAddress, 1, _data))
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_ReadFailed, "HardDrive Error: Failed to read data.");
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
m_memory.write8(memoryAddress, _data[0]);
|
|
}
|
|
else if (status == tStatusValues::Writing)
|
|
{
|
|
int8_t dataRead = m_memory.read8(memoryAddress);
|
|
if (!disk.write(hddAddress, dataRead))
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_WriteFailed, "HardDrive Error: Failed to write data.");
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
}
|
|
memoryAddress++;
|
|
if (memoryAddress == 0xFFFF)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_MemoryOverflow, "HardDrive Error: Reached end of Memory.");
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
restDataSize--;
|
|
if (restDataSize == 0)
|
|
{
|
|
m_data.w_Byte(tRegisters::Status, tStatusValues::Free);
|
|
m_data.w_Byte(tRegisters::Signal, tSignalValues::Ignore);
|
|
m_busy = false;
|
|
m_cpu.handleInterrupt(data::InterruptCodes::DiskInterfaceFFinished);
|
|
return;
|
|
}
|
|
currentAddress++;
|
|
m_data.w_Word(tRegisters::CurrentSector, currentSector);
|
|
m_data.w_Word(tRegisters::CurrentAddress, currentAddress);
|
|
m_data.w_Word(tRegisters::RestDataSize, restDataSize);
|
|
m_data.w_Word(tRegisters::SourceData, memoryAddress);
|
|
return;
|
|
}
|
|
if (signal != tSignalValues::Start) return;
|
|
uint8_t mode = 0, disk = 0;
|
|
uint16_t sector = 0, address = 0, size = 0, srcAddr = 0;
|
|
m_data.r_Byte(tRegisters::ModeSelector, (int8_t&)mode);
|
|
m_data.r_Byte(tRegisters::DiskSelector, (int8_t&)disk);
|
|
m_data.r_Word(tRegisters::SectorSelector, (int16_t&)sector);
|
|
m_data.r_Word(tRegisters::AddressSelector, (int16_t&)address);
|
|
m_data.r_Word(tRegisters::DataSize, (int16_t&)size);
|
|
m_data.r_Word(tRegisters::DataSourceAddress, (int16_t&)srcAddr);
|
|
if (mode == tModeValues::Read)
|
|
m_data.w_Byte(tRegisters::Status, tStatusValues::Reading);
|
|
else if (mode == tModeValues::Write)
|
|
m_data.w_Byte(tRegisters::Status, tStatusValues::Writing);
|
|
else
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_InvalidConfiguration, "Invalid HardDrive configuration: <mode> must be set to <read> or <write> befor starting operations.");
|
|
m_busy = false;
|
|
return;
|
|
}
|
|
m_data.w_Byte(tRegisters::CurrentDisk, disk);
|
|
m_data.w_Word(tRegisters::CurrentSector, sector);
|
|
m_data.w_Word(tRegisters::CurrentAddress, address);
|
|
m_data.w_Word(tRegisters::RestDataSize, size);
|
|
m_data.w_Word(tRegisters::SourceData, srcAddr);
|
|
|
|
m_data.w_Byte(tRegisters::Signal, tSignalValues::Ignore);
|
|
m_busy = true;
|
|
}
|
|
|
|
data::VDiskID Disk::connectDisk(VirtualHardDrive& hdd)
|
|
{
|
|
for (auto& disk : m_connectedDisks)
|
|
{
|
|
if (disk.second->isSame(hdd))
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_DiskAlreadyConnected, "Attempt to connect already connected Disk to Controller");
|
|
return 0;
|
|
}
|
|
}
|
|
m_connectedDisks[Disk::s_nextDiskID] = &hdd;
|
|
return Disk::s_nextDiskID++;
|
|
}
|
|
|
|
bool Disk::disconnectDisk(data::VDiskID diskID)
|
|
{
|
|
if (m_connectedDisks.count(diskID) == 0)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::HardDrive_DisconnectInvalid, "Attempt to disconnect invalid Disk from Controller");
|
|
return false;
|
|
}
|
|
m_connectedDisks.erase(diskID);
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Graphics::Graphics(void)
|
|
{
|
|
}
|
|
|
|
int8_t Graphics::read8(uint16_t addr)
|
|
{
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t Graphics::read16(uint16_t addr)
|
|
{
|
|
return 0x0000;
|
|
}
|
|
|
|
int8_t Graphics::write8(uint16_t addr, int8_t value)
|
|
{
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t Graphics::write16(uint16_t addr, int16_t value)
|
|
{
|
|
return 0x0000;
|
|
}
|
|
|
|
ostd::ByteStream* Graphics::getByteStream(void)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SerialPort::SerialPort(void)
|
|
{
|
|
}
|
|
|
|
int8_t SerialPort::read8(uint16_t addr)
|
|
{
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t SerialPort::read16(uint16_t addr)
|
|
{
|
|
return 0x0000;
|
|
}
|
|
|
|
int8_t SerialPort::write8(uint16_t addr, int8_t value)
|
|
{
|
|
return 0x00;
|
|
}
|
|
|
|
int16_t SerialPort::write16(uint16_t addr, int16_t value)
|
|
{
|
|
return 0x0000;
|
|
}
|
|
|
|
ostd::ByteStream* SerialPort::getByteStream(void)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void CMOS::init(const ostd::String& cmosFilePath)
|
|
{
|
|
m_size = data::MemoryMapAddresses::CMOS_End - data::MemoryMapAddresses::CMOS_Start + 1;
|
|
m_dataFile.open(cmosFilePath.cpp_str(), std::ios::out | std::ios::in | std::ios::binary);
|
|
if(!m_dataFile)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_UnableToMount, "Unable to mount virtual CMOS chip.");
|
|
return;
|
|
}
|
|
m_fileSize = m_dataFile.tellg();
|
|
m_dataFile.seekg( 0, std::ios::end );
|
|
m_fileSize = (int64_t)m_dataFile.tellg() - m_fileSize;
|
|
m_dataFile.seekg( 0, std::ios::beg );
|
|
if (m_fileSize != m_size)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_InvalidSize, ostd::String("Invalid virtual CMOS chhip size: ").add(m_fileSize));
|
|
return;
|
|
}
|
|
m_initialized = true;
|
|
}
|
|
|
|
int8_t CMOS::read8(uint16_t addr)
|
|
{
|
|
if (!m_initialized)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_Uninitialized, "Attempt to read uninitialized CMOS chip.");
|
|
return false;
|
|
}
|
|
if (addr >= m_size)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_InvalidAddress, ostd::String("Invalid Byte CMOS location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return false;
|
|
}
|
|
int8_t value = 0;
|
|
m_dataFile.seekg(addr);
|
|
m_dataFile.read((char*)&value, sizeof(value));
|
|
return value;
|
|
}
|
|
|
|
int16_t CMOS::read16(uint16_t addr)
|
|
{
|
|
if (!m_initialized)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_Uninitialized, "Attempt to read uninitialized CMOS chip.");
|
|
return false;
|
|
}
|
|
if (addr >= m_size - 1)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_InvalidAddress, ostd::String("Invalid Word CMOS location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return 0;
|
|
}
|
|
int8_t b1 = read8(addr);
|
|
int8_t b2 = read8(addr + 1);
|
|
return ((b1 << 8) & 0xFF00U)
|
|
| (b2 & 0x00FFU);
|
|
}
|
|
|
|
int8_t CMOS::write8(uint16_t addr, int8_t value)
|
|
{
|
|
if (!m_initialized)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_Uninitialized, "Attempt to read uninitialized CMOS chip.");
|
|
return false;
|
|
}
|
|
if (addr >= m_size)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_InvalidAddress, ostd::String("Invalid Byte CMOS location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return 0;
|
|
}
|
|
m_dataFile.seekp(addr);
|
|
m_dataFile.write((char*)(&value), sizeof(value));
|
|
return value;
|
|
}
|
|
|
|
int16_t CMOS::write16(uint16_t addr, int16_t value)
|
|
{
|
|
if (!m_initialized)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_Uninitialized, "Attempt to read uninitialized CMOS chip.");
|
|
return false;
|
|
}
|
|
if (addr >= m_size - 1)
|
|
{
|
|
data::ErrorHandler::pushError(data::ErrorCodes::CMOS_InvalidAddress, ostd::String("Invalid Word CMOS location at address: ").add(ostd::Utils::getHexStr(addr, true, 2)));
|
|
return 0;
|
|
}
|
|
int8_t b1 = (value >> 8) & 0xFF;
|
|
int8_t b2 = (value & 0xFF);
|
|
write8(addr, b1);
|
|
write8(addr + 1, b2);
|
|
return value;
|
|
}
|
|
|
|
ostd::ByteStream* CMOS::getByteStream(void)
|
|
{
|
|
return &m_data;
|
|
}
|
|
}
|
|
}
|
|
} |