1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-28 07:29:45 +00:00

Adds enough logic to advance to an ACIA access error.

This commit is contained in:
Thomas Harte 2019-10-09 23:01:11 -04:00
parent 42ebe06474
commit 127bb043e7
5 changed files with 92 additions and 10 deletions

View File

@ -123,11 +123,7 @@ void MFP68901::run_for(HalfCycles time) {
--timers_[c].divisor;
if(!timers_[c].divisor) {
timers_[c].divisor = timers_[c].prescale;
--timers_[c].value;
if(!timers_[c].value) {
// TODO: interrupt.
}
decrement_timer(c);
}
}
}
@ -159,3 +155,19 @@ void MFP68901::set_timer_data(int timer, uint8_t value) {
uint8_t MFP68901::get_timer_data(int timer) {
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 Channels edge bit"? */
decrement_timer(channel);
}
}
void MFP68901::decrement_timer(int timer) {
--timers_[timer].value;
if(!timers_[timer].value) {
// TODO: interrupt. Reload, possibly.
}
}

View File

@ -23,6 +23,8 @@ class MFP68901 {
void run_for(HalfCycles);
HalfCycles get_next_sequence_point();
void set_timer_event_input(int channel, bool value);
private:
// MARK: - Timers
enum class TimerMode {
@ -31,6 +33,7 @@ class MFP68901 {
void set_timer_mode(int timer, TimerMode, int prescale, bool reset_timer);
void set_timer_data(int timer, uint8_t);
uint8_t get_timer_data(int timer);
void decrement_timer(int timer);
struct Timer {
TimerMode mode = TimerMode::Stopped;
@ -38,6 +41,7 @@ class MFP68901 {
uint8_t reload_value = 0;
int prescale = 1;
int divisor = 0;
bool event_input = false;
} timers_[4];
HalfCycles cycles_left_;

View File

@ -115,6 +115,8 @@ class ConcreteMachine:
address %= rom_.size();
break;
case BusDevice::Unassigned:
// TODO: figure out the rules about bus errors.
case BusDevice::Cartridge:
/*
TOS 1.0 appears to attempt to read from the catridge before it has setup
@ -131,10 +133,6 @@ class ConcreteMachine:
}
return HalfCycles(0);
case BusDevice::Unassigned:
assert(false);
return HalfCycles(0);
case BusDevice::IO:
switch(address) {
default:
@ -236,6 +234,39 @@ class ConcreteMachine:
GPIP 0: centronics busy
*/
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);
}
@ -281,6 +312,8 @@ class ConcreteMachine:
cycles_until_video_event_ = video_->get_next_sequence_point();
// 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;
video_ += length;

View File

@ -8,6 +8,8 @@
#include "Video.hpp"
#include "../../Outputs/Log.hpp"
#include <algorithm>
using namespace Atari::ST;
@ -66,6 +68,9 @@ void Video::run_for(HalfCycles duration) {
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) {
const int final_x = std::min(x + integer_duration, mode_params.line_length);
integer_duration -= (final_x - x);
@ -117,7 +122,7 @@ void Video::run_for(HalfCycles duration) {
void Video::output_border(int duration) {
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);
}
@ -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;
}
}
// 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;
}
}

View File

@ -39,9 +39,14 @@ class Video {
bool vsync();
bool display_enabled();
uint8_t read(int address);
void write(int address, uint8_t value);
private:
Outputs::CRT::CRT crt_;
uint16_t palette_[16];
int x = 0, y = 0;
void output_border(int duration);
};