Skip to content

Instantly share code, notes, and snippets.

@teknoman117
Created January 22, 2022 23:16
Show Gist options
  • Save teknoman117/342b43db8b79652c1c91e78e0593f854 to your computer and use it in GitHub Desktop.
Save teknoman117/342b43db8b79652c1c91e78e0593f854 to your computer and use it in GitHub Desktop.
Pokes the bus of a Harris static core 80C286
/*
* Copyright (c) 2021 Nathaniel R. Lewis <github@nrlewis.dev>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of mosquitto nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#define CLK 5
#define N_ERROR 3
#define N_LOCK 10
#define HLDA 11
#define HOLD 12
#define RESET 13
#define INTR 14
#define NMI 15
#define N_READY 16
#define COD_N_INTA 17
#define M_N_IO 18
#define N_BHE 19
#define N_S0 20
#define N_S1 21
unsigned long previousStep = 0;
bool clkState = false;
bool intrState = false;
void clock_step() {
//unsigned long now = 0;
//while ((now = millis()) <= previousStep) {
// stall until clock time
//}
clkState = !clkState;
//previousStep = now;
digitalWrite(CLK, clkState);
}
void interrupt_toggle() {
intrState = !intrState;
digitalWrite(INTR, intrState);
if (intrState) {
Serial.println("assert interrupt");
} else {
Serial.println("deassert interrupt");
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(1000000);
Serial.setTimeout(600000);
// PORTL = D7:0
// PORTC = D15:8
DDRL = 0;
DDRC = 0;
// PORTF = A7:0
// PORTK = A15:8
// PORTA = A23:16
DDRF = 0;
DDRK = 0;
DDRA = 0;
// setup inputs
pinMode(COD_N_INTA, INPUT);
pinMode(M_N_IO, INPUT);
pinMode(N_BHE, INPUT);
pinMode(N_S0, INPUT);
pinMode(N_S1, INPUT);
pinMode(HLDA, INPUT);
pinMode(N_LOCK, INPUT);
// setup outputs
pinMode(CLK, OUTPUT);
pinMode(N_ERROR, OUTPUT);
pinMode(RESET, OUTPUT);
pinMode(INTR, OUTPUT);
pinMode(NMI, OUTPUT);
pinMode(N_READY, OUTPUT);
pinMode(HOLD, OUTPUT);
// output defaults
//digitalWrite(CLK, 0);
digitalWrite(N_ERROR, 1);
digitalWrite(RESET, 1); // chip is by default held in reset
digitalWrite(INTR, 0);
digitalWrite(NMI, 0);
digitalWrite(N_READY, 1); // bus controller by default doesn't assert ready
digitalWrite(HOLD, 0);
// setup timer (16 MHz / 8 = 2 MHz output (4 clocks high, 4 clocks low))
//DDRE |= _BV(3);
//TCCR3A = _BV(COM3A0);
//TCCR3B = _BV(WGM32) | _BV(CS30);
//OCR3A = 1;
// chip needs some clocks with reset asserted to actually be reset
for (int i = 0; i < 1000; i++) {
clock_step();
}
digitalWrite(RESET, 0);
}
enum class BusCycle {
InterruptAcknowledge,
Halt,
Shutdown,
MemoryRead,
MemoryWrite,
IORead,
IOWrite,
InstructionRead,
Reserved
};
uint32_t address = 0;
bool BHE_state = false;
bool BLE_state = false;
void print_header() {
Serial.print(" (");
Serial.print(address & 0xFFFFFE, HEX);
Serial.print(") (");
Serial.print(BHE_state ? 'H' : ' ');
Serial.print(BLE_state ? 'L' : ' ');
Serial.print(") = ");
}
void read_cycle() {
print_header();
// advance through Ts
while (!(digitalRead(N_S0) && digitalRead(N_S1))) {
clock_step();
}
// read data
String dataString;
for (;;) {
dataString = Serial.readStringUntil('\n');
if (dataString[0] == 'i' || dataString[0] == 'I') {
interrupt_toggle();
print_header();
} else break;
}
uint16_t data = strtol(dataString.c_str(), NULL, 16);
Serial.println(data, HEX);
// drive bus for Tc
if (BHE_state & BLE_state) {
PORTC = (data >> 8) & 0xFF;
PORTL = data & 0xFF;
DDRC = 0xff;
DDRL = 0xff;
} else if (BHE_state) {
PORTC = data & 0xFF;
DDRC = 0xff;
} else if (BLE_state) {
PORTL = data & 0xFF;
DDRL = 0xff;
}
// advance to phase 2 of Tc
clock_step();
clock_step();
digitalWrite(N_READY, 0);
// advance through Tc
clock_step();
clock_step();
// release bus
digitalWrite(N_READY, 1);
PORTL = 0x00;
PORTC = 0x00;
DDRL = 0;
DDRC = 0;
}
void write_cycle() {
print_header();
// advance through Ts
while (!(digitalRead(N_S0) && digitalRead(N_S1))) {
clock_step();
}
// read bus for Tc
uint16_t data = 0;
if (BHE_state & BLE_state) {
data = static_cast<uint16_t>(PINC);
data <<= 8;
data |= static_cast<uint16_t>(PINL);
} else if (BHE_state) {
data = static_cast<uint16_t>(PINC);
} else if (BLE_state) {
data = static_cast<uint16_t>(PINL);
}
Serial.println(data, HEX);
// advance to phase 2 of Tc
clock_step();
clock_step();
digitalWrite(N_READY, 0);
// advance through Tc
clock_step();
clock_step();
// release bus
digitalWrite(N_READY, 1);
}
void interrupt_acknowledge() {
// advance through Ts
while (!(digitalRead(N_S0) && digitalRead(N_S1))) {
clock_step();
}
// advance to phase 2 of Tc
clock_step();
clock_step();
// note: not asserting READY to insert wait cycle
// advance through Tc
clock_step();
clock_step();
// advance to phase 2 of inserted Tc
clock_step();
clock_step();
digitalWrite(N_READY, 0);
// advance through inserted Tc
clock_step();
clock_step();
digitalWrite(N_READY, 1);
// advance through idle cycles
while (digitalRead(N_S0) && digitalRead(N_S1)) {
clock_step();
}
// advance to phase 2 of Ts
clock_step();
clock_step();
// sample inputs
bool S0_state = digitalRead(N_S0);
bool S1_state = digitalRead(N_S1);
bool COD_N_INTA_state = digitalRead(COD_N_INTA);
bool M_N_IO_state = digitalRead(M_N_IO);
if (S0_state || S1_state || COD_N_INTA_state || M_N_IO_state) {
Serial.println("critical error");
while (1);
}
// advance through Ts
while (!(digitalRead(N_S0) && digitalRead(N_S1))) {
clock_step();
}
// get vector
Serial.print(" (vector) = ");
String dataString = Serial.readStringUntil('\n');
uint8_t vector = strtol(dataString.c_str(), NULL, 16);
Serial.println(vector, HEX);
PORTC = 0x00;
PORTL = vector;
DDRC = 0xff;
DDRL = 0xff;
// advance to phase 2 of Tc
clock_step();
clock_step();
// note: not asserting READY to insert wait cycle
// advance through Tc
clock_step();
clock_step();
// advance to phase 2 of inserted Tc
clock_step();
clock_step();
digitalWrite(N_READY, 0);
// advance through inserted Tc
clock_step();
clock_step();
digitalWrite(N_READY, 1);
PORTL = 0x00;
PORTC = 0x00;
DDRL = 0;
DDRC = 0;
}
void loop() {
// advance through idle cycles
while (digitalRead(N_S0) && digitalRead(N_S1)) {
clock_step();
}
// advance to next falling edge
clock_step();
clock_step();
// we are now in Ts, phase 2 (right after initial falling edge)
bool S0_state = digitalRead(N_S0);
bool S1_state = digitalRead(N_S1);
bool COD_N_INTA_state = digitalRead(COD_N_INTA);
bool M_N_IO_state = digitalRead(M_N_IO);
// read address bus
address = static_cast<uint32_t>(PINA);
address <<= 8;
address |= static_cast<uint32_t>(PINK);
address <<= 8;
address |= static_cast<uint32_t>(PINF);
BHE_state = !digitalRead(N_BHE);
BLE_state = !(address & _BV(0));
// decode the bus cycle
BusCycle status = BusCycle::Reserved;
if (COD_N_INTA_state) {
if (M_N_IO_state) {
if (S0_state & !S1_state) {
status = BusCycle::InstructionRead;
}
} else {
if (S0_state & !S1_state) {
status = BusCycle::IORead;
address &= 0xffff;
} else if (!S0_state & S1_state) {
status = BusCycle::IOWrite;
address &= 0xffff;
}
}
} else {
if (M_N_IO_state) {
if (!S0_state & !S1_state) {
if (address & _BV(1)) {
status = BusCycle::Halt;
} else {
status = BusCycle::Shutdown;
}
} else if (S0_state & !S1_state) {
status = BusCycle::MemoryRead;
} else if (!S0_state & S1_state) {
status = BusCycle::MemoryWrite;
}
} else {
if (!S0_state & !S1_state) {
status = BusCycle::InterruptAcknowledge;
}
}
}
// print bus cycle name
switch (status) {
case BusCycle::InterruptAcknowledge:
Serial.print("Interrupt Acknowledge");
interrupt_acknowledge();
break;
case BusCycle::Halt:
Serial.println("-- Halt --");
while (1);
break;
case BusCycle::Shutdown:
Serial.println("-- Shutdown --");
while (1);
break;
case BusCycle::MemoryRead:
Serial.print("Memory Read");
read_cycle();
break;
case BusCycle::MemoryWrite:
Serial.print("Memory Write");
write_cycle();
break;
case BusCycle::IORead:
Serial.print("IO Read");
read_cycle();
break;
case BusCycle::IOWrite:
Serial.print("IO Write");
write_cycle();
break;
case BusCycle::InstructionRead:
Serial.print("Instruction Read");
read_cycle();
break;
case BusCycle::Reserved:
Serial.println("Error");
Serial.println("-- Latched State --");
Serial.print("CLK = ");
Serial.println(clkState);
Serial.print("COD_N_INTA = ");
Serial.println(COD_N_INTA_state);
Serial.print("M_N_IO = ");
Serial.println(M_N_IO_state);
Serial.print("S1 = ");
Serial.println(S1_state);
Serial.print("S0 = ");
Serial.println(S0_state);
Serial.println("-- Current State --");
Serial.print("COD_N_INTA = ");
Serial.println(digitalRead(COD_N_INTA));
Serial.print("M_N_IO = ");
Serial.println(digitalRead(M_N_IO));
Serial.print("S1 = ");
Serial.println(digitalRead(N_S1));
Serial.print("S0 = ");
Serial.println(digitalRead(N_S0));
while (1);
break;
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment