1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-21 21:33:54 +00:00

Add optional transaction records to the Blitter.

This commit is contained in:
Thomas Harte 2022-08-06 09:51:20 -04:00
parent 612413cb1c
commit 45892f3584
3 changed files with 94 additions and 14 deletions

View File

@ -113,7 +113,8 @@ constexpr uint32_t fill_values[] = {
}
void Blitter::set_control(int index, uint16_t value) {
template <bool record_bus>
void Blitter<record_bus>::set_control(int index, uint16_t value) {
if(index) {
line_mode_ = (value & 0x0001);
one_dot_ = value & 0x0002;
@ -132,17 +133,20 @@ void Blitter::set_control(int index, uint16_t value) {
LOG("Set control " << index << " to " << PADHEX(4) << value);
}
void Blitter::set_first_word_mask(uint16_t value) {
template <bool record_bus>
void Blitter<record_bus>::set_first_word_mask(uint16_t value) {
LOG("Set first word mask: " << PADHEX(4) << value);
a_mask_[0] = value;
}
void Blitter::set_last_word_mask(uint16_t value) {
template <bool record_bus>
void Blitter<record_bus>::set_last_word_mask(uint16_t value) {
LOG("Set last word mask: " << PADHEX(4) << value);
a_mask_[1] = value;
}
void Blitter::set_size(uint16_t value) {
template <bool record_bus>
void Blitter<record_bus>::set_size(uint16_t value) {
// width_ = (width_ & ~0x3f) | (value & 0x3f);
// height_ = (height_ & ~0x3ff) | (value >> 6);
width_ = value & 0x3f;
@ -155,21 +159,25 @@ void Blitter::set_size(uint16_t value) {
// blitter that it should treat itself as about to start a new line.
}
void Blitter::set_minterms(uint16_t value) {
template <bool record_bus>
void Blitter<record_bus>::set_minterms(uint16_t value) {
LOG("Set minterms " << PADHEX(4) << value);
minterms_ = value & 0xff;
}
//void Blitter::set_vertical_size([[maybe_unused]] uint16_t value) {
//template <bool record_bus>
//void Blitter<record_bus>::set_vertical_size([[maybe_unused]] uint16_t value) {
// LOG("Set vertical size " << PADHEX(4) << value);
// // TODO. This is ECS only, I think. Ditto set_horizontal_size.
//}
//
//void Blitter::set_horizontal_size([[maybe_unused]] uint16_t value) {
//template <bool record_bus>
//void Blitter<record_bus>::set_horizontal_size([[maybe_unused]] uint16_t value) {
// LOG("Set horizontal size " << PADHEX(4) << value);
//}
void Blitter::set_data(int channel, uint16_t value) {
template <bool record_bus>
void Blitter<record_bus>::set_data(int channel, uint16_t value) {
LOG("Set data " << channel << " to " << PADHEX(4) << value);
// Ugh, backed myself into a corner. TODO: clean.
@ -181,7 +189,8 @@ void Blitter::set_data(int channel, uint16_t value) {
}
}
uint16_t Blitter::get_status() {
template <bool record_bus>
uint16_t Blitter<record_bus>::get_status() {
const uint16_t result =
(not_zero_flag_ ? 0x0000 : 0x2000) | (height_ ? 0x4000 : 0x0000);
LOG("Returned status of " << result);
@ -216,14 +225,16 @@ uint16_t Blitter::get_status() {
//
// Table 6-2: Typical Blitter Cycle Sequence
void Blitter::add_modulos() {
template <bool record_bus>
void Blitter<record_bus>::add_modulos() {
pointer_[0] += modulos_[0] * sequencer_.channel_enabled<0>()* direction_;
pointer_[1] += modulos_[1] * sequencer_.channel_enabled<1>() * direction_;
pointer_[2] += modulos_[2] * sequencer_.channel_enabled<2>() * direction_;
pointer_[3] += modulos_[3] * sequencer_.channel_enabled<3>() * direction_;
}
bool Blitter::advance_dma() {
template <bool record_bus>
bool Blitter<record_bus>::advance_dma() {
if(!height_) return false;
if(line_mode_) {
@ -289,11 +300,18 @@ bool Blitter::advance_dma() {
// TODO: patterned lines. Unclear what to do with the bit that comes out of b.
// Probably extend it to a full word?
c_data_ = ram_[pointer_[3] & ram_mask_];
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::ReadC, pointer_[3], c_data_);
}
const uint16_t output =
apply_minterm<uint16_t>(a_data_ >> shifts_[0], b_data_, c_data_, minterms_);
ram_[pointer_[3] & ram_mask_] = output;
not_zero_flag_ |= output;
draw_ &= !one_dot_;
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::WriteFromPipeline, pointer_[3], output);
}
}
constexpr int LEFT = 1 << 0;
@ -383,14 +401,26 @@ bool Blitter::advance_dma() {
switch(next.first) {
case Channel::A:
a_data_ = ram_[pointer_[0] & ram_mask_];
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::ReadA, pointer_[0], a_data_);
}
pointer_[0] += direction_;
return true;
case Channel::B:
b_data_ = ram_[pointer_[1] & ram_mask_];
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::ReadB, pointer_[1], b_data_);
}
pointer_[1] += direction_;
return true;
case Channel::C:
c_data_ = ram_[pointer_[2] & ram_mask_];
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::ReadC, pointer_[2], c_data_);
}
pointer_[2] += direction_;
return true;
case Channel::FlushPipeline:
@ -400,11 +430,20 @@ bool Blitter::advance_dma() {
busy_ = false;
if(write_phase_ == WritePhase::Full) {
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::WriteFromPipeline, write_address_, write_value_);
}
ram_[write_address_ & ram_mask_] = write_value_;
write_phase_ = WritePhase::Starting;
}
return true;
case Channel::None: return false;
case Channel::None:
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::SkippedSlot);
}
return false;
case Channel::Write: break;
}
@ -458,6 +497,9 @@ bool Blitter::advance_dma() {
switch(write_phase_) {
case WritePhase::Full:
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::WriteFromPipeline, write_address_, write_value_);
}
ram_[write_address_ & ram_mask_] = write_value_;
[[fallthrough]];
@ -465,6 +507,10 @@ bool Blitter::advance_dma() {
write_phase_ = WritePhase::Full;
write_address_ = pointer_[3];
write_value_ = output;
if constexpr (record_bus) {
transactions_.emplace_back(Transaction::Type::AddToPipeline, write_address_, write_value_);
}
pointer_[3] += direction_;
return true;
@ -477,3 +523,13 @@ bool Blitter::advance_dma() {
return true;
}
template <bool record_bus>
std::vector<typename Blitter<record_bus>::Transaction> Blitter<record_bus>::get_and_reset_transactions() {
std::vector<Transaction> result;
std::swap(result, transactions_);
return result;
}
template class Amiga::Blitter<false>;
template class Amiga::Blitter<true>;

View File

@ -11,6 +11,7 @@
#include <cstddef>
#include <cstdint>
#include <vector>
#include "../../ClockReceiver/ClockReceiver.hpp"
#include "DMADevice.hpp"
@ -166,7 +167,11 @@ class BlitterSequencer {
Phase next_phase_ = Phase::Complete;
};
class Blitter: public DMADevice<4, 4> {
/*!
If @c record_bus is @c true then all bus interactions will be recorded
and can subsequently be retrieved. This is included for testing purposes.
*/
template <bool record_bus = false> class Blitter: public DMADevice<4, 4> {
public:
using DMADevice::DMADevice;
@ -188,6 +193,24 @@ class Blitter: public DMADevice<4, 4> {
bool advance_dma();
struct Transaction {
enum class Type {
SkippedSlot,
ReadA,
ReadB,
ReadC,
AddToPipeline,
WriteFromPipeline
} type;
uint32_t address = 0;
uint16_t value = 0;
Transaction(Type type) : type(type) {}
Transaction(Type type, uint32_t address, uint16_t value) : type(type), address(address), value(value) {}
};
std::vector<Transaction> get_and_reset_transactions();
private:
int width_ = 0, height_ = 0;
int shifts_[2]{};
@ -221,6 +244,7 @@ class Blitter: public DMADevice<4, 4> {
int loop_index_ = -1;
void add_modulos();
std::vector<Transaction> transactions_;
};
}

View File

@ -139,7 +139,7 @@ class Chipset: private ClockingHint::Observer {
// MARK: - DMA Control, Scheduler and Blitter.
uint16_t dma_control_ = 0;
Blitter blitter_;
Blitter<false> blitter_;
// MARK: - Sprites and collision flags.