Skip to content

Commit

Permalink
Corrected source files - fixed header information
Browse files Browse the repository at this point in the history
  • Loading branch information
Simon Inns committed Apr 10, 2018
1 parent f45aa68 commit c3338b7
Show file tree
Hide file tree
Showing 8 changed files with 1,801 additions and 1,945 deletions.
475 changes: 0 additions & 475 deletions Firmware/TMS6100-Emulator/main.c

This file was deleted.

1,425 changes: 0 additions & 1,425 deletions Firmware/TMS6100-Emulator/tms6100romdata.h

This file was deleted.

2 changes: 1 addition & 1 deletion Firmware/TMS6100-Emulator.atsln → Firmware/tms6100.atsln
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Atmel Studio Solution File, Format Version 11.00
VisualStudioVersion = 14.0.23107.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "TMS6100-Emulator", "TMS6100-Emulator\TMS6100-Emulator.cproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}"
Project("{54F91283-7BC4-4236-8FF9-10F437C3AD48}") = "tms6100", "tms6100\tms6100.cproj", "{DCE6C7E3-EE26-4D79-826B-08594B9AD897}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
112 changes: 112 additions & 0 deletions Firmware/tms6100/hardwaremap.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/************************************************************************
hardwaremap.h
Physical hardware mapping definitions for portability
Copyright (C) 2018 Simon Inns
This file is part of the TMS6100-Emulator.
The TMS6100-Emulator 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 3 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, see <http://www.gnu.org/licenses/>.
Email: simon.inns@gmail.com
************************************************************************/

#ifndef HARDWAREMAP_H_
#define HARDWAREMAP_H_

// Target device: ATmega32u2
// Also tested on the ATmega32u4 (Arduino Leonardo mini pro)

// Definitions for TMS6100 IO Pins --------------------------------------

// ADD1 (PD2)
#define TMS6100_ADD1_PORT PORTD
#define TMS6100_ADD1_PIN PIND
#define TMS6100_ADD1_DDR DDRD
#define TMS6100_ADD1 (1 << 2)

// ADD2 (PD3)
#define TMS6100_ADD2_PORT PORTD
#define TMS6100_ADD2_PIN PIND
#define TMS6100_ADD2_DDR DDRD
#define TMS6100_ADD2 (1 << 3)

// ADD4 (PD4)
#define TMS6100_ADD4_PORT PORTD
#define TMS6100_ADD4_PIN PIND
#define TMS6100_ADD4_DDR DDRD
#define TMS6100_ADD4 (1 << 4)

// ADD8 (PB3/MOSI)
#define TMS6100_ADD8_PORT PORTB
#define TMS6100_ADD8_PIN PINB
#define TMS6100_ADD8_DDR DDRB
#define TMS6100_ADD8 (1 << 3)

// M0 (PD0/INT0)
#define TMS6100_M0_PORT PORTD
#define TMS6100_M0_PIN PIND
#define TMS6100_M0_DDR DDRD
#define TMS6100_M0 (1 << 0)
#define TMS6100_M0_INT INT0
#define TMS6100_M0_INT_VECT INT0_vect
#define TMS6100_M0_ISC0 ISC00
#define TMS6100_M0_ISC1 ISC01
#define TMS6100_M0_INTF INTF0

// M1 (PD1/INT1)
#define TMS6100_M1_PORT PORTD
#define TMS6100_M1_PIN PIND
#define TMS6100_M1_DDR DDRD
#define TMS6100_M1 (1 << 1)
#define TMS6100_M1_INT INT1
#define TMS6100_M1_INT_VECT INT1_vect
#define TMS6100_M1_ISC0 ISC10
#define TMS6100_M1_ISC1 ISC11
#define TMS6100_M1_INTF INTF1

// CLK (PB4) - Not currently used by the emulator as we use
// the SPI module to asynchronously time data based on the
// M0 pulses (which has the effect of making the data in sync
// with the clock).
#define TMS6100_CLK_PORT PORTB
#define TMS6100_CLK_PIN PINB
#define TMS6100_CLK_DDR DDRB
#define TMS6100_CLK (1 << 4)

// Definitions for SPI pins ---------------------------------------------

// MISO - This is ADD8 defined above

// MOSI (PB2)
#define TMS6100_MOSI_PORT PORTB
#define TMS6100_MOSI_PIN PINB
#define TMS6100_MOSI_DDR DDRB
#define TMS6100_MOSI (1 << 2)

// SCK (PB1)
#define TMS6100_SCK_PORT PORTB
#define TMS6100_SCK_PIN PINB
#define TMS6100_SCK_DDR DDRB
#define TMS6100_SCK (1 << 1)

// !SS (PB0)
#define TMS6100_SS_PORT PORTB
#define TMS6100_SS_PIN PINB
#define TMS6100_SS_DDR DDRB
#define TMS6100_SS (1 << 0)

#endif /* HARDWAREMAP_H_ */
267 changes: 267 additions & 0 deletions Firmware/tms6100/main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,267 @@
/************************************************************************
main.c
TMS6100 Emulator (for use with TMS5220 VSP)
Copyright (C) 2018 Simon Inns
This file is part of the TMS6100-Emulator.
The TMS6100-Emulator 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 3 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, see <http://www.gnu.org/licenses/>.
Email: simon.inns@gmail.com
************************************************************************/

// Use the internal clock
#define F_CPU 16000000UL

// Note: The TMS6100 was mask programmed for either 1-bit or 4-bit data
// transfer. This emulation is for use with the TMS5220 VSP which only
// supports 1-bit mode. Therefore 4-bit data is not emulated.

// This code has only been tested for use with the TMS5220 as a phrase ROM
// (PHROM) - If you use it with another device, your millage may vary :)

// Global includes
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>

// Include the PHROM data image
#include "romdata.h"

// Include the hardware mapping
#include "hardwaremap.h"

// Some useful definitions
#define FALSE 0
#define TRUE 1

// Structure for holding the current state of the TMS6100
// Note: All variables need to be 'volatile' as they are
// used within the interrupt handling routines.
volatile struct tms6100State {
volatile uint32_t address; // The current address the ROM is pointing to
volatile uint32_t chipSelectNumber; // The chip identifier sent by the host

volatile uint8_t loadAddressNibble; // The position of the address nibble we are currently waiting for (0-4)
volatile uint8_t validAddressLoadedFlag; // Flag indicating if there is a valid address loaded
} tms6100;

// Initialise the AVR hardware
void initialiseHardware(void)
{
// Set M0 and M1 pins to input and turn off weak pull-ups
TMS6100_M0_DDR &= ~TMS6100_M0;
TMS6100_M0_PORT &= ~TMS6100_M0;
TMS6100_M1_DDR &= ~TMS6100_M1;
TMS6100_M1_PORT &= ~TMS6100_M1;

// Set the address bus to input and turn off weak pull-ups
TMS6100_ADD1_DDR &= ~TMS6100_ADD1;
TMS6100_ADD2_DDR &= ~TMS6100_ADD2;
TMS6100_ADD4_DDR &= ~TMS6100_ADD4;
TMS6100_ADD8_DDR &= ~TMS6100_ADD8;

TMS6100_ADD1_PORT &= ~TMS6100_ADD1;
TMS6100_ADD2_PORT &= ~TMS6100_ADD2;
TMS6100_ADD4_PORT &= ~TMS6100_ADD4;
TMS6100_ADD8_PORT &= ~TMS6100_ADD8;

// Set CLK to input and turn off weak pull-ups
TMS6100_CLK_DDR &= ~TMS6100_CLK;
TMS6100_CLK_PORT &= ~TMS6100_CLK;

// Initialise the TMS6100 emulation:
tms6100.address = 0;
tms6100.loadAddressNibble = 0;
tms6100.validAddressLoadedFlag = FALSE;

// Initialise the SPI pins
// (MISO configured by ADD8)
TMS6100_MOSI_DDR &= ~TMS6100_MOSI; // Input
TMS6100_SCK_DDR &= ~TMS6100_SCK; // Input
TMS6100_SS_DDR &= ~TMS6100_SS; // Input
}

// SPI buffer interrupt - called when the SPI buffer is empty
ISR(SPI_STC_vect)
{
// Point to the next byte of the PHROM
tms6100.address++;

// Read the next byte to transfer from our current
// valid address and place it in the SPI transmit buffer
SPDR = pgm_read_byte(&(phromData[tms6100.address]));
}

// Function to handle external interrupt vector for the falling edge of M0
// Note: The falling edge of M0 indicates a READ DATA command
ISR(TMS6100_M0_INT_VECT)
{
// There are two possible types of READ DATA command:
// A 'dummy' read which indicates the TMS6100 should reset
// and a real read which indicates the TMS6100 should transfer a bit of data

// The reset can be detected because the TMS6100 requires 5 calls to the
// LOAD ADDRESS command before a loaded address is considered 'valid',
// so if we get a read, and there is not yet a valid address, the command
// is a dummy read.

// Check for a 'dummy' read (indicating reset requested)
if (tms6100.validAddressLoadedFlag == FALSE)
{
// There is no valid loaded address... Reset the TMS6100 to a known state
tms6100.address = 0;
tms6100.loadAddressNibble = 0;
}
else
{
// We have a valid address so this is a 'real' READ DATA command

// This is triggered because the host sends a single M0 pulse
// to initiate the DATA READ command (and this pulse is *not*
// for data transfer) - so we can detect this pulse and use it
// to turn on the SPI module for the actual (much higher speed)
// data transfer

// Set the ADD8 bus pin to output mode (this doubles as SPI MISO)
TMS6100_ADD8_DDR |= TMS6100_ADD8;

// Turn off the M0 interrupt (so we only react using the SPI module
// from here on)
EIMSK &= ~(1 << TMS6100_M0_INT);

// Turn on the SPI module (slave mode, reverse data order, interrupt on,
// sample on trailing edge)
SPCR |= (1 << SPE) | (1 << DORD) | (1 << SPIE) | (1 << CPHA);

// Fill the SPI buffer with the first byte
SPDR = pgm_read_byte(&(phromData[tms6100.address]));
}
}

// Function to handle external interrupt vector for the rising edge of M1
// Note: The rising edge of M1 indicates a LOAD ADDRESS command
ISR(TMS6100_M1_INT_VECT)
{
uint32_t addressNibble = 0;

// Since this could occur after an SPI transfer has
// been in progress, we need to reset the SPI, switch
// ADD8/MISO back to input and re-enable the M0
// interrupt...

// Turn the SPI off
SPCR = 0;

// Ensure there is no pending interrupt on M0
// (clear the interrupt flag by writing a logical one)
EIFR |= (1 << TMS6100_M0_INTF);

// Enable the M0 interrupt
EIMSK |= (1 << TMS6100_M0_INT);

// Set the ADD8 bus pin to input mode
TMS6100_ADD8_DDR &= ~TMS6100_ADD8;

// Read the nibble from the address bus
if ((TMS6100_ADD1_PIN & TMS6100_ADD1)) addressNibble += 1;
if ((TMS6100_ADD2_PIN & TMS6100_ADD2)) addressNibble += 2;
if ((TMS6100_ADD4_PIN & TMS6100_ADD4)) addressNibble += 4;
if ((TMS6100_ADD8_PIN & TMS6100_ADD8)) addressNibble += 8;

// If this is the first nibble of a new 20-bit address, clear the address register
if (tms6100.loadAddressNibble == 0) tms6100.address = 0;

// Store the address nibble in the correct position of the 20-bit address register
if (tms6100.loadAddressNibble == 0) tms6100.address |= addressNibble << 0;
if (tms6100.loadAddressNibble == 1) tms6100.address |= addressNibble << 4;
if (tms6100.loadAddressNibble == 2) tms6100.address |= addressNibble << 8;
if (tms6100.loadAddressNibble == 3) tms6100.address |= addressNibble << 12;
if (tms6100.loadAddressNibble == 4) tms6100.address |= addressNibble << 16;

// Increment the current address register nibble pointer and range check
tms6100.loadAddressNibble++;

// Was the received nibble the 5th and final nibble of an address?
if (tms6100.loadAddressNibble > 4)
{
// 5th nibble of an address received - Address is now valid for use
tms6100.validAddressLoadedFlag = TRUE;
tms6100.loadAddressNibble = 0;

// We get 20 bits of address data from the host in 5 nibbles...

// The datasheet says to ignore the two most significant bits:
tms6100.address &= 0x9FFFF; // Mask = 0b0011 1111 1111 1111 1111 = 0x9FFFF

// The number of the selected chip is the 4 most significant bits of the remaining bits:
// 0b11 1100 0000 0000 0000 = 0x3C000 >> 14
tms6100.chipSelectNumber = (tms6100.address & 0x3C000) >> 14; // Should be 'FF' for the Acorn PHROM

// Note: An original TMS6100 would be mask programmed with it's own chip number.
// If you want to support multiple TMS6100 chips you could test it here.

// Now we need to remove the chip select bits so we are left with only 14-bit address for this PHROM
tms6100.address &= 0x3FFF; // 0b11 1111 1111 1111 = 0x3FFF
}
else
{
// We only have a partial address...

// Mark the current address register as invalid
tms6100.validAddressLoadedFlag = FALSE;
}
}

// Note: The TMS6100 supports a 3rd command (INDIRECT ADDRESS) which is
// indicated by both M0 and M1 rising at the same time. This isn't used
// by the TMS5220 VSP, so it's not implemented in this emulator.

// Main function
int main(void)
{
// Initialise the hardware
initialiseHardware();

// We need to interrupt on the M0 and M1 pins
// using INT (external interrupts) which can be
// configured to interrupt on either the rising
// or falling edge of a pulse:

// External interrupt on the falling edge of a M0 pulse
EICRA |= (1 << TMS6100_M0_ISC1);

// External interrupt on the rising edge of a M1 pulse
EICRA |= (1 << TMS6100_M1_ISC1) | (1 << TMS6100_M1_ISC0);

// Enable external interrupts for M0 and M1
EIMSK |= (1 << TMS6100_M0_INT) | (1 << TMS6100_M1_INT);

// Turn SPI off
SPCR = 0; // Probably not required?

// Enable interrupts globally
sei();

// Main processing loop
while (1)
{
// Nothing to do here. Everything is performed
// using interrupts.
}
}

Loading

0 comments on commit c3338b7

Please sign in to comment.