mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-26 23:52:26 +00:00
Take a shot at LMMC.
This commit is contained in:
parent
975ead5d01
commit
d3c446d91b
@ -852,6 +852,15 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
|
|||||||
|
|
||||||
case 44:
|
case 44:
|
||||||
Storage<personality>::command_context_.colour = value;
|
Storage<personality>::command_context_.colour = value;
|
||||||
|
|
||||||
|
// Check whether a command was blocked on this.
|
||||||
|
if(
|
||||||
|
Storage<personality>::command_ &&
|
||||||
|
Storage<personality>::command_->access == Command::AccessType::WaitForColour
|
||||||
|
) {
|
||||||
|
Storage<personality>::command_->advance();
|
||||||
|
Storage<personality>::update_command_step(fetch_pointer_.column);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 45:
|
case 45:
|
||||||
@ -884,14 +893,14 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
|
|||||||
default: break;
|
default: break;
|
||||||
|
|
||||||
case 0b0100: break; // TODO: point. [read a pixel colour]
|
case 0b0100: break; // TODO: point. [read a pixel colour]
|
||||||
case 0b0101: Begin(PointSet); break;
|
case 0b0101: Begin(PointSet); break; // PSET
|
||||||
case 0b0110: break; // TODO: srch. [search horizontally for a colour]
|
case 0b0110: break; // TODO: srch. [search horizontally for a colour]
|
||||||
case 0b0111: Begin(Line); break;
|
case 0b0111: Begin(Line); break; // LINE
|
||||||
|
|
||||||
case 0b1000: break; // TODO: lmmv. [logical move, VDP to VRAM]
|
case 0b1000: break; // TODO: lmmv. [logical move, VDP to VRAM]
|
||||||
case 0b1001: break; // TODO: lmmm. [logical move, VRAM to VRAM]
|
case 0b1001: break; // TODO: lmmm. [logical move, VRAM to VRAM]
|
||||||
case 0b1010: break; // TODO: lmcm. [logical move, VRAM to CPU]
|
case 0b1010: break; // TODO: lmcm. [logical move, VRAM to CPU]
|
||||||
case 0b1011: break; // TODO: lmmc. [logical move, CPU to VRAM]
|
case 0b1011: Begin(LogicalMoveFromCPU); break; // LMMC [logical move, CPU to VRAM]
|
||||||
|
|
||||||
case 0b1100: break; // TODO: hmmv. [high-speed move, VRAM to VDP]
|
case 0b1100: break; // TODO: hmmv. [high-speed move, VRAM to VDP]
|
||||||
case 0b1101: break; // TODO: hmmm. [high-speed move, VRAM to VRAM]
|
case 0b1101: break; // TODO: hmmm. [high-speed move, VRAM to VRAM]
|
||||||
@ -900,12 +909,15 @@ void Base<personality>::commit_register(int reg, uint8_t value) {
|
|||||||
}
|
}
|
||||||
#undef Begin
|
#undef Begin
|
||||||
|
|
||||||
// Seed timing information if a command was found.
|
// Kill the command immediately if it's done in zero operations
|
||||||
Storage<personality>::update_command_step(fetch_pointer_.column);
|
// (e.g. a line of length 0).
|
||||||
|
|
||||||
if(!Storage<personality>::command_) {
|
if(!Storage<personality>::command_) {
|
||||||
LOG("TODO: Yamaha command " << PADHEX(2) << +value);
|
LOG("TODO: Yamaha command " << PADHEX(2) << +value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Seed timing information if a command was found.
|
||||||
|
Storage<personality>::update_command_step(fetch_pointer_.column);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1003,20 +1015,30 @@ uint8_t Base<personality>::read_register() {
|
|||||||
switch(Storage<personality>::selected_status_) {
|
switch(Storage<personality>::selected_status_) {
|
||||||
case 0: break;
|
case 0: break;
|
||||||
|
|
||||||
case 2:
|
case 1:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2: {
|
||||||
// b7 = transfer ready flag (i.e. VDP ready for next transfer)
|
// b7 = transfer ready flag (i.e. VDP ready for next transfer)
|
||||||
// b6 = 1 during vblank
|
// b6 = 1 during vblank
|
||||||
// b5 = 1 during hblank
|
// b5 = 1 during hblank
|
||||||
// b4 = set if colour detected during search command
|
// b4 = set if colour detected during search command
|
||||||
// b1 = display field odd/even
|
// b1 = display field odd/even
|
||||||
// b0 = command ongoing
|
// b0 = command ongoing
|
||||||
|
const uint8_t transfer_ready =
|
||||||
|
(queued_access_ == MemoryAccess::None ? 0x80 : 0x00) &
|
||||||
|
((
|
||||||
|
!Storage<personality>::command_ ||
|
||||||
|
Storage<personality>::command_->access != Command::AccessType::WaitForColour
|
||||||
|
) ? 0x80 : 0x00);
|
||||||
|
|
||||||
return
|
return
|
||||||
(queued_access_ == MemoryAccess::None ? 0x80 : 0x00) |
|
transfer_ready |
|
||||||
(is_vertical_blank() ? 0x40 : 0x00) |
|
(is_vertical_blank() ? 0x40 : 0x00) |
|
||||||
(is_horizontal_blank() ? 0x20 : 0x00) |
|
(is_horizontal_blank() ? 0x20 : 0x00) |
|
||||||
(Storage<personality>::command_ ? 0x01 : 0x00);
|
(Storage<personality>::command_ ? 0x01 : 0x00);
|
||||||
|
|
||||||
break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,12 +201,21 @@ template <Personality personality> struct Storage<personality, std::enable_if_t<
|
|||||||
next_command_step_ = CommandStep::None;
|
next_command_step_ = CommandStep::None;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if(command_->done()) {
|
||||||
|
command_ = nullptr;
|
||||||
|
next_command_step_ = CommandStep::None;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
minimum_command_column_ = current_column + command_->cycles;
|
minimum_command_column_ = current_column + command_->cycles;
|
||||||
switch(command_->access) {
|
switch(command_->access) {
|
||||||
case Command::AccessType::PlotPoint:
|
case Command::AccessType::PlotPoint:
|
||||||
next_command_step_ = CommandStep::ReadPixel;
|
next_command_step_ = CommandStep::ReadPixel;
|
||||||
break;
|
break;
|
||||||
|
case Command::AccessType::WaitForColour:
|
||||||
|
// i.e. nothing to do until a colour is received.
|
||||||
|
next_command_step_ = CommandStep::None;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -59,7 +59,10 @@ struct Command {
|
|||||||
enum class AccessType {
|
enum class AccessType {
|
||||||
/// Plots a single pixel of the current contextual colour at @c location,
|
/// Plots a single pixel of the current contextual colour at @c location,
|
||||||
/// which occurs as a read, then a 24-cycle pause, then a write.
|
/// which occurs as a read, then a 24-cycle pause, then a write.
|
||||||
PlotPoint
|
PlotPoint,
|
||||||
|
|
||||||
|
/// Blocks until the next CPU write to the colour register.
|
||||||
|
WaitForColour,
|
||||||
};
|
};
|
||||||
AccessType access = AccessType::PlotPoint;
|
AccessType access = AccessType::PlotPoint;
|
||||||
int cycles = 0;
|
int cycles = 0;
|
||||||
@ -165,6 +168,52 @@ struct PointSet: public Command {
|
|||||||
bool done_ = false;
|
bool done_ = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LogicalMoveFromCPU: public Command {
|
||||||
|
public:
|
||||||
|
LogicalMoveFromCPU(CommandContext &context) : Command(context) {
|
||||||
|
start_x_ = context.destination.v[0];
|
||||||
|
width_ = context.size.v[0];
|
||||||
|
|
||||||
|
cycles = 64;
|
||||||
|
access = AccessType::WaitForColour;
|
||||||
|
}
|
||||||
|
|
||||||
|
void advance() final {
|
||||||
|
switch(access) {
|
||||||
|
default: break;
|
||||||
|
|
||||||
|
case AccessType::WaitForColour:
|
||||||
|
cycles = 32;
|
||||||
|
location = context.destination;
|
||||||
|
access = AccessType::PlotPoint;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case AccessType::PlotPoint:
|
||||||
|
cycles = 0;
|
||||||
|
access = AccessType::WaitForColour;
|
||||||
|
++location.v[0];
|
||||||
|
--context.size.v[0];
|
||||||
|
|
||||||
|
if(!context.size.v[0]) {
|
||||||
|
cycles = 64;
|
||||||
|
++location.v[1];
|
||||||
|
--context.size.v[1];
|
||||||
|
|
||||||
|
context.size.v[0] = width_;
|
||||||
|
location.v[0] = start_x_;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool done() final {
|
||||||
|
return !context.size.v[1] || !width_;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
int start_x_ = 0, width_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user