Skip to content

Commit 5f92470

Browse files
committed
Merge branch 'dev'
2 parents 65d9809 + 22b5fa8 commit 5f92470

12 files changed

+1991
-50
lines changed

.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
2+
.DS_Store
3+
.gitattributes
4+
.vscode

6502-SBC-using-Teensy.ino

+107-32
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,42 @@
1-
/*
2-
Bus Access system
3-
Access 65C02 address and databus on 24 Teensy Pins
4-
Start simulate some memory for 65c02 to Read/Write.
5-
*/
1+
//
2+
// TEENSY 65C02
3+
//
4+
// Access 65C02 address and databus using Teensy 3.6(3.3v) or 3.5 (5v)
5+
// Can simulate RAM, ROM and ACIA (6551 or 6850)
6+
// Provide access to all pins.
7+
68

79
#include "SBC.h"
810

11+
// ROM image declared as a C Array.
12+
// Can be easily created from a real ROM image using srec_cat
13+
// http://srecord.sourceforge.net/man/man1/srec_cat.html
14+
915
#ifdef ROMEMU
1016
#include "rom.h"
1117
#endif
1218

1319

1420
// Declare the Pins to use
1521

22+
// Bus Pins (DATA and ADDRESS)
23+
// As the Teensy doens't expose 16 consecutive PINS attached to the same PORT
24+
// we need to split the Address bus over two different PORTS
25+
26+
byte dataPins[] = {5,21,20,6,8,7,14,2}; // Data Bus
27+
byte addressHPins [] = {30,29,1,0,18,19,17,16}; // Address Bus High byte
28+
byte addressLPins[]={12,11,13,10,9,23,22,15}; // Address Bus Low byte
29+
30+
// Variable declarations
1631

17-
byte dataPins[] = {2,14,7,8,6,20,21,5}; // Data Bus
18-
byte addressHPins [] = {16,17,19,18,0,1,29,30}; // Address Bus High byte
19-
byte addressLPins[]={15,22,23,9,10,13,11,12}; // Address Bus Low byte
2032
uint8_t chipEnable; // RAM, ROM or Serial to access
33+
2134
#ifdef DEBUG
22-
byte databyte=0;
35+
byte databyte=0;
2336
uint16_t savedaddress=0;
2437
#endif
38+
39+
2540
// Declare global variables
2641
// Must be volatile to avoid any compiler optimization
2742

@@ -31,50 +46,98 @@ volatile boolean rw;
3146
volatile byte ACIAStatus;
3247
volatile uint16_t address;
3348

49+
// If RAM emulation is required
50+
// declare a corresponding array
51+
3452
#ifdef RAMEMU
35-
byte mem[RAMSIZE]; // declare RAM as a byte array.
53+
byte mem[RAMSIZE]; // declare RAM as a byte array.
3654
#endif
3755

3856
// Redefine yield() as the default one is useless and waste time.
57+
// This is required to achieve a descent speed
58+
3959
void yield(){}
4060

4161
void setup() {
4262

4363
Serial.begin(0); // Start the serial port
64+
65+
#ifdef DEBUG
66+
Serial.print("Bringing RESET LOW\n");
67+
#endif
68+
69+
// First thing, let's bring reset LOW
70+
// This will stall the 6502 while we Initialize
71+
72+
pinMode(RESETPIN, OUTPUT);
73+
digitalWrite(RESETPIN,LOW); // Bring the RESET LOW to get the 6502
74+
// in a reset state
4475

4576
// Set all pins to their initial state.
4677
#ifdef DEBUG
4778
delay(2000);
4879
#ifdef RAMEMU
4980
Serial.print("RAM Emulation\n");
5081
#endif
51-
5282
#ifdef ROMEMU
5383
Serial.print("ROM Emulation\n");
5484
#endif
55-
5685
#ifdef ACIA6551
5786
Serial.print("6551 ACIA Emulation\n");
5887
#endif
59-
6088
#ifdef ACIA6850
6189
Serial.print("6850 ACIA Emulation\n");
6290
#endif
63-
91+
#ifdef BARECPU
92+
Serial.print("CPU Only\n");
93+
#endif
6494
Serial.print("Initializing PINs\n");
65-
#endif
95+
#endif
96+
97+
// Initialize Data and Address BUSs to Input
98+
6699
for (int i=0;i<8;i++) {
67100
pinMode(dataPins[i],INPUT); //Ensure we're not writing to the Bus
68101
pinMode(addressLPins[i],INPUT_PULLDOWN);
69102
pinMode(addressHPins[i],INPUT_PULLDOWN);
70103
}
71104

105+
// Initialize R/W' and PHI2
106+
72107
pinMode(RWPIN, INPUT);
73108
pinMode(CLOCKPIN, OUTPUT);
74-
pinMode(RESETPIN, OUTPUT);
109+
110+
// With a bare CPU we need to drive these pins high.
111+
// And SO LOW
112+
// On a real SBC, this should be done by the circuit.
113+
114+
#ifdef BARECPU
115+
pinMode(BEPIN, OUTPUT);
116+
pinMode(RDYPIN, OUTPUT);
117+
pinMode(NMIPIN, OUTPUT);
118+
pinMode(IRQPIN, OUTPUT);
119+
pinMode(MLPIN, INPUT);
120+
pinMode(VPPIN, INPUT);
121+
pinMode(SYNCPIN, INPUT);
122+
pinMode(SOPIN,OUTPUT);
123+
digitalWrite(BEPIN,HIGH);
124+
digitalWrite(RDYPIN,HIGH);
125+
digitalWrite(IRQPIN,HIGH);
126+
digitalWrite(NMIPIN,HIGH);
127+
digitalWrite(SOPIN,LOW);
128+
#endif
129+
130+
// With a CPU on its own circuit we just want to read what happens.
131+
132+
#ifndef BARECPU
133+
pinMode(BEPIN, INPUT);
134+
pinMode(RDYPIN, INPUT);
135+
pinMode(NMIPIN, INPUT);
136+
pinMode(IRQPIN, INPUT);
137+
#endif
75138

76139
#ifdef DEBUG
77-
Serial.print("Initializing varialbles\n");
140+
Serial.print("Initializing variables\n");
78141
#endif
79142

80143
// Initialize some variables
@@ -83,13 +146,9 @@ void setup() {
83146
chipEnable=0x0;
84147
rw=true;
85148

86-
#ifdef DEBUG
87-
Serial.print("Bringing RESET LOW\n");
88-
#endif
89149

90-
digitalWrite(RESETPIN,LOW); // Bring the RESET LOW to get the 6502
91-
// in a reset state
92-
150+
151+
93152
#ifdef RAMEMU
94153
#ifdef DEBUG
95154
Serial.print("Initializing RAM\n");
@@ -104,20 +163,30 @@ void setup() {
104163
#endif
105164

106165
digitalWrite(RESETPIN,HIGH); // Release RESET and start working
107-
108-
Serial.print("Starting SBC....\n");
166+
Serial.print("Starting Teensy 65C02....\n");
109167
}
110168

111169

112170
void loop(){
113171

114-
GPIOA_PDOR &=0x0000; // Bring Clock LOW to start Phase 1
115-
for (i=0; i< WAITCYCLE; i++){} // Keep Phase 1 LOW
172+
173+
// Start the loop by bring Clock low and up again
174+
// Duration of PHI1 (Clock low) is defined by WAITCYCLE
175+
176+
GPIOA_PDOR &=~(1<<13); // Bring Clock LOW to start Phase 1
177+
// Clock is on PIN 13 of PORT A
178+
179+
for (i=0; i< WAITCYCLE; i++){} // Keep Phase 1 LOW for WAITCYCLES
180+
116181
GPIOA_PDOR |=1<<13; // Bring Clock HIGH to start Phase 2
117182

183+
// Read the Address BUSs
118184

119185
addressL = GPIOC_PDIR; // Read the Address Bus Low byte
120186
addressH = GPIOB_PDIR; // Read the Address Bus High byte
187+
188+
// PORT B doesn't have 4 consecutive Pins so we need to concatenate
189+
121190
addressH |= (GPIOB_PDIR >> 12) & 0xF0; // Shift the register right by 12 bits
122191
// to get bits 16,17,18 and 19
123192
// in position 4,5,6 and 7.
@@ -129,27 +198,32 @@ void loop(){
129198
savedaddress=address; // Saving original address for DEBUG as it's modified for ROM access.
130199
#endif
131200

201+
// Address decoding
202+
132203
if (address < RAMSIZE) {
133204
chipEnable=RAMENABLE;
134205
} else if (address >= ROMADDRESS) {
135206
chipEnable=ROMENABLE;
136207
} else if (address >= ACIADDRESS) {
137208
chipEnable=ACIAENABLE;
138209
}
210+
211+
139212
rw=(GPIOA_PDIR>>12)&0x1; // Check if it's a Write Cycle
140213
// or Read Cycle
214+
215+
// If it's a READ Cycle, we need to reconfigure DATA Pins to OUTPUT
141216
GPIOD_PDDR=(rw) ? GPIOOUTPUT : GPIOINPUT; // Configure PIN direction.
142217

143218

144-
219+
// Based on Address decoding, now is time to taje appropriate actions.
145220
switch (chipEnable) {
146221

147-
148-
#if defined ACIA6551 || defined ACIA6850
222+
#if defined ACIA6551 || defined ACIA6850
149223
case ACIAENABLE:
150224
if (rw) {
151225
if (address == ACIADATA){ // CPU wants to get data
152-
GPIOD_PDOR=Serial.read() ; // Send what's in buffer (CPU should have checked buffer ia not empty)
226+
GPIOD_PDOR=Serial.read() ; // Send what's in buffer (CPU should have checked buffer is not empty)
153227
} else if (address == ACIASTATUS) { // CPU Wants to check buffer status
154228
GPIOD_PDOR=(Serial.available()>0) ? (RDRFBIT | TDREBIT) : TDREBIT; // We only check if read buffer is empty.
155229
}
@@ -160,7 +234,7 @@ void loop(){
160234
// We simply ignore the case where we receive config /Control/Reset byte for ACIA.
161235
}
162236
break;
163-
#endif
237+
#endif
164238

165239

166240
#ifdef ROMEMU
@@ -184,6 +258,7 @@ void loop(){
184258
}
185259
#ifdef DEBUG
186260
databyte=(rw) ? GPIOD_PDOR : GPIOD_PDIR;
261+
187262
Serial.print(savedaddress,HEX);
188263
Serial.print("\t");
189264
Serial.print(rw);

README.md

+16-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# SBC (for Teensy 3.6)
22

3-
This codes uses a Teensy to emulate hardware of a **6502** based computer apart from CPU itself.
3+
This codes uses a Teensy to emulate hardware of a **65C02** based computer apart from CPU itself.
44
The following parts can be emulated :
55

66
- Clock (mandatory)
@@ -24,7 +24,7 @@ Edit `SBC.h` and `#define` which part are to be emulated by commenting out the u
2424
> 3. If you emulate a component, make sure a real IC is not actually connected, as both Teensy and the IC will put data on the bus at the same time !
2525
2626
### ROM configuration
27-
If you emulate a ROM, provide it as a C Array in a file called `rom.h`. Two ROMs are provided here:
27+
If you emulate a ROM, provide it as a C Array in a file called `rom.h`. Three ROMs are provided here:
2828

2929
1. **OSI Basic ROM** (rom.h.OSI)
3030
- Uses a 6850.
@@ -38,11 +38,24 @@ If you emulate a ROM, provide it as a C Array in a file called `rom.h`. Two ROMs
3838
- ACIADDRESS: 0xA000
3939
- ROMADDRESS: 0xB000
4040

41+
3. **Java6502** (rom.h)
42+
My own ROM using Microsoft Basic 2
43+
- RAMSIZE(max): 0xC000
44+
- ACIADDRESS: 0xC100
45+
- ROMADDRESS: 0xD000
46+
4147
You can replace with your own ROM, using srec_cat to generate the C Array. See my [ROM Software repo](https://github.com/olivierjan/ROM-software-for-6502-SBC) for more details.
4248

4349
The code is very basic but is meant to help debug a hombrew computer. It can be greatly optimised and I will try to add new features over time (usable debugging, support for VIAs and other components, etc...).
4450

45-
**WARNING:** Teensy 3.6 is only 3.3v and will provide power to the whole circuit. A 5V version should be possible using Teensy 3.5 but I haven't tested yet.
51+
**WARNING:** Teensy 3.6 is only 3.3v and will provide power to the whole circuit. A 5V version should be possible using Teensy 3.5 but I can't get this to work on Teensy 3.5 at the moment.
52+
53+
### PCB Board
54+
A PCB to host the Teensy and the 65C02 is provided, I designed it using EasyEDA and ordered it from JLCPCB.
55+
I provided the design here in Altium and Gerber format, but haven't tested these, only the EasyEDA.
56+
57+
The PCB can be plugged in an existing circuit, and you can choose to power the circuit from Teensy or not using the jumper.
58+
4659

4760
Any comments welcome !
4861

SBC.h

+39-15
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,29 @@
1-
/*
2-
Bus Access system
3-
Access 65C02 address and databus on 24 Teensy Pins
4-
Start simulate some memory for 65c02 to Read/Write.
5-
*/
1+
//
2+
// TEENSY 65C02
3+
//
4+
// Access 65C02 address and databus using Teensy 3.6(3.3v) or 3.5 (5v)
5+
// Can simulate RAM, ROM and ACIA (6551 or 6850)
6+
// Provide access to all pins.
67

78

8-
//#define DEBUG
9-
#define ACIA6551 // Model of ACIA to emulate
9+
10+
//#define DEBUG 0
11+
#define ACIA6551 1 // Model of ACIA to emulate
12+
1013
//#define ACIA6850 // 6850 or 6551
11-
#define ROMEMU // Do we emulate RAM or is it a real chip ?
14+
//#define ROMEMU // Do we emulate RAM or is it a real chip ?
1215
//#define RAMEMU // Do we emulate ROM or is it a real chip ?
16+
#define BARECPU 1 // Are we just using the 65C02 ?
17+
18+
#ifdef BARECPU
19+
#ifndef ROMEMU
20+
#define ROMEMU 1
21+
#endif
22+
#ifndef RAMEMU
23+
#define RAMEMU 1
24+
#endif
25+
#endif
26+
1327

1428
// For the time being, memory map is :
1529
// 0x0000 - (RAMSIZE-1): RAM
@@ -18,9 +32,9 @@ Start simulate some memory for 65c02 to Read/Write.
1832
// Make sure you provide right values below, even if the component is not emulated
1933

2034

21-
#define RAMSIZE 0xA000 // Size of RAM to emulate
22-
#define ACIADDRESS 0xA000 // Base address of Serial Device
23-
#define ROMADDRESS 0xB000 // Base address of ROM Data
35+
#define RAMSIZE 0xC000 // Size of RAM to emulate
36+
#define ACIADDRESS 0xC100 // Base address of Serial Device
37+
#define ROMADDRESS 0xD000 // Base address of ROM Data
2438
// make sure your ROM fit as there is nocheck.
2539
// if the ROM is too big some of it won't be reachable with 16bits addresses
2640

@@ -42,13 +56,23 @@ Start simulate some memory for 65c02 to Read/Write.
4256
#define ACIASTATUS ACIADDRESS
4357
#endif
4458

45-
#define WAITCYCLE 5 // How long do we wante Phase 1 to be.
59+
#define WAITCYCLE 1 // How long do we wante Phase 1 to be.
4660

4761
// PIN definitions
4862

49-
#define RWPIN 3 // Read/Write' signal
50-
#define CLOCKPIN 4 // Clock generation
51-
#define RESETPIN 33 // Reset signal
63+
#define RWPIN 3 // Read/Write' signal
64+
#define CLOCKPIN 4 // Clock generation
65+
#define RESETPIN 33 // Reset signal
66+
#define BEPIN 24
67+
#define RDYPIN 34
68+
#define IRQPIN 27
69+
#define NMIPIN 26
70+
#define MLPIN 31
71+
#define SYNCPIN 32
72+
#define VPPIN 36
73+
#define SOPIN 35
74+
75+
// #define SOPIN
5276

5377
#define GPIOOUTPUT 0xFF // Value to configure Pins for Output
5478
#define GPIOINPUT 0x00 // Value to configure Pins for Input

0 commit comments

Comments
 (0)