1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-12-12 08:30:05 +00:00
CLK/Components/8255/i8255.hpp

93 lines
2.3 KiB
C++
Raw Normal View History

//
// i8255.hpp
// Clock Signal
//
// Created by Thomas Harte on 01/08/2017.
// Copyright 2017 Thomas Harte. All rights reserved.
//
#pragma once
#include <cstdint>
2023-05-10 21:02:18 +00:00
namespace Intel::i8255 {
class PortHandler {
2024-11-30 03:43:54 +00:00
public:
void set_value([[maybe_unused]] int port, [[maybe_unused]] uint8_t value) {}
uint8_t get_value([[maybe_unused]] int port) { return 0xff; }
};
2017-08-08 11:44:46 +00:00
// TODO: Modes 1 and 2.
template <class T> class i8255 {
2024-11-30 03:43:54 +00:00
public:
i8255(T &port_handler) : control_(0), outputs_{0, 0, 0}, port_handler_(port_handler) {}
2024-11-30 03:43:54 +00:00
/*!
Stores the value @c value to the register at @c address. If this causes a change in 8255 output
then the PortHandler will be informed.
*/
void write(const int address, const uint8_t value) {
switch(address & 3) {
case 0:
if(!(control_ & 0x10)) {
// TODO: so what would output be when switching from input to output mode?
outputs_[0] = value; port_handler_.set_value(0, value);
}
break;
case 1:
if(!(control_ & 0x02)) {
outputs_[1] = value; port_handler_.set_value(1, value);
}
break;
case 2: outputs_[2] = value; port_handler_.set_value(2, value); break;
case 3:
if(value & 0x80) {
control_ = value;
} else {
if(value & 1) {
outputs_[2] |= 1 << ((value >> 1)&7);
} else {
2024-11-30 03:43:54 +00:00
outputs_[2] &= ~(1 << ((value >> 1)&7));
}
2024-11-30 03:43:54 +00:00
}
update_outputs();
break;
}
2024-11-30 03:43:54 +00:00
}
2024-11-30 03:43:54 +00:00
/*!
Obtains the current value for the register at @c address. If this provides a reading
of input then the PortHandler will be queried.
*/
uint8_t read(const int address) {
switch(address & 3) {
case 0: return (control_ & 0x10) ? port_handler_.get_value(0) : outputs_[0];
case 1: return (control_ & 0x02) ? port_handler_.get_value(1) : outputs_[1];
case 2: {
if(!(control_ & 0x09)) return outputs_[2];
uint8_t input = port_handler_.get_value(2);
return ((control_ & 0x01) ?
(input & 0x0f) :
(outputs_[2] & 0x0f)) | ((control_ & 0x08) ?
(input & 0xf0) : (outputs_[2] & 0xf0));
}
2024-11-30 03:43:54 +00:00
case 3: return control_;
}
2024-11-30 03:43:54 +00:00
return 0xff;
}
2024-11-30 03:43:54 +00:00
private:
void update_outputs() {
if(!(control_ & 0x10)) port_handler_.set_value(0, outputs_[0]);
if(!(control_ & 0x02)) port_handler_.set_value(1, outputs_[1]);
port_handler_.set_value(2, outputs_[2]);
}
2024-11-30 03:43:54 +00:00
uint8_t control_;
uint8_t outputs_[3];
T &port_handler_;
};
}