mirror of
https://github.com/TomHarte/CLK.git
synced 2025-01-14 13:33:42 +00:00
Adds enough logic to advance to an ACIA access error.
This commit is contained in:
parent
42ebe06474
commit
127bb043e7
@ -123,11 +123,7 @@ void MFP68901::run_for(HalfCycles time) {
|
|||||||
--timers_[c].divisor;
|
--timers_[c].divisor;
|
||||||
if(!timers_[c].divisor) {
|
if(!timers_[c].divisor) {
|
||||||
timers_[c].divisor = timers_[c].prescale;
|
timers_[c].divisor = timers_[c].prescale;
|
||||||
|
decrement_timer(c);
|
||||||
--timers_[c].value;
|
|
||||||
if(!timers_[c].value) {
|
|
||||||
// TODO: interrupt.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -159,3 +155,19 @@ void MFP68901::set_timer_data(int timer, uint8_t value) {
|
|||||||
uint8_t MFP68901::get_timer_data(int timer) {
|
uint8_t MFP68901::get_timer_data(int timer) {
|
||||||
return timers_[timer].value;
|
return timers_[timer].value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MFP68901::set_timer_event_input(int channel, bool value) {
|
||||||
|
if(timers_[channel].event_input == value) return;
|
||||||
|
|
||||||
|
timers_[channel].event_input = value;
|
||||||
|
if(timers_[channel].mode == TimerMode::EventCount && !value) { /* TODO: which edge is counted? "as defined by the associated Interrupt Channel’s edge bit"? */
|
||||||
|
decrement_timer(channel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void MFP68901::decrement_timer(int timer) {
|
||||||
|
--timers_[timer].value;
|
||||||
|
if(!timers_[timer].value) {
|
||||||
|
// TODO: interrupt. Reload, possibly.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -23,6 +23,8 @@ class MFP68901 {
|
|||||||
void run_for(HalfCycles);
|
void run_for(HalfCycles);
|
||||||
HalfCycles get_next_sequence_point();
|
HalfCycles get_next_sequence_point();
|
||||||
|
|
||||||
|
void set_timer_event_input(int channel, bool value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MARK: - Timers
|
// MARK: - Timers
|
||||||
enum class TimerMode {
|
enum class TimerMode {
|
||||||
@ -31,6 +33,7 @@ class MFP68901 {
|
|||||||
void set_timer_mode(int timer, TimerMode, int prescale, bool reset_timer);
|
void set_timer_mode(int timer, TimerMode, int prescale, bool reset_timer);
|
||||||
void set_timer_data(int timer, uint8_t);
|
void set_timer_data(int timer, uint8_t);
|
||||||
uint8_t get_timer_data(int timer);
|
uint8_t get_timer_data(int timer);
|
||||||
|
void decrement_timer(int timer);
|
||||||
|
|
||||||
struct Timer {
|
struct Timer {
|
||||||
TimerMode mode = TimerMode::Stopped;
|
TimerMode mode = TimerMode::Stopped;
|
||||||
@ -38,6 +41,7 @@ class MFP68901 {
|
|||||||
uint8_t reload_value = 0;
|
uint8_t reload_value = 0;
|
||||||
int prescale = 1;
|
int prescale = 1;
|
||||||
int divisor = 0;
|
int divisor = 0;
|
||||||
|
bool event_input = false;
|
||||||
} timers_[4];
|
} timers_[4];
|
||||||
|
|
||||||
HalfCycles cycles_left_;
|
HalfCycles cycles_left_;
|
||||||
|
@ -115,6 +115,8 @@ class ConcreteMachine:
|
|||||||
address %= rom_.size();
|
address %= rom_.size();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case BusDevice::Unassigned:
|
||||||
|
// TODO: figure out the rules about bus errors.
|
||||||
case BusDevice::Cartridge:
|
case BusDevice::Cartridge:
|
||||||
/*
|
/*
|
||||||
TOS 1.0 appears to attempt to read from the catridge before it has setup
|
TOS 1.0 appears to attempt to read from the catridge before it has setup
|
||||||
@ -131,10 +133,6 @@ class ConcreteMachine:
|
|||||||
}
|
}
|
||||||
return HalfCycles(0);
|
return HalfCycles(0);
|
||||||
|
|
||||||
case BusDevice::Unassigned:
|
|
||||||
assert(false);
|
|
||||||
return HalfCycles(0);
|
|
||||||
|
|
||||||
case BusDevice::IO:
|
case BusDevice::IO:
|
||||||
switch(address) {
|
switch(address) {
|
||||||
default:
|
default:
|
||||||
@ -236,6 +234,39 @@ class ConcreteMachine:
|
|||||||
GPIP 0: centronics busy
|
GPIP 0: centronics busy
|
||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Video controls.
|
||||||
|
case 0x7fc100: case 0x7fc101: case 0x7fc102: case 0x7fc103:
|
||||||
|
case 0x7fc104: case 0x7fc105: case 0x7fc106: case 0x7fc107:
|
||||||
|
case 0x7fc108: case 0x7fc109: case 0x7fc10a: case 0x7fc10b:
|
||||||
|
case 0x7fc10c: case 0x7fc10d: case 0x7fc10e: case 0x7fc10f:
|
||||||
|
case 0x7fc110: case 0x7fc111: case 0x7fc112: case 0x7fc113:
|
||||||
|
case 0x7fc114: case 0x7fc115: case 0x7fc116: case 0x7fc117:
|
||||||
|
case 0x7fc118: case 0x7fc119: case 0x7fc11a: case 0x7fc11b:
|
||||||
|
case 0x7fc11c: case 0x7fc11d: case 0x7fc11e: case 0x7fc11f:
|
||||||
|
case 0x7fc120: case 0x7fc121: case 0x7fc122: case 0x7fc123:
|
||||||
|
case 0x7fc124: case 0x7fc125: case 0x7fc126: case 0x7fc127:
|
||||||
|
case 0x7fc128: case 0x7fc129: case 0x7fc12a: case 0x7fc12b:
|
||||||
|
case 0x7fc12c: case 0x7fc12d: case 0x7fc12e: case 0x7fc12f:
|
||||||
|
case 0x7fc130: case 0x7fc131:
|
||||||
|
if(!cycle.data_select_active()) return HalfCycles(0);
|
||||||
|
|
||||||
|
if(cycle.operation & Microcycle::Read) {
|
||||||
|
const uint8_t value = video_->read(int(address));
|
||||||
|
if(cycle.operation & Microcycle::SelectByte) {
|
||||||
|
cycle.value->halves.low = value;
|
||||||
|
} else {
|
||||||
|
cycle.value->halves.high = value;
|
||||||
|
cycle.value->halves.low = 0xff;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if(cycle.operation & Microcycle::SelectByte) {
|
||||||
|
video_->write(int(address), cycle.value->halves.low);
|
||||||
|
} else {
|
||||||
|
video_->write(int(address), cycle.value->halves.high);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
return HalfCycles(0);
|
return HalfCycles(0);
|
||||||
}
|
}
|
||||||
@ -281,6 +312,8 @@ class ConcreteMachine:
|
|||||||
cycles_until_video_event_ = video_->get_next_sequence_point();
|
cycles_until_video_event_ = video_->get_next_sequence_point();
|
||||||
|
|
||||||
// TODO: push v/hsync/display_enable elsewhere.
|
// TODO: push v/hsync/display_enable elsewhere.
|
||||||
|
mfp_->set_timer_event_input(1, video_->display_enabled());
|
||||||
|
// printf("%c%c%c\n", video_->display_enabled() ? 'e' : '-', video_->hsync() ? 'h' : '-', video_->vsync() ? 'v' : '-');
|
||||||
}
|
}
|
||||||
cycles_until_video_event_ -= length;
|
cycles_until_video_event_ -= length;
|
||||||
video_ += length;
|
video_ += length;
|
||||||
|
@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
#include "Video.hpp"
|
#include "Video.hpp"
|
||||||
|
|
||||||
|
#include "../../Outputs/Log.hpp"
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
using namespace Atari::ST;
|
using namespace Atari::ST;
|
||||||
@ -66,6 +68,9 @@ void Video::run_for(HalfCycles duration) {
|
|||||||
x = target; \
|
x = target; \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: the below is **way off**. The real hardware does what you'd expect with ongoing state and
|
||||||
|
// exact equality tests. Fixes to come.
|
||||||
|
|
||||||
while(integer_duration) {
|
while(integer_duration) {
|
||||||
const int final_x = std::min(x + integer_duration, mode_params.line_length);
|
const int final_x = std::min(x + integer_duration, mode_params.line_length);
|
||||||
integer_duration -= (final_x - x);
|
integer_duration -= (final_x - x);
|
||||||
@ -117,7 +122,7 @@ void Video::run_for(HalfCycles duration) {
|
|||||||
|
|
||||||
void Video::output_border(int duration) {
|
void Video::output_border(int duration) {
|
||||||
uint16_t *colour_pointer = reinterpret_cast<uint16_t *>(crt_.begin_data(1));
|
uint16_t *colour_pointer = reinterpret_cast<uint16_t *>(crt_.begin_data(1));
|
||||||
if(colour_pointer) *colour_pointer = 0x333;
|
if(colour_pointer) *colour_pointer = palette_[0];
|
||||||
crt_.output_level(duration);
|
crt_.output_level(duration);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -178,3 +183,26 @@ HalfCycles Video::get_next_sequence_point() {
|
|||||||
return (cycles_until_vsync < cycles_until_display_enable) ? cycles_until_vsync : cycles_until_display_enable;
|
return (cycles_until_vsync < cycles_until_display_enable) ? cycles_until_vsync : cycles_until_display_enable;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: - IO dispatch
|
||||||
|
|
||||||
|
uint8_t Video::read(int address) {
|
||||||
|
LOG("[Video] read " << (address & 0x3f));
|
||||||
|
return 0xff;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Video::write(int address, uint8_t value) {
|
||||||
|
LOG("[Video] write " << PADHEX(2) << int(value) << " to " << PADHEX(2) << (address & 0x3f));
|
||||||
|
address &= 0x3f;
|
||||||
|
switch(address) {
|
||||||
|
default: break;
|
||||||
|
|
||||||
|
// Palette.
|
||||||
|
case 0x20: case 0x21: case 0x22: case 0x23:
|
||||||
|
case 0x24: case 0x25: case 0x26: case 0x27:
|
||||||
|
case 0x28: case 0x29: case 0x2a: case 0x2b:
|
||||||
|
case 0x2c: case 0x2d: case 0x2e: case 0x2f:
|
||||||
|
palette_[address - 0x20] = uint16_t((value & 0x777) << 5);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -39,9 +39,14 @@ class Video {
|
|||||||
bool vsync();
|
bool vsync();
|
||||||
bool display_enabled();
|
bool display_enabled();
|
||||||
|
|
||||||
|
uint8_t read(int address);
|
||||||
|
void write(int address, uint8_t value);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Outputs::CRT::CRT crt_;
|
Outputs::CRT::CRT crt_;
|
||||||
|
|
||||||
|
uint16_t palette_[16];
|
||||||
|
|
||||||
int x = 0, y = 0;
|
int x = 0, y = 0;
|
||||||
void output_border(int duration);
|
void output_border(int duration);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user