Created
January 20, 2018 08:10
-
-
Save dhouck/ecdeca32606815ef363a1a8389661cc9 to your computer and use it in GitHub Desktop.
Microcode for Ben Eater's breadboard computer at https://www.youtube.com/playlist?list=PLowKtXNTBypGqImE405J2565dvjafglHU
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstddef> | |
#include <array> | |
#include <stdexcept> | |
//// This would be a header file if Compiler Explorer supported those | |
//// You can skip to the comment "Instructions set definition here" | |
// Use put in a namespace to avoid poluting global namespace (Otherwise there are issues with multiple HLTs) | |
namespace ControlBitsNS { | |
enum ControlBits : uint16_t { | |
NONE = 0, | |
J = 1 << 1, | |
CO = 1 << 2, | |
CE = 1 << 3, | |
OI = 1 << 4, | |
BI = 1 << 5, | |
SU = 1 << 6, | |
EO = 1 << 7, | |
AO = 1 << 8, | |
AI = 1 << 9, | |
II = 1 << 10, | |
IO = 1 << 11, | |
RO = 1 << 12, | |
RI = 1 << 13, | |
MI = 1 << 14, | |
HLT = 1 << 15 | |
}; | |
// Make the bitwise operators return the right type | |
ControlBits constexpr operator|(ControlBits lhs, ControlBits rhs) { | |
return ControlBits(uint16_t(lhs) | uint16_t(rhs)); | |
} | |
ControlBits constexpr operator&(ControlBits lhs, ControlBits rhs) { | |
return ControlBits(uint16_t(lhs) & uint16_t(rhs)); | |
} | |
ControlBits constexpr operator~(ControlBits bits) { | |
return ControlBits(~ uint16_t(bits)); | |
} | |
} | |
using ControlBitsNS::ControlBits; | |
/// Verify that control bits are sensible | |
ControlBits constexpr verify(ControlBits uop) { | |
ControlBits output_ops = ControlBits::CO | ControlBits::EO | ControlBits::AO | |
| ControlBits::IO | ControlBits::RO; | |
ControlBits input_ops = ControlBits::J | ControlBits::OI | ControlBits::BI | |
| ControlBits::AI | ControlBits::II | ControlBits::RI | |
| ControlBits::MI; | |
if (__builtin_popcount(uint16_t(uop & output_ops)) > 1) { | |
throw std::invalid_argument("Contention on the bus"); | |
} | |
if ((uop & output_ops) && ! (uop & input_ops)) { | |
throw std::invalid_argument("Bus output not being read"); | |
} | |
if ((uop & input_ops) && ! (uop & output_ops)) { | |
throw std::invalid_argument("Reading floating bus input"); | |
} | |
// Note: We do not check that HLT is the only control bit if it's set | |
// You might want to halt in subtract mode or with soething on the bus. | |
return uop; | |
} | |
struct Microcode { | |
constexpr Microcode(ControlBits t2 = ControlBits::NONE, ControlBits t3 = ControlBits::NONE, | |
ControlBits t4 = ControlBits::NONE, ControlBits t5 = ControlBits::NONE, | |
ControlBits t6 = ControlBits::NONE, ControlBits t7 = ControlBits::NONE) | |
: uops{{verify(t2), verify(t3), verify(t4), verify(t5), verify(t6), verify(t7)}} {} | |
// Initialization microcode; same for every instruction | |
std::array<ControlBits, 2> init {{verify(ControlBits::MI | ControlBits::CO), | |
verify(ControlBits::II | ControlBits::RO | ControlBits::CE)}}; | |
std::array<ControlBits, 6> uops; | |
}; | |
static_assert(sizeof(Microcode) == 16, "Microcode object size incorrect"); | |
using InstructionSet = std::array<Microcode, 16>; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment