mirror of
https://github.com/TomHarte/CLK.git
synced 2024-11-23 03:32:32 +00:00
Merge pull request #440 from TomHarte/VapourLock
Attempts to implement vapour lock bus behaviour.
This commit is contained in:
commit
3053acb4f3
@ -193,6 +193,23 @@ class ConcreteMachine:
|
|||||||
if(isReadOperation(operation)) *value = block->read_pointer[address];
|
if(isReadOperation(operation)) *value = block->read_pointer[address];
|
||||||
else if(block->write_pointer) block->write_pointer[address] = *value;
|
else if(block->write_pointer) block->write_pointer[address] = *value;
|
||||||
} else {
|
} else {
|
||||||
|
// Assume a vapour read unless it turns out otherwise; this is a little
|
||||||
|
// wasteful but works for now.
|
||||||
|
//
|
||||||
|
// Longer version: like many other machines, when the Apple II reads from
|
||||||
|
// an address at which no hardware loads the data bus, through a process of
|
||||||
|
// practical analogue effects it'll end up receiving whatever was last on
|
||||||
|
// the bus. Which will always be whatever the video circuit fetched because
|
||||||
|
// that fetches in between every instruction.
|
||||||
|
//
|
||||||
|
// So this code assumes that'll happen unless it later determines that it
|
||||||
|
// doesn't. The call into the video isn't free because it's a just-in-time
|
||||||
|
// actor, but this will actually be the result most of the time so it's not
|
||||||
|
// too terrible.
|
||||||
|
if(isReadOperation(operation) && address != 0xc000) {
|
||||||
|
*value = video_->get_last_read_value(cycles_since_video_update_);
|
||||||
|
}
|
||||||
|
|
||||||
switch(address) {
|
switch(address) {
|
||||||
default:
|
default:
|
||||||
if(isReadOperation(operation)) {
|
if(isReadOperation(operation)) {
|
||||||
|
@ -209,7 +209,56 @@ template <class BusHandler> class Video: public VideoBase {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
Obtains the last value the video read prior to time now+offset.
|
||||||
|
*/
|
||||||
|
uint8_t get_last_read_value(Cycles offset) {
|
||||||
|
// Rules of generation:
|
||||||
|
// (1) a complete sixty-five-cycle scan line consists of sixty-five consecutive bytes of
|
||||||
|
// display buffer memory that starts twenty-five bytes prior to the actual data to be displayed.
|
||||||
|
// (2) During VBL the data acts just as if it were starting a whole new frame from the beginning, but
|
||||||
|
// it never finishes this pseudo-frame. After getting one third of the way through the frame (to
|
||||||
|
// scan line $3F), it suddenly repeats the previous six scan lines ($3A through $3F) before aborting
|
||||||
|
// to begin the next true frame.
|
||||||
|
//
|
||||||
|
// Source: Have an Apple Split by Bob Bishop; http://rich12345.tripod.com/aiivideo/softalk.html
|
||||||
|
|
||||||
|
// Determine column at offset.
|
||||||
|
int mapped_column = column_ + offset.as_int();
|
||||||
|
|
||||||
|
// Map that backwards from the internal pixels-at-start generation to pixels-at-end
|
||||||
|
// (so what was column 0 is now column 25).
|
||||||
|
mapped_column += 25;
|
||||||
|
|
||||||
|
// Apply carry into the row counter.
|
||||||
|
int mapped_row = row_ + (mapped_column / 65);
|
||||||
|
mapped_column %= 65;
|
||||||
|
mapped_row %= 262;
|
||||||
|
|
||||||
|
// Apple out-of-bounds row logic.
|
||||||
|
if(mapped_row >= 256) {
|
||||||
|
mapped_row = 0x3a + (mapped_row&255);
|
||||||
|
} else {
|
||||||
|
mapped_row %= 192;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate the address and return the value.
|
||||||
|
uint16_t read_address = static_cast<uint16_t>(get_row_address(mapped_row) + mapped_column - 25);
|
||||||
|
return bus_handler_.perform_read(read_address);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
uint16_t get_row_address(int row) {
|
||||||
|
const int character_row = row >> 3;
|
||||||
|
const int pixel_row = row & 7;
|
||||||
|
const uint16_t row_address = static_cast<uint16_t>((character_row >> 3) * 40 + ((character_row&7) << 7));
|
||||||
|
|
||||||
|
GraphicsMode pixel_mode = ((!mixed_mode_ || row < 160) && use_graphics_mode_) ? graphics_mode_ : GraphicsMode::Text;
|
||||||
|
return (pixel_mode == GraphicsMode::HighRes) ?
|
||||||
|
static_cast<uint16_t>(((video_page_+1) * 0x2000) + row_address + ((pixel_row&7) << 10)) :
|
||||||
|
static_cast<uint16_t>(((video_page_+1) * 0x400) + row_address);
|
||||||
|
}
|
||||||
|
|
||||||
const int flash_length = 8406;
|
const int flash_length = 8406;
|
||||||
BusHandler &bus_handler_;
|
BusHandler &bus_handler_;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user