mirror of
https://github.com/dougg3/mac-rom-simm-programmer.git
synced 2024-11-15 06:07:46 +00:00
339 lines
8.9 KiB
C
339 lines
8.9 KiB
C
/*
|
|
* ports.c
|
|
*
|
|
* Created on: Nov 26, 2011
|
|
* Author: Doug
|
|
*
|
|
* Copyright (C) 2011-2012 Doug Brown
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*
|
|
*/
|
|
|
|
#include "ports.h"
|
|
#include "mcp23s17.h"
|
|
|
|
// Save some time by not changing the register
|
|
// unless the value has changed [SPI = relatively slow]
|
|
static uint32_t savedDataDDR = 0;
|
|
|
|
void Ports_Init(void)
|
|
{
|
|
// This module depends on the MPC23S17
|
|
MCP23S17_Init();
|
|
savedDataDDR = 0xFFFFFFFFUL;
|
|
Ports_SetDataDDR(0);
|
|
}
|
|
|
|
void Ports_SetAddressOut(uint32_t data)
|
|
{
|
|
// NOTE: If any of PORTA or PORTC or PORTD pins 0, 1, 4, 5, or 6 are set as
|
|
// inputs, this function might mess with their pull-up resistors.
|
|
// Only use it under normal operation when all the address pins are being
|
|
// used as outputs
|
|
|
|
PORTA = (data & 0xFF); // A0-A7
|
|
PORTC = ((data >> 8) & 0xFF); // A8-A15
|
|
|
|
// A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
|
|
uint8_t tmp = (data >> 16) & 0xFF;
|
|
tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
|
|
|
|
// Now, turn off the pins we have to turn off, and turn on the pins we have to turn on
|
|
// (without affecting other pins [2, 3, and 7] that we aren't supposed to touch)
|
|
PORTD &= (0x8C | tmp); // This should turn off all '0' bits in tmp.
|
|
PORTD |= tmp; // This should turn on all '1' bits in tmp
|
|
}
|
|
|
|
void Ports_AddressOut_RMW(uint32_t data, uint32_t modifyMask)
|
|
{
|
|
uint32_t modifiedDataOn = data & modifyMask;
|
|
uint32_t modifiedDataOff = data | ~modifyMask;
|
|
|
|
// Turn on/off requested bits in the PORT register.
|
|
PORTA |= ((modifiedDataOn >> 0) & 0xFF);
|
|
PORTA &= ((modifiedDataOff >> 0) & 0xFF);
|
|
PORTC |= ((modifiedDataOn >> 8) & 0xFF);
|
|
PORTC &= ((modifiedDataOff >> 8) & 0xFF);
|
|
|
|
// A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
|
|
uint8_t tmp = (modifiedDataOn >> 16) & 0xFF;
|
|
tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
|
|
|
|
PORTD |= tmp;
|
|
PORTD &= (0x8C | tmp);
|
|
}
|
|
|
|
void Ports_SetDataOut(uint32_t data)
|
|
{
|
|
// NOTE: If any pins of PORTE or PORTF are set as inputs, this
|
|
// function might mess with their pull-up resistors.
|
|
// Only use it under normal operation when all the address pins are being
|
|
// used as outputs
|
|
|
|
// Set the actual outputted values
|
|
MCP23S17_SetPins((data >> 16) & 0xFFFF); // D0-D15
|
|
PORTE = ((data >> 8) & 0xFF); // D16-D23
|
|
PORTF = ((data >> 0) & 0xFF); // D24-D31
|
|
}
|
|
|
|
void Ports_DataOut_RMW(uint32_t data, uint32_t modifyMask)
|
|
{
|
|
uint32_t modifiedDataOn = data & modifyMask;
|
|
uint32_t modifiedDataOff = data | ~modifyMask;
|
|
|
|
// Read what's in it first...
|
|
uint16_t outputLatches = MCP23S17_GetOutputs();
|
|
outputLatches |= (modifiedDataOn >> 16) & 0xFFFF;
|
|
outputLatches &= (modifiedDataOff >> 16) & 0xFFFF;
|
|
MCP23S17_SetPins(outputLatches);
|
|
|
|
// Turn on/off requested bits in the PORT register.
|
|
PORTE |= ((modifiedDataOn >> 8) & 0xFF);
|
|
PORTE &= ((modifiedDataOff >> 8) & 0xFF);
|
|
PORTF |= ((modifiedDataOn >> 0) & 0xFF);
|
|
PORTF &= ((modifiedDataOff >> 0) & 0xFF);
|
|
}
|
|
|
|
void Ports_SetAddressDDR(uint32_t ddr)
|
|
{
|
|
DDRA = (ddr & 0xFF); // A0-A7
|
|
DDRC = ((ddr >> 8) & 0xFF); // A8-A15
|
|
|
|
// A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
|
|
uint8_t tmp = (ddr >> 16) & 0xFF;
|
|
tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
|
|
|
|
// Now, turn off the DDR bits we have to turn off,
|
|
// and turn on the DDR bits we have to turn on
|
|
// (without affecting other bits [2, 3, and 7]
|
|
// that we aren't supposed to touch)
|
|
DDRD &= (0x8C | tmp); // This should turn off all '0' bits in tmp.
|
|
DDRD |= tmp; // This should turn on all '1' bits in tmp
|
|
}
|
|
|
|
void Ports_AddressDDR_RMW(uint32_t ddr, uint32_t modifyMask)
|
|
{
|
|
uint32_t modifiedDataOn = ddr & modifyMask;
|
|
uint32_t modifiedDataOff = ddr | ~modifyMask;
|
|
|
|
// Turn on/off requested bits in the DDR register.
|
|
DDRA |= ((modifiedDataOn >> 0) & 0xFF);
|
|
DDRA &= ((modifiedDataOff >> 0) & 0xFF);
|
|
DDRC |= ((modifiedDataOn >> 8) & 0xFF);
|
|
DDRC &= ((modifiedDataOff >> 8) & 0xFF);
|
|
|
|
// A16-A20 are special because they are split up...(We use PORTD pins 0, 1, 4, 5, 6)
|
|
uint8_t tmp = (modifiedDataOn >> 16) & 0xFF;
|
|
tmp = (tmp & 0x03) | ((tmp & 0x1C) << 2);
|
|
|
|
DDRD |= tmp;
|
|
DDRD &= (0x8C | tmp);
|
|
}
|
|
|
|
void Ports_SetDataDDR(uint32_t ddr)
|
|
{
|
|
if (savedDataDDR != ddr)
|
|
{
|
|
MCP23S17_SetDDR((ddr >> 16) & 0xFFFF); // D0-D15
|
|
DDRE = ((ddr >> 8) & 0xFF); // D16-D23
|
|
DDRF = ((ddr >> 0) & 0xFF); // D24-D31
|
|
|
|
savedDataDDR = ddr;
|
|
}
|
|
}
|
|
|
|
void Ports_DataDDR_RMW(uint32_t ddr, uint32_t modifyMask)
|
|
{
|
|
uint32_t newSavedDataDDR;
|
|
uint32_t modifiedDataOn = ddr & modifyMask;
|
|
uint32_t modifiedDataOff = ddr | ~modifyMask;
|
|
|
|
// If we can get away with it, don't bother reading back...
|
|
if (((modifyMask >> 16) & 0xFFFF) == 0xFFFF)
|
|
{
|
|
MCP23S17_SetDDR((modifiedDataOn >> 16) & 0xFFFF);
|
|
|
|
// Remember what the new DDR will be
|
|
newSavedDataDDR = (modifiedDataOn & 0xFFFF0000UL);
|
|
}
|
|
else // Otherwise, we have to read what's in it first...(unless I decide to keep a local cached copy)
|
|
{
|
|
uint16_t outputLatches = MCP23S17_GetDDR();
|
|
outputLatches |= (modifiedDataOn >> 16) & 0xFFFF;
|
|
outputLatches &= (modifiedDataOff >> 16) & 0xFFFF;
|
|
MCP23S17_SetDDR(outputLatches);
|
|
|
|
// Remember what the new DDR will be
|
|
newSavedDataDDR = ((uint32_t)outputLatches << 16);
|
|
}
|
|
|
|
// Turn on/off requested bits in the DDR register.
|
|
DDRE |= ((modifiedDataOn >> 8) & 0xFF);
|
|
DDRE &= ((modifiedDataOff >> 8) & 0xFF);
|
|
DDRF |= ((modifiedDataOn >> 0) & 0xFF);
|
|
DDRF &= ((modifiedDataOff >> 0) & 0xFF);
|
|
|
|
// Remember what the new DDR will be
|
|
newSavedDataDDR |= ((uint32_t)DDRE) << 8;
|
|
newSavedDataDDR |= ((uint32_t)DDRF) << 0;
|
|
|
|
// Save the new DDR
|
|
savedDataDDR = newSavedDataDDR;
|
|
}
|
|
|
|
void Ports_SetCSDDR(bool ddr)
|
|
{
|
|
if (ddr)
|
|
{
|
|
DDRB |= SIMM_CS;
|
|
}
|
|
else
|
|
{
|
|
DDRB &= ~SIMM_CS;
|
|
}
|
|
}
|
|
|
|
void Ports_SetOEDDR(bool ddr)
|
|
{
|
|
if (ddr)
|
|
{
|
|
DDRB |= SIMM_OE;
|
|
}
|
|
else
|
|
{
|
|
DDRB &= ~SIMM_OE;
|
|
}
|
|
}
|
|
|
|
void Ports_SetWEDDR(bool ddr)
|
|
{
|
|
if (ddr)
|
|
{
|
|
DDRB |= SIMM_WE;
|
|
}
|
|
else
|
|
{
|
|
DDRB &= ~SIMM_WE;
|
|
}
|
|
}
|
|
|
|
void Ports_AddressPullups_RMW(uint32_t pullups, uint32_t modifyMask)
|
|
{
|
|
// Pull-ups are set by writing to the data register when in input mode.
|
|
// MAKE SURE THE PINS ARE SET AS INPUTS FIRST!
|
|
Ports_AddressOut_RMW(pullups, modifyMask);
|
|
}
|
|
|
|
void Ports_DataPullups_RMW(uint32_t pullups, uint32_t modifyMask)
|
|
{
|
|
// Pull-ups here are a little more tricky because the MCP23S17 has
|
|
// separate registers for pull-up enable.
|
|
uint32_t modifiedDataOn = pullups & modifyMask;
|
|
uint32_t modifiedDataOff = pullups | ~modifyMask;
|
|
|
|
// If we can get away with it, don't bother reading back...
|
|
if (((modifyMask >> 16) & 0xFFFF) == 0xFFFF)
|
|
{
|
|
MCP23S17_SetPullups((modifiedDataOn >> 16) & 0xFFFF);
|
|
}
|
|
else // Otherwise, we have to read what's in it first...(unless I decide to keep a local cached copy)
|
|
{
|
|
uint16_t outputLatches = MCP23S17_GetPullups();
|
|
outputLatches |= (modifiedDataOn >> 16) & 0xFFFF;
|
|
outputLatches &= (modifiedDataOff >> 16) & 0xFFFF;
|
|
MCP23S17_SetPullups(outputLatches);
|
|
}
|
|
|
|
// Turn on/off requested bits in the PORT register for the other 16 bits.
|
|
PORTE |= ((modifiedDataOn >> 8) & 0xFF);
|
|
PORTE &= ((modifiedDataOff >> 8) & 0xFF);
|
|
PORTF |= ((modifiedDataOn >> 0) & 0xFF);
|
|
PORTF &= ((modifiedDataOff >> 0) & 0xFF);
|
|
}
|
|
|
|
void Ports_SetCSPullup(bool pullup)
|
|
{
|
|
if (pullup)
|
|
{
|
|
PORTB |= SIMM_CS;
|
|
}
|
|
else
|
|
{
|
|
PORTB &= ~SIMM_CS;
|
|
}
|
|
}
|
|
|
|
void Ports_SetOEPullup(bool pullup)
|
|
{
|
|
if (pullup)
|
|
{
|
|
PORTB |= SIMM_OE;
|
|
}
|
|
else
|
|
{
|
|
PORTB &= ~SIMM_OE;
|
|
}
|
|
}
|
|
|
|
void Ports_SetWEPullup(bool pullup)
|
|
{
|
|
if (pullup)
|
|
{
|
|
PORTB |= SIMM_WE;
|
|
}
|
|
else
|
|
{
|
|
PORTB &= ~SIMM_WE;
|
|
}
|
|
}
|
|
|
|
|
|
uint32_t Ports_ReadAddress(void)
|
|
{
|
|
uint32_t result = PINA;
|
|
result |= (((uint32_t)PINC) << 8);
|
|
uint8_t tmp = (PIND & 0x03) | ((PIND & 0x70) >> 2);
|
|
result |= (((uint32_t)tmp) << 16);
|
|
|
|
return result;
|
|
}
|
|
|
|
uint32_t Ports_ReadData(void)
|
|
{
|
|
uint32_t result = (uint32_t)MCP23S17_ReadPins() << 16;
|
|
|
|
// Grab the other two bytes...
|
|
result |= (((uint32_t)PINE) << 8);
|
|
result |= (((uint32_t)PINF) << 0);
|
|
|
|
return result;
|
|
}
|
|
|
|
bool Ports_ReadCS(void)
|
|
{
|
|
return (PINB & SIMM_CS) != 0;
|
|
}
|
|
|
|
bool Ports_ReadOE(void)
|
|
{
|
|
return (PINB & SIMM_OE) != 0;
|
|
}
|
|
|
|
bool Ports_ReadWE(void)
|
|
{
|
|
return (PINB & SIMM_WE) != 0;
|
|
}
|