mirror of
https://github.com/JorjBauer/aiie.git
synced 2024-11-29 16:49:26 +00:00
99d0c8e72c
* New BIOS interface * New linux framebuffer version * Unified linuxfb and SDL with Teensy * Abstracted VM RAM * Fixed disk image corruption due to bad cache handling * Variable CPU speed support
219 lines
5.0 KiB
C++
219 lines
5.0 KiB
C++
#include "parallelsram.h"
|
|
|
|
// Assumes any Output Enable pin is hardwired-enabled;
|
|
// any Chip Enable pin is hardwared-enabled.
|
|
//
|
|
// Uses the low 8 bits of Port D as I/O lines (2, 14, 7, 8, 6, 20, 21, 5).
|
|
//
|
|
// R/W (aka WriteEnable) is on pin 31.
|
|
|
|
#define RAM_RW 34
|
|
|
|
// The Address pins (19 of them). It would be nice to have these
|
|
// easily bitwise-manipulable, instead of having to set each bit
|
|
// individually.
|
|
//
|
|
// We can use 12 bits of Port C: 15, 22, 23, 9, 10, 13, 11, 12, 35, 36, 37, 38
|
|
// And then 6 bits of Port B: 16 17 19 18 49 50
|
|
//
|
|
// And hard wire one bit low (we don't need all 19 lines). That gets us
|
|
// 256 Kb of RAM which should be sufficient.
|
|
|
|
static uint8_t addrPins[] = { 15, 22, 23, 9, 10, 13, 11, 12, 35, 36, 37, 38,
|
|
16, 17, 19, 18, 49, 50
|
|
};
|
|
|
|
#if 0
|
|
#define DELAY { delayMicroseconds(1); /* overkill, but useful for debugging */ }
|
|
#else
|
|
#define DELAY { __asm__ volatile ("nop"); __asm__ volatile ("nop"); \
|
|
__asm__ volatile ("nop"); __asm__ volatile ("nop"); \
|
|
__asm__ volatile ("nop"); __asm__ volatile ("nop"); \
|
|
__asm__ volatile ("nop"); __asm__ volatile ("nop"); \
|
|
}
|
|
#endif
|
|
|
|
#define OE_ON { /*if (noe != 255) {digitalWrite(noe, LOW);}*/ }
|
|
#define OE_OFF { /*if (noe != 255) {digitalWrite(noe, HIGH);}*/ }
|
|
|
|
#define CE_ON { /*if (n_ce != 255) {digitalWrite(n_ce, LOW);} if (p_ce != 255) { digitalWrite(p_ce, HIGH); }*/ }
|
|
#define CE_OFF { /*if (n_ce != 255) {digitalWrite(n_ce, HIGH);} if (p_ce != 255) { digitalWrite(p_ce, LOW); }*/ }
|
|
|
|
#define WE_ON { digitalWriteFast(RAM_RW, LOW); }
|
|
#define WE_OFF { digitalWriteFast(RAM_RW, HIGH); }
|
|
|
|
ParallelSRAM::ParallelSRAM()
|
|
{
|
|
pinMode(RAM_RW, OUTPUT);
|
|
|
|
// Port D is our I/O port. Use the AVR emulation layer to set up the
|
|
// pins once, and then we'll just fiddle with the DDR, input, and
|
|
// output directly.
|
|
|
|
// Enable it as a digital port...
|
|
// SIM_SCGC5 |= SIM_SCGC5_PORTD;
|
|
//... what else? How do we set PORTD_PCR[0-7]?
|
|
|
|
pinMode(2, INPUT);
|
|
pinMode(14, INPUT);
|
|
pinMode(7, INPUT);
|
|
pinMode(8, INPUT);
|
|
pinMode(6, INPUT);
|
|
pinMode(20, INPUT);
|
|
pinMode(21, INPUT);
|
|
pinMode(5, INPUT);
|
|
isInput = true;
|
|
|
|
// Set up the address pins
|
|
for (int i=0; i<sizeof(addrPins); i++) {
|
|
pinMode(addrPins[i], INPUT); // disable pull-ups
|
|
pinMode(addrPins[i], OUTPUT);
|
|
digitalWrite(addrPins[i], LOW);
|
|
}
|
|
|
|
}
|
|
|
|
void ParallelSRAM::SetPins()
|
|
{
|
|
pinMode(RAM_RW, OUTPUT);
|
|
|
|
// Port D is our I/O port. Use the AVR emulation layer to set up the
|
|
// pins once, and then we'll just fiddle with the DDR, input, and
|
|
// output directly.
|
|
|
|
// Enable it as a digital port...
|
|
// SIM_SCGC5 |= SIM_SCGC5_PORTD;
|
|
//... what else? How do we set PORTD_PCR[0-7]?
|
|
|
|
pinMode(2, INPUT);
|
|
pinMode(14, INPUT);
|
|
pinMode(7, INPUT);
|
|
pinMode(8, INPUT);
|
|
pinMode(6, INPUT);
|
|
pinMode(20, INPUT);
|
|
pinMode(21, INPUT);
|
|
pinMode(5, INPUT);
|
|
isInput = true;
|
|
|
|
// Set up the address pins
|
|
for (int i=0; i<sizeof(addrPins); i++) {
|
|
pinMode(addrPins[i], INPUT); // disable pull-ups
|
|
pinMode(addrPins[i], OUTPUT);
|
|
digitalWrite(addrPins[i], LOW);
|
|
}
|
|
}
|
|
|
|
ParallelSRAM::~ParallelSRAM()
|
|
{
|
|
}
|
|
|
|
uint8_t ParallelSRAM::read(uint32_t addr)
|
|
{
|
|
cli();
|
|
// Read cycle 2
|
|
setAddress(addr);
|
|
|
|
// make sure address is valid before CE is asserted
|
|
DELAY;
|
|
|
|
CE_ON;
|
|
OE_ON;
|
|
|
|
DELAY;
|
|
|
|
uint8_t ret = getInput();
|
|
|
|
// Optional; can leave these lines asserted...
|
|
OE_OFF;
|
|
CE_OFF;
|
|
|
|
sei();
|
|
return ret;
|
|
}
|
|
|
|
void ParallelSRAM::write(uint32_t addr, uint8_t v)
|
|
{
|
|
cli();
|
|
setAddress(addr);
|
|
|
|
DELAY;
|
|
|
|
WE_ON;
|
|
CE_ON;
|
|
|
|
setOutput(v);
|
|
|
|
DELAY;
|
|
|
|
CE_OFF;
|
|
WE_OFF;
|
|
sei();
|
|
}
|
|
|
|
uint8_t ParallelSRAM::getInput()
|
|
{
|
|
if (!isInput) {
|
|
#if 1
|
|
// Directly set the direction bits. The rest of the port setup
|
|
// should be fine from the initial config.
|
|
*(volatile uint8_t *)(&GPIOD_PDDR) = 0x00; // inputs
|
|
#else
|
|
pinMode(2, INPUT);
|
|
pinMode(14, INPUT);
|
|
pinMode(7, INPUT);
|
|
pinMode(8, INPUT);
|
|
pinMode(6, INPUT);
|
|
pinMode(20, INPUT);
|
|
pinMode(21, INPUT);
|
|
pinMode(5, INPUT);
|
|
#endif
|
|
isInput = true;
|
|
}
|
|
|
|
return GPIOD_PDIR & 0xFF;
|
|
}
|
|
|
|
void ParallelSRAM::setOutput(uint8_t v)
|
|
{
|
|
// FIXME: is there a faster way to do this?
|
|
if (isInput) {
|
|
#if 1
|
|
// FIMXE: would this be correct?
|
|
*(volatile uint8_t *)(&GPIOD_PDDR) |= 0xFF; // outputs
|
|
#else
|
|
pinMode(2, OUTPUT);
|
|
pinMode(14, OUTPUT);
|
|
pinMode(7, OUTPUT);
|
|
pinMode(8, OUTPUT);
|
|
pinMode(6, OUTPUT);
|
|
pinMode(20, OUTPUT);
|
|
pinMode(21, OUTPUT);
|
|
pinMode(5, OUTPUT);
|
|
#endif
|
|
isInput = false;
|
|
}
|
|
|
|
// Directly set the low 8 bits of D.
|
|
*(volatile uint8_t *)(&GPIOD_PDOR) = v;
|
|
}
|
|
|
|
void ParallelSRAM::setAddress(uint32_t addr)
|
|
{
|
|
// The low 12 bits of the address go right in to Port C. Set these
|
|
// by doing a clear of the bitmask, and then set the bits...
|
|
GPIOC_PCOR = 0x00000FFF;
|
|
GPIOC_PSOR = (addr & 0xFFF);
|
|
|
|
// The high 6 bits of the address go in to Port B, bits 0..5.
|
|
// We do that the same way...
|
|
GPIOB_PCOR = 0x0000003F;
|
|
GPIOB_PSOR = (addr >> 12);
|
|
|
|
#if 0
|
|
for (uint8_t i=0; i<sizeof(addrPins); i++) {
|
|
digitalWrite(addrPins[i],
|
|
addr & (1 << i) ? HIGH : LOW);
|
|
}
|
|
#endif
|
|
}
|