2019-10-07 03:14:05 +00:00
|
|
|
//
|
|
|
|
// MFP68901.hpp
|
|
|
|
// Clock Signal
|
|
|
|
//
|
|
|
|
// Created by Thomas Harte on 06/10/2019.
|
|
|
|
// Copyright © 2019 Thomas Harte. All rights reserved.
|
|
|
|
//
|
|
|
|
|
|
|
|
#ifndef MFP68901_hpp
|
|
|
|
#define MFP68901_hpp
|
|
|
|
|
|
|
|
#include <cstdint>
|
|
|
|
#include "../../ClockReceiver/ClockReceiver.hpp"
|
2019-10-31 02:42:06 +00:00
|
|
|
#include "../../ClockReceiver/ClockingHintSource.hpp"
|
2019-10-07 03:14:05 +00:00
|
|
|
|
|
|
|
namespace Motorola {
|
|
|
|
namespace MFP68901 {
|
|
|
|
|
2019-10-17 03:21:25 +00:00
|
|
|
class PortHandler {
|
|
|
|
public:
|
2019-10-22 03:02:30 +00:00
|
|
|
// TODO: announce changes in output.
|
2019-10-17 03:21:25 +00:00
|
|
|
};
|
|
|
|
|
2019-10-31 02:42:06 +00:00
|
|
|
class MFP68901: public ClockingHint::Source {
|
2019-10-07 03:14:05 +00:00
|
|
|
public:
|
|
|
|
uint8_t read(int address);
|
|
|
|
void write(int address, uint8_t value);
|
|
|
|
|
|
|
|
void run_for(HalfCycles);
|
|
|
|
HalfCycles get_next_sequence_point();
|
2019-10-08 02:44:35 +00:00
|
|
|
|
2019-10-10 03:01:11 +00:00
|
|
|
void set_timer_event_input(int channel, bool value);
|
|
|
|
|
2019-10-17 03:21:25 +00:00
|
|
|
void set_port_handler(PortHandler *);
|
|
|
|
void set_port_input(uint8_t);
|
|
|
|
uint8_t get_port_output();
|
|
|
|
|
2019-10-25 02:33:42 +00:00
|
|
|
bool get_interrupt_line();
|
2019-10-31 23:57:36 +00:00
|
|
|
|
2019-11-01 01:00:05 +00:00
|
|
|
static const int NoAcknowledgement = 0x100;
|
2019-10-31 23:57:36 +00:00
|
|
|
int acknowledge_interrupt();
|
2019-10-26 02:36:01 +00:00
|
|
|
|
|
|
|
struct InterruptDelegate {
|
|
|
|
virtual void mfp68901_did_change_interrupt_status(MFP68901 *) = 0;
|
|
|
|
};
|
|
|
|
void set_interrupt_delegate(InterruptDelegate *delegate);
|
2019-10-25 02:33:42 +00:00
|
|
|
|
2019-10-31 02:42:06 +00:00
|
|
|
// ClockingHint::Source.
|
|
|
|
ClockingHint::Preference preferred_clocking() final;
|
|
|
|
|
2019-10-08 02:44:35 +00:00
|
|
|
private:
|
|
|
|
// MARK: - Timers
|
|
|
|
enum class TimerMode {
|
|
|
|
Stopped, EventCount, Delay, PulseWidth
|
|
|
|
};
|
|
|
|
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);
|
2019-10-31 02:42:06 +00:00
|
|
|
void decrement_timer(int timer, int amount);
|
2019-10-08 02:44:35 +00:00
|
|
|
|
|
|
|
struct Timer {
|
|
|
|
TimerMode mode = TimerMode::Stopped;
|
|
|
|
uint8_t value = 0;
|
|
|
|
uint8_t reload_value = 0;
|
|
|
|
int prescale = 1;
|
2019-10-27 03:20:13 +00:00
|
|
|
int divisor = 1;
|
2019-10-10 03:01:11 +00:00
|
|
|
bool event_input = false;
|
2019-10-08 02:44:35 +00:00
|
|
|
} timers_[4];
|
2019-10-28 02:38:49 +00:00
|
|
|
uint8_t timer_ab_control_[2] = { 0, 0 };
|
|
|
|
uint8_t timer_cd_control_ = 0;
|
2019-10-08 02:44:35 +00:00
|
|
|
|
|
|
|
HalfCycles cycles_left_;
|
2019-10-22 03:02:30 +00:00
|
|
|
|
|
|
|
// MARK: - GPIP
|
|
|
|
uint8_t gpip_input_ = 0;
|
|
|
|
uint8_t gpip_output_ = 0;
|
|
|
|
uint8_t gpip_active_edge_ = 0;
|
|
|
|
uint8_t gpip_direction_ = 0;
|
|
|
|
uint8_t gpip_interrupt_state_ = 0;
|
|
|
|
|
|
|
|
void reevaluate_gpip_interrupts();
|
2019-10-24 03:09:49 +00:00
|
|
|
|
|
|
|
// MARK: - Interrupts
|
|
|
|
|
2019-10-26 02:36:01 +00:00
|
|
|
InterruptDelegate *interrupt_delegate_ = nullptr;
|
|
|
|
|
2019-10-26 19:55:19 +00:00
|
|
|
// Ad hoc documentation:
|
2019-10-24 03:09:49 +00:00
|
|
|
//
|
2019-10-26 19:55:19 +00:00
|
|
|
// An interrupt becomes pending if it is enabled at the time it occurs.
|
2019-10-24 03:09:49 +00:00
|
|
|
//
|
2019-10-26 19:55:19 +00:00
|
|
|
// If a pending interrupt is enabled in the interrupt mask, a processor
|
|
|
|
// interrupt is generated. Otherwise no processor interrupt is generated.
|
2019-10-24 03:09:49 +00:00
|
|
|
//
|
2019-10-26 19:55:19 +00:00
|
|
|
// (Disabling a bit in the enabled mask also instantaneously clears anything
|
|
|
|
// in the pending mask.)
|
|
|
|
//
|
|
|
|
// The user can write to the pending interrupt register; a write
|
|
|
|
// masks whatever is there — so you can disable bits but you cannot set them.
|
|
|
|
//
|
|
|
|
// If the vector register's 'S' bit is set then software end-of-interrupt mode applies:
|
|
|
|
// Acknowledgement of an interrupt clears that interrupt's pending bit, but also sets
|
|
|
|
// its in-service bit. That bit will remain set until the user writes a zero to its position.
|
|
|
|
// If any bits are set in the in-service register, then they will prevent lower-priority
|
|
|
|
// interrupts from being signalled to the CPU. Further interrupts of the same or a higher
|
|
|
|
// priority may occur.
|
|
|
|
//
|
|
|
|
// If the vector register's 'S' bit is clear then automatic end-of-interrupt mode applies:
|
|
|
|
// Acknowledgement of an interrupt will automatically clear the corresponding
|
|
|
|
// pending bit.
|
2019-10-24 03:09:49 +00:00
|
|
|
//
|
2019-10-25 02:33:42 +00:00
|
|
|
int interrupt_enable_ = 0;
|
|
|
|
int interrupt_pending_ = 0;
|
|
|
|
int interrupt_mask_ = 0;
|
2019-10-26 19:55:19 +00:00
|
|
|
int interrupt_in_service_ = 0;
|
2019-10-25 02:33:42 +00:00
|
|
|
bool interrupt_line_ = false;
|
2019-10-26 02:36:01 +00:00
|
|
|
uint8_t interrupt_vector_ = 0;
|
2019-10-24 03:09:49 +00:00
|
|
|
|
|
|
|
enum Interrupt {
|
2019-10-25 02:33:42 +00:00
|
|
|
GPIP0 = (1 << 0),
|
|
|
|
GPIP1 = (1 << 1),
|
|
|
|
GPIP2 = (1 << 2),
|
|
|
|
GPIP3 = (1 << 3),
|
|
|
|
TimerD = (1 << 4),
|
|
|
|
TimerC = (1 << 5),
|
|
|
|
GPIP4 = (1 << 6),
|
|
|
|
GPIP5 = (1 << 7),
|
|
|
|
|
|
|
|
TimerB = (1 << 8),
|
|
|
|
TransmitError = (1 << 9),
|
|
|
|
TransmitBufferEmpty = (1 << 10),
|
|
|
|
ReceiveError = (1 << 11),
|
|
|
|
ReceiveBufferFull = (1 << 12),
|
|
|
|
TimerA = (1 << 13),
|
|
|
|
GPIP6 = (1 << 14),
|
|
|
|
GPIP7 = (1 << 15),
|
2019-10-24 03:09:49 +00:00
|
|
|
};
|
2019-10-25 02:33:42 +00:00
|
|
|
void begin_interrupts(int interrupt);
|
|
|
|
void end_interrupts(int interrupt);
|
|
|
|
void update_interrupts();
|
2019-10-07 03:14:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* MFP68901_hpp */
|