cleanup spc700 and add todos
This commit is contained in:
@@ -58,8 +58,9 @@ set(
|
||||
app/emu/audio/spc700.cc
|
||||
app/emu/audio/dsp.cc
|
||||
app/emu/audio/internal/addressing.cc
|
||||
app/emu/cpu/internal/instructions.cc
|
||||
app/emu/audio/internal/instructions.cc
|
||||
app/emu/cpu/internal/addressing.cc
|
||||
app/emu/cpu/internal/instructions.cc
|
||||
app/emu/cpu/cpu.cc
|
||||
app/emu/video/ppu.cc
|
||||
app/emu/memory/dma.cc
|
||||
|
||||
@@ -41,6 +41,7 @@ absl::Status OverworldEditor::Update() {
|
||||
gfx_group_editor_.InitBlockset(tile16_blockset_bmp_);
|
||||
all_gfx_loaded_ = true;
|
||||
} else if (!rom()->isLoaded() && all_gfx_loaded_) {
|
||||
// TODO: Destroy the overworld graphics canvas.
|
||||
// Reset the editor if the ROM is unloaded
|
||||
Shutdown();
|
||||
all_gfx_loaded_ = false;
|
||||
@@ -226,8 +227,9 @@ void OverworldEditor::DrawOverworldMapSettings() {
|
||||
ImGui::SetNextItemWidth(100.f);
|
||||
ImGui::Combo("##World", &game_state_, kGamePartComboString, 3);
|
||||
|
||||
// TODO: Make enable grid bool change the current canvas.
|
||||
TableNextColumn();
|
||||
ImGui::Checkbox("Show grid", &opt_enable_grid); // TODO
|
||||
ImGui::Checkbox("Show grid", &opt_enable_grid);
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
@@ -521,14 +523,13 @@ void OverworldEditor::DrawTileSelector() {
|
||||
ImGuiTabBarFlags_FittingPolicyScroll)) {
|
||||
if (ImGui::BeginTabItem("Tile16")) {
|
||||
gui::BitmapCanvasPipeline(blockset_canvas_, tile16_blockset_bmp_, 0x100,
|
||||
(8192 * 2), 0x20, map_blockset_loaded_, true,
|
||||
1);
|
||||
(8192 * 2), 0x20, map_blockset_loaded_, true,
|
||||
1);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Tile8")) {
|
||||
if (ImGui::BeginChild("##tile8viewer",
|
||||
ImGui::GetContentRegionAvail(), true,
|
||||
ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
if (ImGui::BeginChild("##tile8viewer", ImGui::GetContentRegionAvail(),
|
||||
true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
|
||||
DrawTile8Selector();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
@@ -536,8 +537,8 @@ void OverworldEditor::DrawTileSelector() {
|
||||
}
|
||||
if (ImGui::BeginTabItem("Area Graphics")) {
|
||||
gui::BitmapCanvasPipeline(current_gfx_canvas_, current_gfx_bmp_, 256,
|
||||
0x10 * 0x40, 0x20, overworld_.isLoaded(), true,
|
||||
3);
|
||||
0x10 * 0x40, 0x20, overworld_.isLoaded(), true,
|
||||
3);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
@@ -557,13 +558,13 @@ absl::Status OverworldEditor::LoadGraphics() {
|
||||
|
||||
// Create the area graphics image
|
||||
gui::BuildAndRenderBitmapPipeline(0x80, 0x200, 0x40,
|
||||
overworld_.AreaGraphics(), *rom(),
|
||||
current_gfx_bmp_, palette_);
|
||||
overworld_.AreaGraphics(), *rom(),
|
||||
current_gfx_bmp_, palette_);
|
||||
|
||||
// Create the tile16 blockset image
|
||||
gui::BuildAndRenderBitmapPipeline(0x80, 0x2000, 0x80,
|
||||
overworld_.Tile16Blockset(), *rom(),
|
||||
tile16_blockset_bmp_, palette_);
|
||||
overworld_.Tile16Blockset(), *rom(),
|
||||
tile16_blockset_bmp_, palette_);
|
||||
map_blockset_loaded_ = true;
|
||||
|
||||
// Copy the tile16 data into individual tiles.
|
||||
@@ -653,10 +654,10 @@ absl::Status OverworldEditor::DrawExperimentalModal() {
|
||||
&tile32_configuration_filename_);
|
||||
ImGui::SameLine();
|
||||
gui::FileDialogPipeline("ImportTile32Key", ".DAT,.dat\0", "Tile32 Hex File",
|
||||
[this]() {
|
||||
tile32_configuration_filename_ =
|
||||
ImGuiFileDialog::Instance()->GetFilePathName();
|
||||
});
|
||||
[this]() {
|
||||
tile32_configuration_filename_ =
|
||||
ImGuiFileDialog::Instance()->GetFilePathName();
|
||||
});
|
||||
|
||||
if (ImGui::Button("Load Prototype Overworld with ROM graphics")) {
|
||||
RETURN_IF_ERROR(LoadGraphics())
|
||||
|
||||
@@ -28,11 +28,9 @@ void APU::Init() {
|
||||
}
|
||||
|
||||
void APU::Reset() {
|
||||
// Reset the clock
|
||||
clock_.ResetAccumulatedTime();
|
||||
|
||||
// Reset the SPC700
|
||||
// ...
|
||||
spc700_.Reset();
|
||||
dsp_.Reset();
|
||||
}
|
||||
|
||||
void APU::Update() {
|
||||
@@ -51,6 +49,33 @@ void APU::Update() {
|
||||
ProcessSamples();
|
||||
}
|
||||
|
||||
void APU::Notify(uint32_t address, uint8_t data) {
|
||||
if (address < 0x2140 || address > 0x2143) {
|
||||
return;
|
||||
}
|
||||
auto offset = address - 0x2140;
|
||||
spc700_.write(offset, data);
|
||||
|
||||
// HACK - This is a temporary solution to get the APU to play audio
|
||||
ports_[address - 0x2140] = data;
|
||||
switch (address) {
|
||||
case 0x2140:
|
||||
if (data == BEGIN_SIGNAL) {
|
||||
SignalReady();
|
||||
}
|
||||
break;
|
||||
case 0x2141:
|
||||
// TODO: Handle data byte transfer here
|
||||
break;
|
||||
case 0x2142:
|
||||
// TODO: Handle the setup of destination address
|
||||
break;
|
||||
case 0x2143:
|
||||
// TODO: Handle additional communication/commands
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void APU::ProcessSamples() {
|
||||
// Fetch sample data from AudioRam
|
||||
// Iterate over all voices
|
||||
@@ -62,63 +87,51 @@ void APU::ProcessSamples() {
|
||||
int16_t processed_sample = dsp_.ProcessSample(voice_num, sample);
|
||||
|
||||
// Add the processed sample to the audio buffer
|
||||
audioSamples_.push_back(processed_sample);
|
||||
audio_samples_.push_back(processed_sample);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t APU::FetchSampleForVoice(uint8_t voice_num) {
|
||||
// Define how you determine the address based on the voice_num
|
||||
uint16_t address = CalculateAddressForVoice(voice_num);
|
||||
return aram_.read(address);
|
||||
}
|
||||
|
||||
uint16_t APU::CalculateAddressForVoice(uint8_t voice_num) {
|
||||
// Placeholder logic to calculate the address in the AudioRam
|
||||
// based on the voice number.
|
||||
return voice_num; // Assuming each voice has a fixed size
|
||||
// TODO: Calculate the address for the specified voice
|
||||
return voice_num;
|
||||
}
|
||||
|
||||
int16_t APU::GetNextSample() {
|
||||
// This method fetches the next sample. If there's no sample available, it can
|
||||
// return 0 or the last sample.
|
||||
if (!audioSamples_.empty()) {
|
||||
int16_t sample = audioSamples_.front();
|
||||
audioSamples_.erase(audioSamples_.begin());
|
||||
if (!audio_samples_.empty()) {
|
||||
int16_t sample = audio_samples_.front();
|
||||
audio_samples_.erase(audio_samples_.begin());
|
||||
return sample;
|
||||
}
|
||||
return 0; // or return the last sample
|
||||
}
|
||||
|
||||
uint8_t APU::ReadRegister(uint16_t address) {
|
||||
// ...
|
||||
}
|
||||
|
||||
void APU::WriteRegister(uint16_t address, uint8_t value) {
|
||||
// ...
|
||||
return 0; // TODO: Return the last sample instead of 0.
|
||||
}
|
||||
|
||||
const std::vector<int16_t>& APU::GetAudioSamples() const {
|
||||
// ...
|
||||
return audio_samples_;
|
||||
}
|
||||
|
||||
void APU::UpdateChannelSettings() {
|
||||
// ...
|
||||
// TODO: Implement this method to update the channel settings.
|
||||
}
|
||||
|
||||
int16_t APU::GenerateSample(int channel) {
|
||||
// ...
|
||||
// TODO: Implement this method to generate a sample for the specified channel.
|
||||
}
|
||||
|
||||
void APU::ApplyEnvelope(int channel) {
|
||||
// ...
|
||||
// TODO: Implement this method to apply an envelope to the specified channel.
|
||||
}
|
||||
|
||||
uint8_t APU::ReadDSPMemory(uint16_t address) {
|
||||
// ...
|
||||
uint8_t APU::ReadDspMemory(uint16_t address) {
|
||||
return dsp_.ReadGlobalReg(address);
|
||||
}
|
||||
|
||||
void APU::WriteDSPMemory(uint16_t address, uint8_t value) {
|
||||
// ...
|
||||
void APU::WriteDspMemory(uint16_t address, uint8_t value) {
|
||||
dsp_.WriteGlobalReg(address, value);
|
||||
}
|
||||
|
||||
} // namespace emu
|
||||
|
||||
@@ -39,134 +39,32 @@ const int apuClocksPerSample = 64; // 64 clocks per sample
|
||||
|
||||
class APU : public Observer {
|
||||
public:
|
||||
// Initializes the APU with the necessary resources and dependencies
|
||||
APU(MemoryImpl &memory, AudioRam &aram, Clock &clock)
|
||||
: aram_(aram), clock_(clock), memory_(memory) {}
|
||||
|
||||
void Init();
|
||||
|
||||
// Resets the APU to its initial state
|
||||
void Reset();
|
||||
|
||||
// Runs the APU for one frame
|
||||
void Update();
|
||||
void Notify(uint32_t address, uint8_t data) override;
|
||||
|
||||
void ProcessSamples();
|
||||
|
||||
uint8_t FetchSampleForVoice(uint8_t voice_num);
|
||||
|
||||
uint16_t CalculateAddressForVoice(uint8_t voice_num);
|
||||
|
||||
int16_t GetNextSample();
|
||||
|
||||
void Notify(uint32_t address, uint8_t data) override {
|
||||
ports_[address - 0x2140] = data;
|
||||
|
||||
switch (address) {
|
||||
case 0x2140:
|
||||
if (data == BEGIN_SIGNAL) {
|
||||
BeginTransfer();
|
||||
} else {
|
||||
AcknowledgeSignal();
|
||||
}
|
||||
break;
|
||||
case 0x2141:
|
||||
// Handle data byte transfer here, if needed
|
||||
break;
|
||||
case 0x2142:
|
||||
// Handle the setup of destination address, if needed
|
||||
break;
|
||||
case 0x2143:
|
||||
// Handle additional communication or commands
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Called upon a reset
|
||||
void Initialize() {
|
||||
spc700_.Reset();
|
||||
dsp_.Reset();
|
||||
// Set stack pointer, zero-page values, etc. for the SPC700
|
||||
SignalReady();
|
||||
}
|
||||
|
||||
// Set Port 0 = $AA and Port 1 = $BB
|
||||
void SignalReady() {
|
||||
// Set Port 0 = $AA and Port 1 = $BB
|
||||
ports_[0] = READY_SIGNAL_0;
|
||||
ports_[1] = READY_SIGNAL_1;
|
||||
memory_.WriteByte(0x2140, READY_SIGNAL_0);
|
||||
memory_.WriteByte(0x2141, READY_SIGNAL_1);
|
||||
}
|
||||
|
||||
bool IsReadySignalReceived() const {
|
||||
return ports_[0] == READY_SIGNAL_0 && ports_[1] == READY_SIGNAL_1;
|
||||
}
|
||||
|
||||
void WaitForSignal() const {
|
||||
// This might be an active wait or a passive state where APU does nothing
|
||||
// until it's externally triggered by the main CPU writing to its ports.
|
||||
while (ports_[0] != BEGIN_SIGNAL)
|
||||
;
|
||||
}
|
||||
|
||||
uint16_t ReadAddressFromPorts() const {
|
||||
// Read 2 byte address from port 2 (low) and 3 (high)
|
||||
return static_cast<uint16_t>(ports_[2]) |
|
||||
(static_cast<uint16_t>(ports_[3]) << 8);
|
||||
}
|
||||
|
||||
void AcknowledgeSignal() {
|
||||
// Read value from Port 0 and write it back to Port 0
|
||||
ports_[0] = ports_[0];
|
||||
}
|
||||
|
||||
void BeginTransfer() {
|
||||
const uint16_t startAddress = 0x0200;
|
||||
|
||||
// Write the starting address to ports 0x2142 and 0x2143
|
||||
WriteToPort(2, static_cast<uint8_t>(startAddress & 0xFF)); // Lower byte
|
||||
WriteToPort(3, static_cast<uint8_t>(startAddress >> 8)); // Upper byte
|
||||
|
||||
// Trigger the actual data transfer process
|
||||
TriggerDataTransfer(startAddress);
|
||||
}
|
||||
|
||||
void TriggerDataTransfer(uint16_t startAddress) {
|
||||
const int DATA_SIZE = 0x1000; // Size of the data to be transferred
|
||||
uint8_t audioData[DATA_SIZE]; // Buffer containing the audio data
|
||||
|
||||
// Load audioData as needed...
|
||||
|
||||
for (int i = 0; i < DATA_SIZE; ++i) {
|
||||
WriteToPort(1, audioData[i]); // Write data byte
|
||||
WriteToPort(0, i & 0xFF); // Write index and wait for acknowledgment
|
||||
WaitForAcknowledgment(i & 0xFF);
|
||||
}
|
||||
|
||||
// After transferring all data, trigger the execution of the program
|
||||
StartSpcProgram(startAddress);
|
||||
}
|
||||
|
||||
void WaitForAcknowledgment(uint8_t expectedIndex) {
|
||||
while (ports_[0] != expectedIndex) {
|
||||
// Active wait - consider implementing a more efficient mechanism
|
||||
}
|
||||
}
|
||||
|
||||
void StartSpcProgram(uint16_t startAddress) {
|
||||
// Send the start address for execution
|
||||
WriteToPort(2, static_cast<uint8_t>(startAddress & 0xFF)); // Lower byte
|
||||
WriteToPort(3, static_cast<uint8_t>(startAddress >> 8)); // Upper byte
|
||||
|
||||
WriteToPort(1, 0x00); // Zero value indicates execution command
|
||||
WriteToPort(0, 0xCE); // Send a unique signal to start execution
|
||||
|
||||
// Wait for acknowledgment
|
||||
WaitForAcknowledgment(0xCE);
|
||||
}
|
||||
|
||||
void ExecuteProgram() { spc700_.ExecuteInstructions(ReadAddressFromPorts()); }
|
||||
|
||||
void WriteToPort(uint8_t portNum, uint8_t value) {
|
||||
ports_[portNum] = value;
|
||||
switch (portNum) {
|
||||
@@ -185,10 +83,6 @@ class APU : public Observer {
|
||||
}
|
||||
}
|
||||
|
||||
void SetReadyCallback(std::function<void()> callback) {
|
||||
ready_callback_ = callback;
|
||||
}
|
||||
|
||||
void UpdateClock(int delta_time) { clock_.UpdateClock(delta_time); }
|
||||
|
||||
// Method to fetch a sample from AudioRam
|
||||
@@ -197,13 +91,7 @@ class APU : public Observer {
|
||||
}
|
||||
|
||||
// Method to push a processed sample to the audio buffer
|
||||
void PushToAudioBuffer(int16_t sample) { audioSamples_.push_back(sample); }
|
||||
|
||||
// Reads a byte from the specified APU register
|
||||
uint8_t ReadRegister(uint16_t address);
|
||||
|
||||
// Writes a byte to the specified APU register
|
||||
void WriteRegister(uint16_t address, uint8_t value);
|
||||
void PushToAudioBuffer(int16_t sample) { audio_samples_.push_back(sample); }
|
||||
|
||||
// Returns the audio samples for the current frame
|
||||
const std::vector<int16_t> &GetAudioSamples() const;
|
||||
@@ -227,8 +115,8 @@ class APU : public Observer {
|
||||
void ApplyEnvelope(int channel);
|
||||
|
||||
// Handles DSP (Digital Signal Processor) memory reads and writes
|
||||
uint8_t ReadDSPMemory(uint16_t address);
|
||||
void WriteDSPMemory(uint16_t address, uint8_t value);
|
||||
uint8_t ReadDspMemory(uint16_t address);
|
||||
void WriteDspMemory(uint16_t address, uint8_t value);
|
||||
|
||||
// Member variables to store internal APU state and resources
|
||||
AudioRam &aram_;
|
||||
@@ -237,7 +125,7 @@ class APU : public Observer {
|
||||
|
||||
DigitalSignalProcessor dsp_;
|
||||
Spc700 spc700_{aram_};
|
||||
std::vector<int16_t> audioSamples_;
|
||||
std::vector<int16_t> audio_samples_;
|
||||
|
||||
std::function<void()> ready_callback_;
|
||||
};
|
||||
|
||||
@@ -4,358 +4,89 @@ namespace yaze {
|
||||
namespace app {
|
||||
namespace emu {
|
||||
|
||||
void Spc700::MOV(uint8_t& dest, uint8_t operand) {
|
||||
dest = operand;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
// Immediate
|
||||
uint8_t Spc700::imm() {
|
||||
PC++;
|
||||
return read(PC);
|
||||
}
|
||||
|
||||
void Spc700::MOV_ADDR(uint16_t address, uint8_t operand) {
|
||||
write(address, operand);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
// Direct page
|
||||
uint8_t Spc700::dp() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
return read((PSW.P << 8) + offset);
|
||||
}
|
||||
|
||||
void Spc700::ADC(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest + operand + PSW.C;
|
||||
PSW.V = ((A ^ result) & (operand ^ result) & 0x80);
|
||||
PSW.C = (result > 0xFF);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
PSW.H = ((A ^ operand ^ result) & 0x10);
|
||||
dest = result & 0xFF;
|
||||
uint8_t Spc700::get_dp_addr() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
return (PSW.P << 8) + offset;
|
||||
}
|
||||
|
||||
void Spc700::SBC(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest - operand - (1 - PSW.C);
|
||||
PSW.V = ((dest ^ result) & (dest ^ operand) & 0x80);
|
||||
PSW.C = (result < 0x100);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
PSW.H = ((dest ^ operand ^ result) & 0x10);
|
||||
dest = result & 0xFF;
|
||||
// Direct page indexed by X
|
||||
uint8_t Spc700::dp_plus_x() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
return read((PSW.P << 8) + offset + X);
|
||||
}
|
||||
|
||||
void Spc700::CMP(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest - operand;
|
||||
PSW.C = (result < 0x100);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
// Direct page indexed by Y
|
||||
uint8_t Spc700::dp_plus_y() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
return read((PSW.P << 8) + offset + Y);
|
||||
}
|
||||
|
||||
void Spc700::AND(uint8_t& dest, uint8_t operand) {
|
||||
dest &= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
// Indexed indirect (add index before 16-bit lookup).
|
||||
uint16_t Spc700::dp_plus_x_indirect() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
uint16_t addr = read((PSW.P << 8) + offset + X) |
|
||||
(read((PSW.P << 8) + offset + X + 1) << 8);
|
||||
return addr;
|
||||
}
|
||||
|
||||
void Spc700::OR(uint8_t& dest, uint8_t operand) {
|
||||
dest |= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
// Indirect indexed (add index after 16-bit lookup).
|
||||
uint16_t Spc700::dp_indirect_plus_y() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
uint16_t baseAddr =
|
||||
read((PSW.P << 8) + offset) | (read((PSW.P << 8) + offset + 1) << 8);
|
||||
return baseAddr + Y;
|
||||
}
|
||||
|
||||
void Spc700::EOR(uint8_t& dest, uint8_t operand) {
|
||||
dest ^= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
uint16_t Spc700::abs() {
|
||||
PC++;
|
||||
uint16_t addr = read(PC) | (read(PC) << 8);
|
||||
return addr;
|
||||
}
|
||||
|
||||
void Spc700::ASL(uint8_t operand) {
|
||||
PSW.C = (operand & 0x80);
|
||||
operand <<= 1;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
// A = value;
|
||||
int8_t Spc700::rel() {
|
||||
PC++;
|
||||
return static_cast<int8_t>(read(PC));
|
||||
}
|
||||
|
||||
void Spc700::LSR(uint8_t& operand) {
|
||||
PSW.C = (operand & 0x01);
|
||||
operand >>= 1;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
uint8_t Spc700::i() { return read((PSW.P << 8) + X); }
|
||||
|
||||
uint8_t Spc700::i_postinc() {
|
||||
uint8_t value = read((PSW.P << 8) + X);
|
||||
X++;
|
||||
return value;
|
||||
}
|
||||
|
||||
void Spc700::ROL(uint8_t operand, bool isImmediate) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
uint8_t carry = PSW.C;
|
||||
PSW.C = (value & 0x80);
|
||||
value <<= 1;
|
||||
value |= carry;
|
||||
PSW.Z = (value == 0);
|
||||
PSW.N = (value & 0x80);
|
||||
// operand = value;
|
||||
uint16_t Spc700::addr_plus_i() {
|
||||
PC++;
|
||||
uint16_t addr = read(PC) | (read(PC) << 8);
|
||||
return read(addr) + X;
|
||||
}
|
||||
|
||||
void Spc700::XCN(uint8_t operand, bool isImmediate) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4);
|
||||
PSW.Z = (value == 0);
|
||||
PSW.N = (value & 0x80);
|
||||
// operand = value;
|
||||
uint16_t Spc700::addr_plus_i_indexed() {
|
||||
PC++;
|
||||
uint16_t addr = read(PC) | (read(PC) << 8);
|
||||
addr += X;
|
||||
return read(addr) | (read(addr + 1) << 8);
|
||||
}
|
||||
|
||||
void Spc700::INC(uint8_t& operand) {
|
||||
operand++;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::DEC(uint8_t& operand) {
|
||||
operand--;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::MOVW(uint16_t& dest, uint16_t operand) {
|
||||
dest = operand;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::INCW(uint16_t& operand) {
|
||||
operand++;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::DECW(uint16_t& operand) {
|
||||
operand--;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::ADDW(uint16_t& dest, uint16_t operand) {
|
||||
uint32_t result = dest + operand;
|
||||
PSW.C = (result > 0xFFFF);
|
||||
PSW.Z = ((result & 0xFFFF) == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
PSW.V = ((dest ^ result) & (operand ^ result) & 0x8000);
|
||||
dest = result & 0xFFFF;
|
||||
}
|
||||
|
||||
void Spc700::SUBW(uint16_t& dest, uint16_t operand) {
|
||||
uint32_t result = dest - operand;
|
||||
PSW.C = (result < 0x10000);
|
||||
PSW.Z = ((result & 0xFFFF) == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
PSW.V = ((dest ^ result) & (dest ^ operand) & 0x8000);
|
||||
dest = result & 0xFFFF;
|
||||
}
|
||||
|
||||
void Spc700::CMPW(uint16_t operand) {
|
||||
uint32_t result = YA - operand;
|
||||
PSW.C = (result < 0x10000);
|
||||
PSW.Z = ((result & 0xFFFF) == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::MUL(uint8_t operand) {
|
||||
uint16_t result = A * operand;
|
||||
YA = result;
|
||||
PSW.Z = (result == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::DIV(uint8_t operand) {
|
||||
if (operand == 0) {
|
||||
// Handle divide by zero error
|
||||
return;
|
||||
}
|
||||
uint8_t quotient = A / operand;
|
||||
uint8_t remainder = A % operand;
|
||||
A = quotient;
|
||||
Y = remainder;
|
||||
PSW.Z = (quotient == 0);
|
||||
PSW.N = (quotient & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::BRA(int8_t offset) { PC += offset; }
|
||||
|
||||
void Spc700::BEQ(int8_t offset) {
|
||||
if (PSW.Z) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BNE(int8_t offset) {
|
||||
if (!PSW.Z) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BCS(int8_t offset) {
|
||||
if (PSW.C) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BCC(int8_t offset) {
|
||||
if (!PSW.C) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BVS(int8_t offset) {
|
||||
if (PSW.V) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BVC(int8_t offset) {
|
||||
if (!PSW.V) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BMI(int8_t offset) {
|
||||
if (PSW.N) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BPL(int8_t offset) {
|
||||
if (!PSW.N) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BBS(uint8_t bit, uint8_t operand) {
|
||||
if (operand & (1 << bit)) {
|
||||
PC += rel();
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BBC(uint8_t bit, uint8_t operand) {
|
||||
if (!(operand & (1 << bit))) {
|
||||
PC += rel();
|
||||
}
|
||||
}
|
||||
|
||||
// CBNE DBNZ
|
||||
// JMP
|
||||
void Spc700::JMP(uint16_t address) { PC = address; }
|
||||
|
||||
void Spc700::CALL(uint16_t address) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = address;
|
||||
}
|
||||
|
||||
void Spc700::PCALL(uint8_t offset) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC += offset;
|
||||
}
|
||||
|
||||
void Spc700::TCALL(uint8_t offset) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = 0xFFDE + offset;
|
||||
}
|
||||
|
||||
void Spc700::BRK() {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = 0xFFDE;
|
||||
}
|
||||
|
||||
void Spc700::RET() {
|
||||
uint16_t return_address = read(SP) | (read(SP + 1) << 8);
|
||||
SP += 2;
|
||||
PC = return_address;
|
||||
}
|
||||
|
||||
void Spc700::RETI() {
|
||||
uint16_t return_address = read(SP) | (read(SP + 1) << 8);
|
||||
SP += 2;
|
||||
PC = return_address;
|
||||
PSW.I = 1;
|
||||
}
|
||||
|
||||
void Spc700::PUSH(uint8_t operand) {
|
||||
write(SP, operand);
|
||||
SP--;
|
||||
}
|
||||
|
||||
void Spc700::POP(uint8_t& operand) {
|
||||
SP++;
|
||||
operand = read(SP);
|
||||
}
|
||||
|
||||
void Spc700::SET1(uint8_t bit, uint8_t& operand) { operand |= (1 << bit); }
|
||||
|
||||
void Spc700::CLR1(uint8_t bit, uint8_t& operand) { operand &= ~(1 << bit); }
|
||||
|
||||
void Spc700::TSET1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand |= (1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::TCLR1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand &= ~(1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::AND1(uint8_t bit, uint8_t& operand) {
|
||||
operand &= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::OR1(uint8_t bit, uint8_t& operand) {
|
||||
operand |= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::EOR1(uint8_t bit, uint8_t& operand) {
|
||||
operand ^= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::NOT1(uint8_t bit, uint8_t& operand) {
|
||||
operand ^= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::MOV1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand |= (1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::CLRC() { PSW.C = 0; }
|
||||
|
||||
void Spc700::SETC() { PSW.C = 1; }
|
||||
|
||||
void Spc700::NOTC() { PSW.C = !PSW.C; }
|
||||
|
||||
void Spc700::CLRV() { PSW.V = 0; }
|
||||
|
||||
void Spc700::CLRP() { PSW.P = 0; }
|
||||
|
||||
void Spc700::SETP() { PSW.P = 1; }
|
||||
|
||||
void Spc700::EI() { PSW.I = 1; }
|
||||
|
||||
void Spc700::DI() { PSW.I = 0; }
|
||||
|
||||
void Spc700::NOP() { PC++; }
|
||||
|
||||
void Spc700::SLEEP() {}
|
||||
|
||||
void Spc700::STOP() {}
|
||||
|
||||
} // namespace emu
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
361
src/app/emu/audio/internal/instructions.cc
Normal file
361
src/app/emu/audio/internal/instructions.cc
Normal file
@@ -0,0 +1,361 @@
|
||||
#include "app/emu/audio/spc700.h"
|
||||
|
||||
namespace yaze {
|
||||
namespace app {
|
||||
namespace emu {
|
||||
|
||||
void Spc700::MOV(uint8_t& dest, uint8_t operand) {
|
||||
dest = operand;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::MOV_ADDR(uint16_t address, uint8_t operand) {
|
||||
write(address, operand);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::ADC(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest + operand + PSW.C;
|
||||
PSW.V = ((A ^ result) & (operand ^ result) & 0x80);
|
||||
PSW.C = (result > 0xFF);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
PSW.H = ((A ^ operand ^ result) & 0x10);
|
||||
dest = result & 0xFF;
|
||||
}
|
||||
|
||||
void Spc700::SBC(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest - operand - (1 - PSW.C);
|
||||
PSW.V = ((dest ^ result) & (dest ^ operand) & 0x80);
|
||||
PSW.C = (result < 0x100);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
PSW.H = ((dest ^ operand ^ result) & 0x10);
|
||||
dest = result & 0xFF;
|
||||
}
|
||||
|
||||
void Spc700::CMP(uint8_t& dest, uint8_t operand) {
|
||||
uint16_t result = dest - operand;
|
||||
PSW.C = (result < 0x100);
|
||||
PSW.Z = ((result & 0xFF) == 0);
|
||||
PSW.N = (result & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::AND(uint8_t& dest, uint8_t operand) {
|
||||
dest &= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::OR(uint8_t& dest, uint8_t operand) {
|
||||
dest |= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::EOR(uint8_t& dest, uint8_t operand) {
|
||||
dest ^= operand;
|
||||
PSW.Z = (dest == 0);
|
||||
PSW.N = (dest & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::ASL(uint8_t operand) {
|
||||
PSW.C = (operand & 0x80);
|
||||
operand <<= 1;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
// A = value;
|
||||
}
|
||||
|
||||
void Spc700::LSR(uint8_t& operand) {
|
||||
PSW.C = (operand & 0x01);
|
||||
operand >>= 1;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::ROL(uint8_t operand, bool isImmediate) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
uint8_t carry = PSW.C;
|
||||
PSW.C = (value & 0x80);
|
||||
value <<= 1;
|
||||
value |= carry;
|
||||
PSW.Z = (value == 0);
|
||||
PSW.N = (value & 0x80);
|
||||
// operand = value;
|
||||
}
|
||||
|
||||
void Spc700::XCN(uint8_t operand, bool isImmediate) {
|
||||
uint8_t value = isImmediate ? imm() : operand;
|
||||
value = ((value & 0xF0) >> 4) | ((value & 0x0F) << 4);
|
||||
PSW.Z = (value == 0);
|
||||
PSW.N = (value & 0x80);
|
||||
// operand = value;
|
||||
}
|
||||
|
||||
void Spc700::INC(uint8_t& operand) {
|
||||
operand++;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::DEC(uint8_t& operand) {
|
||||
operand--;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::MOVW(uint16_t& dest, uint16_t operand) {
|
||||
dest = operand;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::INCW(uint16_t& operand) {
|
||||
operand++;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::DECW(uint16_t& operand) {
|
||||
operand--;
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::ADDW(uint16_t& dest, uint16_t operand) {
|
||||
uint32_t result = dest + operand;
|
||||
PSW.C = (result > 0xFFFF);
|
||||
PSW.Z = ((result & 0xFFFF) == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
PSW.V = ((dest ^ result) & (operand ^ result) & 0x8000);
|
||||
dest = result & 0xFFFF;
|
||||
}
|
||||
|
||||
void Spc700::SUBW(uint16_t& dest, uint16_t operand) {
|
||||
uint32_t result = dest - operand;
|
||||
PSW.C = (result < 0x10000);
|
||||
PSW.Z = ((result & 0xFFFF) == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
PSW.V = ((dest ^ result) & (dest ^ operand) & 0x8000);
|
||||
dest = result & 0xFFFF;
|
||||
}
|
||||
|
||||
void Spc700::CMPW(uint16_t operand) {
|
||||
uint32_t result = YA - operand;
|
||||
PSW.C = (result < 0x10000);
|
||||
PSW.Z = ((result & 0xFFFF) == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::MUL(uint8_t operand) {
|
||||
uint16_t result = A * operand;
|
||||
YA = result;
|
||||
PSW.Z = (result == 0);
|
||||
PSW.N = (result & 0x8000);
|
||||
}
|
||||
|
||||
void Spc700::DIV(uint8_t operand) {
|
||||
if (operand == 0) {
|
||||
// Handle divide by zero error
|
||||
return;
|
||||
}
|
||||
uint8_t quotient = A / operand;
|
||||
uint8_t remainder = A % operand;
|
||||
A = quotient;
|
||||
Y = remainder;
|
||||
PSW.Z = (quotient == 0);
|
||||
PSW.N = (quotient & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::BRA(int8_t offset) { PC += offset; }
|
||||
|
||||
void Spc700::BEQ(int8_t offset) {
|
||||
if (PSW.Z) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BNE(int8_t offset) {
|
||||
if (!PSW.Z) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BCS(int8_t offset) {
|
||||
if (PSW.C) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BCC(int8_t offset) {
|
||||
if (!PSW.C) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BVS(int8_t offset) {
|
||||
if (PSW.V) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BVC(int8_t offset) {
|
||||
if (!PSW.V) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BMI(int8_t offset) {
|
||||
if (PSW.N) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BPL(int8_t offset) {
|
||||
if (!PSW.N) {
|
||||
PC += offset;
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BBS(uint8_t bit, uint8_t operand) {
|
||||
if (operand & (1 << bit)) {
|
||||
PC += rel();
|
||||
}
|
||||
}
|
||||
|
||||
void Spc700::BBC(uint8_t bit, uint8_t operand) {
|
||||
if (!(operand & (1 << bit))) {
|
||||
PC += rel();
|
||||
}
|
||||
}
|
||||
|
||||
// CBNE DBNZ
|
||||
// JMP
|
||||
void Spc700::JMP(uint16_t address) { PC = address; }
|
||||
|
||||
void Spc700::CALL(uint16_t address) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = address;
|
||||
}
|
||||
|
||||
void Spc700::PCALL(uint8_t offset) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC += offset;
|
||||
}
|
||||
|
||||
void Spc700::TCALL(uint8_t offset) {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = 0xFFDE + offset;
|
||||
}
|
||||
|
||||
void Spc700::BRK() {
|
||||
uint16_t return_address = PC + 2;
|
||||
write(SP, return_address & 0xFF);
|
||||
write(SP - 1, (return_address >> 8) & 0xFF);
|
||||
SP -= 2;
|
||||
PC = 0xFFDE;
|
||||
}
|
||||
|
||||
void Spc700::RET() {
|
||||
uint16_t return_address = read(SP) | (read(SP + 1) << 8);
|
||||
SP += 2;
|
||||
PC = return_address;
|
||||
}
|
||||
|
||||
void Spc700::RETI() {
|
||||
uint16_t return_address = read(SP) | (read(SP + 1) << 8);
|
||||
SP += 2;
|
||||
PC = return_address;
|
||||
PSW.I = 1;
|
||||
}
|
||||
|
||||
void Spc700::PUSH(uint8_t operand) {
|
||||
write(SP, operand);
|
||||
SP--;
|
||||
}
|
||||
|
||||
void Spc700::POP(uint8_t& operand) {
|
||||
SP++;
|
||||
operand = read(SP);
|
||||
}
|
||||
|
||||
void Spc700::SET1(uint8_t bit, uint8_t& operand) { operand |= (1 << bit); }
|
||||
|
||||
void Spc700::CLR1(uint8_t bit, uint8_t& operand) { operand &= ~(1 << bit); }
|
||||
|
||||
void Spc700::TSET1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand |= (1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::TCLR1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand &= ~(1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::AND1(uint8_t bit, uint8_t& operand) {
|
||||
operand &= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::OR1(uint8_t bit, uint8_t& operand) {
|
||||
operand |= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::EOR1(uint8_t bit, uint8_t& operand) {
|
||||
operand ^= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::NOT1(uint8_t bit, uint8_t& operand) {
|
||||
operand ^= (1 << bit);
|
||||
PSW.Z = (operand == 0);
|
||||
PSW.N = (operand & 0x80);
|
||||
}
|
||||
|
||||
void Spc700::MOV1(uint8_t bit, uint8_t& operand) {
|
||||
PSW.C = (operand & (1 << bit));
|
||||
operand |= (1 << bit);
|
||||
}
|
||||
|
||||
void Spc700::CLRC() { PSW.C = 0; }
|
||||
|
||||
void Spc700::SETC() { PSW.C = 1; }
|
||||
|
||||
void Spc700::NOTC() { PSW.C = !PSW.C; }
|
||||
|
||||
void Spc700::CLRV() { PSW.V = 0; }
|
||||
|
||||
void Spc700::CLRP() { PSW.P = 0; }
|
||||
|
||||
void Spc700::SETP() { PSW.P = 1; }
|
||||
|
||||
void Spc700::EI() { PSW.I = 1; }
|
||||
|
||||
void Spc700::DI() { PSW.I = 0; }
|
||||
|
||||
void Spc700::NOP() { PC++; }
|
||||
|
||||
void Spc700::SLEEP() {}
|
||||
|
||||
void Spc700::STOP() {}
|
||||
|
||||
} // namespace emu
|
||||
} // namespace app
|
||||
} // namespace yaze
|
||||
@@ -12,20 +12,21 @@ namespace yaze {
|
||||
namespace app {
|
||||
namespace emu {
|
||||
|
||||
void Spc700::Reset() {}
|
||||
void Spc700::Reset() {
|
||||
PC = 0;
|
||||
A = 0;
|
||||
X = 0;
|
||||
Y = 0;
|
||||
SP = 0xFF;
|
||||
PSW = ByteToFlags(0x00);
|
||||
aram_.reset();
|
||||
}
|
||||
|
||||
void Spc700::BootIplRom() {
|
||||
PC = 0xFFC0;
|
||||
A = 0;
|
||||
X = 0;
|
||||
Y = 0;
|
||||
|
||||
// for (int i = 0; i < 0x40; ++i) {
|
||||
// uint8_t opcode = read(PC);
|
||||
// ExecuteInstructions(opcode);
|
||||
// PC++;
|
||||
// }
|
||||
|
||||
int i = 0;
|
||||
while (PC != 0xFFC0 + 0x3F) {
|
||||
uint8_t opcode = read(PC);
|
||||
@@ -615,16 +616,27 @@ void Spc700::ExecuteInstructions(uint8_t opcode) {
|
||||
case 0x1F: // JMP [!abs+X]
|
||||
break;
|
||||
|
||||
// . subroutines
|
||||
|
||||
// . subroutines
|
||||
case 0x3F: // CALL !abs
|
||||
{
|
||||
CALL(abs());
|
||||
break;
|
||||
}
|
||||
case 0x4F: // PCALL up
|
||||
{
|
||||
PCALL(imm());
|
||||
break;
|
||||
}
|
||||
case 0x6F: // RET
|
||||
{
|
||||
RET();
|
||||
break;
|
||||
}
|
||||
case 0x7F: // RETI
|
||||
{
|
||||
RETI();
|
||||
break;
|
||||
}
|
||||
|
||||
// . stack
|
||||
case 0x2D: // PUSH A
|
||||
|
||||
@@ -13,27 +13,23 @@ namespace emu {
|
||||
class AudioRam {
|
||||
public:
|
||||
virtual ~AudioRam() = default;
|
||||
|
||||
// Read a byte from ARAM at the given address
|
||||
virtual void reset() = 0;
|
||||
virtual uint8_t read(uint16_t address) const = 0;
|
||||
|
||||
// Write a byte to ARAM at the given address
|
||||
virtual void write(uint16_t address, uint8_t value) = 0;
|
||||
};
|
||||
|
||||
class AudioRamImpl : public AudioRam {
|
||||
static const size_t ARAM_SIZE = 64 * 1024; // 64 KB
|
||||
static const int ARAM_SIZE = 0x10000;
|
||||
std::vector<uint8_t> ram = std::vector<uint8_t>(ARAM_SIZE, 0);
|
||||
|
||||
public:
|
||||
AudioRamImpl() = default;
|
||||
void reset() override { ram = std::vector<uint8_t>(ARAM_SIZE, 0); }
|
||||
|
||||
// Read a byte from ARAM at the given address
|
||||
uint8_t read(uint16_t address) const override {
|
||||
return ram[address % ARAM_SIZE];
|
||||
}
|
||||
|
||||
// Write a byte to ARAM at the given address
|
||||
void write(uint16_t address, uint8_t value) override {
|
||||
ram[address % ARAM_SIZE] = value;
|
||||
}
|
||||
@@ -54,17 +50,14 @@ class Spc700 {
|
||||
|
||||
public:
|
||||
explicit Spc700(AudioRam& aram) : aram_(aram) {}
|
||||
uint8_t test_register_;
|
||||
uint8_t control_register_;
|
||||
uint8_t dsp_address_register_;
|
||||
|
||||
// Registers
|
||||
uint8_t A = 0; // 8-bit accumulator
|
||||
uint8_t X = 0; // 8-bit index
|
||||
uint8_t Y = 0; // 8-bit index
|
||||
uint16_t YA = 0; // 16-bit pair of A (lsb) and Y (msb)
|
||||
uint16_t PC = 0; // program counter
|
||||
uint8_t SP = 0; // stack pointer
|
||||
uint8_t A = 0x00; // 8-bit accumulator
|
||||
uint8_t X = 0x00; // 8-bit index
|
||||
uint8_t Y = 0x00; // 8-bit index
|
||||
uint16_t YA = 0x00; // 16-bit pair of A (lsb) and Y (msb)
|
||||
uint16_t PC = 0xFFC0; // program counter
|
||||
uint8_t SP = 0x00; // stack pointer
|
||||
|
||||
struct Flags {
|
||||
uint8_t N : 1; // Negative flag
|
||||
@@ -105,42 +98,26 @@ class Spc700 {
|
||||
|
||||
// Read a byte from the memory-mapped registers
|
||||
uint8_t read(uint16_t address) {
|
||||
switch (address) {
|
||||
case 0xF0:
|
||||
return test_register_;
|
||||
case 0xF1:
|
||||
return control_register_;
|
||||
case 0xF2:
|
||||
return dsp_address_register_;
|
||||
default:
|
||||
if (address < 0xFFC0) {
|
||||
return aram_.read(address);
|
||||
} else {
|
||||
// Handle IPL ROM or RAM reads here
|
||||
return ipl_rom_[address - 0xFFC0];
|
||||
}
|
||||
if (address < 0xFFC0) {
|
||||
return aram_.read(address);
|
||||
} else {
|
||||
// Check if register is set to unmap the IPL ROM
|
||||
if (read(0xF1) & 0x80) {
|
||||
return aram_.read(address);
|
||||
}
|
||||
return ipl_rom_[address - 0xFFC0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write a byte to the memory-mapped registers
|
||||
void write(uint16_t address, uint8_t value) {
|
||||
switch (address) {
|
||||
case 0xF0:
|
||||
test_register_ = value;
|
||||
break;
|
||||
case 0xF1:
|
||||
control_register_ = value;
|
||||
break;
|
||||
case 0xF2:
|
||||
dsp_address_register_ = value;
|
||||
break;
|
||||
default:
|
||||
if (address < 0xFFC0) {
|
||||
aram_.write(address, value);
|
||||
} else {
|
||||
// Handle IPL ROM or RAM writes here
|
||||
}
|
||||
if (address < 0xFFC0) {
|
||||
aram_.write(address, value);
|
||||
} else {
|
||||
// Check if register is set to unmap the IPL ROM
|
||||
if (read(0xF1) & 0x80) {
|
||||
aram_.write(address, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -148,87 +125,36 @@ class Spc700 {
|
||||
// Addressing modes
|
||||
|
||||
// Immediate
|
||||
uint8_t imm() {
|
||||
PC++;
|
||||
return read(PC);
|
||||
}
|
||||
uint8_t imm();
|
||||
|
||||
// Direct page
|
||||
uint8_t dp() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
return read((PSW.P << 8) + offset);
|
||||
}
|
||||
uint8_t dp();
|
||||
|
||||
uint8_t get_dp_addr() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
return (PSW.P << 8) + offset;
|
||||
}
|
||||
uint8_t get_dp_addr();
|
||||
|
||||
// Direct page indexed by X
|
||||
uint8_t dp_plus_x() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
return read((PSW.P << 8) + offset + X);
|
||||
}
|
||||
uint8_t dp_plus_x();
|
||||
|
||||
// Direct page indexed by Y
|
||||
uint8_t dp_plus_y() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
return read((PSW.P << 8) + offset + Y);
|
||||
}
|
||||
uint8_t dp_plus_y();
|
||||
|
||||
// Indexed indirect (add index before 16-bit lookup).
|
||||
uint16_t dp_plus_x_indirect() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
uint16_t addr = read((PSW.P << 8) + offset + X) |
|
||||
(read((PSW.P << 8) + offset + X + 1) << 8);
|
||||
return addr;
|
||||
}
|
||||
uint16_t dp_plus_x_indirect();
|
||||
|
||||
// Indirect indexed (add index after 16-bit lookup).
|
||||
uint16_t dp_indirect_plus_y() {
|
||||
PC++;
|
||||
uint8_t offset = read(PC);
|
||||
uint16_t baseAddr =
|
||||
read((PSW.P << 8) + offset) | (read((PSW.P << 8) + offset + 1) << 8);
|
||||
return baseAddr + Y;
|
||||
}
|
||||
uint16_t dp_indirect_plus_y();
|
||||
|
||||
uint16_t abs() {
|
||||
PC++;
|
||||
uint16_t addr = read(PC) | (read(PC) << 8);
|
||||
return addr;
|
||||
}
|
||||
uint16_t abs();
|
||||
|
||||
int8_t rel() {
|
||||
PC++;
|
||||
return static_cast<int8_t>(read(PC));
|
||||
}
|
||||
int8_t rel();
|
||||
|
||||
uint8_t i() { return read((PSW.P << 8) + X); }
|
||||
uint8_t i();
|
||||
|
||||
uint8_t i_postinc() {
|
||||
uint8_t value = read((PSW.P << 8) + X);
|
||||
X++;
|
||||
return value;
|
||||
}
|
||||
uint8_t i_postinc();
|
||||
|
||||
uint16_t addr_plus_i() {
|
||||
PC++;
|
||||
uint16_t addr = read(PC) | (read(PC) << 8);
|
||||
return read(addr) + X;
|
||||
}
|
||||
uint16_t addr_plus_i();
|
||||
|
||||
uint16_t addr_plus_i_indexed() {
|
||||
PC++;
|
||||
uint16_t addr = read(PC) | (read(PC) << 8);
|
||||
addr += X;
|
||||
return read(addr) | (read(addr + 1) << 8);
|
||||
}
|
||||
uint16_t addr_plus_i_indexed();
|
||||
|
||||
// ==========================================================================
|
||||
// Instructions
|
||||
|
||||
@@ -1876,6 +1876,7 @@ uint8_t CPU::GetInstructionLength(uint8_t opcode) {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Implement 65816 interrupts.
|
||||
void CPU::HandleInterrupts() {
|
||||
if (GetInterruptFlag()) {
|
||||
return;
|
||||
|
||||
@@ -178,7 +178,6 @@ class CPU : public Memory, public Loggable, public core::ExperimentFlags {
|
||||
// LDA addr, Y
|
||||
uint32_t AbsoluteIndexedY();
|
||||
|
||||
// Test Me :)
|
||||
// Effective Address:
|
||||
// Bank: Program Bank Register (PBR)
|
||||
// High/low: The Indirect Address
|
||||
|
||||
@@ -329,17 +329,6 @@ void SNES::VBlankRoutine() {
|
||||
// ...
|
||||
}
|
||||
|
||||
void SNES::BootApuWithIPL() {
|
||||
// 1. Check if the SPC700 is ready, else set a callback for when it becomes
|
||||
// ready
|
||||
if (!apu_.IsReadySignalReceived()) {
|
||||
apu_.SetReadyCallback([this]() { this->StartApuDataTransfer(); });
|
||||
return; // Exit and wait for callback to be called
|
||||
}
|
||||
|
||||
StartApuDataTransfer();
|
||||
}
|
||||
|
||||
void SNES::StartApuDataTransfer() {
|
||||
// 2. Setting the starting address
|
||||
const uint16_t startAddress = 0x0200;
|
||||
|
||||
@@ -389,6 +389,7 @@ void Canvas::DrawGrid(float grid_step) {
|
||||
draw_list_->PushClipRect(canvas_p0_, canvas_p1_, true);
|
||||
if (enable_grid_) {
|
||||
if (custom_step_ != 0.f) grid_step = custom_step_;
|
||||
|
||||
grid_step *= global_scale_; // Apply global scale to grid step
|
||||
for (float x = fmodf(scrolling_.x, grid_step); x < canvas_sz_.x;
|
||||
x += grid_step)
|
||||
|
||||
@@ -96,7 +96,7 @@ class Canvas {
|
||||
bool custom_canvas_size_ = false;
|
||||
bool is_hovered_ = false;
|
||||
|
||||
float custom_step_ = 8.0f;
|
||||
float custom_step_ = 0.0f;
|
||||
float global_scale_ = 1.0f;
|
||||
|
||||
ImDrawList* draw_list_;
|
||||
|
||||
@@ -202,6 +202,7 @@ absl::StatusOr<Bytes> ROM::Load2BppGraphics() {
|
||||
return sheet;
|
||||
}
|
||||
|
||||
// TODO: Load Links graphics from the ROM
|
||||
absl::Status ROM::LoadLinkGraphics() {
|
||||
const auto link_gfx_offset = 81920; // $10:8000
|
||||
const auto link_gfx_length = 0x800;
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "app/emu/cpu.h"
|
||||
#include "app/emu/cpu/cpu.h"
|
||||
#include "app/emu/memory/memory.h"
|
||||
#include "app/emu/video/ppu.h"
|
||||
#include "app/gfx/snes_palette.h"
|
||||
@@ -147,7 +147,7 @@ class DungeonObjectRenderer : public SharedROM {
|
||||
|
||||
int i = 0;
|
||||
while (true) {
|
||||
uint8_t opcode = cpu.FetchByte();
|
||||
uint8_t opcode = cpu.ReadByte(cpu.PC);
|
||||
cpu.ExecuteInstruction(opcode);
|
||||
cpu.HandleInterrupts();
|
||||
|
||||
@@ -156,7 +156,7 @@ class DungeonObjectRenderer : public SharedROM {
|
||||
}
|
||||
i++;
|
||||
|
||||
UpdateObjectBitmap();
|
||||
// UpdateObjectBitmap();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user