ERIC-1: My homebrew computer project

Building your first 6502-based project? We'll help you get started here.
phvic
Posts: 36
Joined: 22 Nov 2014

ERIC-1: My homebrew computer project

Post by phvic »

I've been building my first 6502 based computer for a few nights and the project has been progressing nicely. I can now blink a LED :)

You can find a write up with schematics and pictures on my blog:
http://petenpaja.blogspot.fi/2014/11/er ... art-1.html

I think the design could be somewhat simplified. At least the BE pin of a WDC 6502 would help in getting rid of the two buffer chips on the address lines. And I think routing the R/W and phi2 clock through the third buffer chip could be avoided... maybe.

Next I'm going to start working on composite video signal generation. I'll be using the ATMega1284P for that.
mstram
Posts: 39
Joined: 26 Dec 2009

Re: ERIC-1: My homebrew computer project

Post by mstram »

Minor typo :
>address from $FFFD - $FFFD ( s.b. $FFFC - $FFFD

>The reset signal must be clean, rise quickly and be properly debounced.

I'm interested in the details of how you're doing that. Can you show your clocking and reset firmware code?

I am not going to try to build it, I just like to learn how things work
phvic
Posts: 36
Joined: 22 Nov 2014

Re: ERIC-1: My homebrew computer project

Post by phvic »

Thank you for reading!

Reset signal is actually really simple. When the microcontroller starts it pulls the reset line of 6502 down, waits for 100ms and then pulls it up. When I want to reset the computer, I reset the microcontroller (I can just pull its reset line down with a button) and it will reset the 6502.

Code: Select all

void reset6502() {
	PORTD &= ~CPU_RESET;	// reset low
	_delay_ms(100);	
	PORTD |= CPU_RESET;		// reset high
}
Clock generation is quite a bit more complicated. I'm using a hardware counter/timer feature of the ATMega1284P. The ATMega has a counter that counts from 0 to a 8-bit top value that I can specify. When the counter hits the top value an output pin is toggled and the counter is reset to zero. I can control the speed of the counter programmatically and start/stop the counting. Here is the relevant code:

Code: Select all

void initClock(uint8_t prescaler = 1, uint8_t top = 7) {
	// configure timer to count from 0 to OCR2A
	// when timer reaches OCR2A, OC2A connected to pin PD7 is toggled
	// this generates a square wave whose frequency is clk / (2 * N * (1 + OCR2A)), where clk = system clock frequency and N = timer prescaler

	OCR2A = top;						// clock freq = clk / (2 * 1 * (1 + 7)) = clk / 16 = 1 Mhz
	TCCR2A = _BV(COM2A0) | _BV(WGM21);	// set CTC mode, toggle OC2A on compare match, OC2B disabled
	TCCR2B = prescaler;					// low 3 bits select the timer prescaler (0, 1, 8, 32, 64, 128, 256, 1024)
	DDRD |= 0x80;						// set PD7 as output
}

	//initClock(1, 1);		// 4 Mhz
	//initClock(1, 3);		// 2 Mhz
	//initClock(1, 7);		// 1 Mhz
	//initClock(1, 15);		// 500 Khz
	initClock(1, 31);		// 250 Khz
To stop the clock in high state, I'm monitoring the state of the clock output pin and if it's 1 I stop the counter by setting it frequency to zero. When I later resume the timer it begins counting from the value it was at:

Code: Select all

// stop CPU clock in high state
void stopClock() {
	// wait for clock to go low
	while((PIND & CPU_CLOCK) != 0) {}
	// wait for clock to go high
	// must check that WE is high, otherwise CPU may be writing to memory
	while((PIND & (CPU_CLOCK|SRAM_WE)) == 0) {}
	TCCR2B = 0;	// stop timer by setting prescaler to 0
	TCCR2A = 0;	// disable timer so that we can control PD7 manually
}

// resume clock
void resumeClock(uint8_t prescaler = 1) {
	TCCR2A = _BV(COM2A0) | _BV(WGM21);
	TCCR2B = prescaler;
}
Klaus2m5
Posts: 442
Joined: 28 Jul 2012
Location: Wiesbaden, Germany

Re: ERIC-1: My homebrew computer project

Post by Klaus2m5 »

phvic wrote:
I think the design could be somewhat simplified. At least the BE pin of a WDC 6502 would help in getting rid of the two buffer chips on the address lines. And I think routing the R/W and phi2 clock through the third buffer chip could be avoided... maybe.
You could have the 6502 generate the memory addresses instead of disconnecting it. Just clocking through a bunch of injected NOPs on the databus will do the trick. You would still need a little bit of logic to disable OE or CS on the SRAM while the instruction (NOP) is fetched and inject WE when data is ready to be written to SRAM.
6502 sources on GitHub: https://github.com/Klaus2m5
User avatar
jac_goudsmit
Posts: 229
Joined: 23 Jun 2011
Location: Rancho Cucamonga, California
Contact:

Re: ERIC-1: My homebrew computer project

Post by jac_goudsmit »

phvic wrote:
I think the design could be somewhat simplified. At least the BE pin of a WDC 6502 would help in getting rid of the two buffer chips on the address lines.
Nice! Did you see my project at http://www.propeddle.com? It uses some of the same ideas as you had, but uses a Parallax Propeller to bitbang the 6502. I have some buffers in my project, but those are used to multiplex the address bus to the Propeller (I used other pins to generate video and connect to a PS/2 keyboard so I multiplex 16 pins between data bus, address bus and signals such as !NMI/!IRQ/RDY/!SO). I think for your design you could get rid of the buffers if you are willing to do some programming on the microcontroller to let the 6502 provide addresses (i.e. on the microcontroller, the address bus is always an input).

In my design(*), the Propeller doesn't have direct control over the address bus, but it does control the enable-lines on the memory chip and it can take control of the data bus. If I want to use the RAM chip as ROM, all I need is to keep the !WE (Write-Enable-Not) line high on the RAM chip. If I want to simulate an I/O device, I keep both !WE and !RD (ReaD-Not) high. In other cases, the !WE and !RD lines are activated during the second half of the clock cycle, depending on the R/!W line from the 6502.

To download data from the Propeller into the RAM (or to read data back from the RAM into the Propeller), the Propeller generates an NMI, to which the 6502 answers by reading the NMI vector at $FFFA/$FFFB. Instead of enabling the RAM chip for those addresses, I let the Propeller put the two bytes of a memory area on the data bus. The 6502 jumps to that address and starts executing, so it starts by putting the first address on the data bus, in read mode. During the first half cycle of CLK0, the 6502 never uses the data bus, so the Propeller can switch its data bus pins to OUTPUT mode and put some data on there, and enable the Write-Enable line on the memory chip to store that data into memory at the current address bus location. Then the Propeller disables the !WE pin again, takes the memory data off the data bus, puts a dummy instruction (I think it's CMP immediate) on the data bus, and makes the clock high so the 6502 reads the dummy instruction and executes it. Then the Program Counter in the 6502 increases by one, and the whole cycle repeats itself for the next memory byte. This continues until the Propeller feeds an RTI instruction to the 6502, and the 6502 restores the flags and continues where it left off. No registers (except the flags) are modified during the fake interrupt, and the 6502 is none the wiser: it just thinks it executed a lot of identical instructions, and doesn't realize that those instructions came from the Propeller, not from memory. And because the Propeller holds !NMI low the entire time, it's impossible for another NMI from another source to interrupt the process. And you can use the same process to read data from memory too.

Maybe this gives you some good ideas :-)

===Jac

(*) The idea to generate a fake interrupt and let the 6502 generate the addresses was originally by Dennis Ferron; I made some improvements, for example he used RESET and NOP. Others may also have thought about similar schemes so I don't think it's original in any way. Feel free to use it in your design, or not.
User avatar
BigDumbDinosaur
Posts: 9425
Joined: 28 May 2009
Location: Midwestern USA (JB Pritzker’s dystopia)
Contact:

Re: ERIC-1: My homebrew computer project

Post by BigDumbDinosaur »

jac_goudsmit wrote:
phvic wrote:
I think the design could be somewhat simplified. At least the BE pin of a WDC 6502 would help in getting rid of the two buffer chips on the address lines.
Nice! Did you see my project at http://www.propeddle.com?
I do recommend that you have a look at Jac's design. It's quite clever and may give you some inspiration with your own project.
x86?  We ain't got no x86.  We don't NEED no stinking x86!
phvic
Posts: 36
Joined: 22 Nov 2014

Re: ERIC-1: My homebrew computer project

Post by phvic »

Forcing the 6502 to generate the necessary addresses on the address bus is a really interesting idea! I need to think about this some more. I'm actually running quite low on available pins on the ATMega1284P so a trick like this might be what I need to do at some point.

The Parallax Propeller is an order of magnitude faster than the ATMega. I really have to fight hard and cycle count to get even black and white 320x256 PAL out of the ATMega. But I like the challenge! :)

I've been working on bitbanging the video signal for a few nights. This is what I got at the moment:
https://www.dropbox.com/s/2aj7a0j5jyyda ... t.JPG?dl=0

Unfortunately I've hit a major snag. I'm using ATMega's SPI hardware to output the pixels. It's the fastest method to gets bits out of the chip, achieving 8 MHz pixel clock, enough for 320x256, when the chip is clocked at 16 MHz. Unfortunately I've now found out the hard way that the SPI hardware cannot generate a gapless signal. After sending a byte, there is a small gap (1 pixel?) between pixels. This seems to be a AVR hardware limitation and there is no way to workaround this as far as I know..

Close up of the issue:
https://www.dropbox.com/s/0dst7zdmccuuc ... m.JPG?dl=0

It seems I will have to live with the artifact or make some major changes.
User avatar
jac_goudsmit
Posts: 229
Joined: 23 Jun 2011
Location: Rancho Cucamonga, California
Contact:

Re: ERIC-1: My homebrew computer project

Post by jac_goudsmit »

phvic wrote:
The Parallax Propeller is an order of magnitude faster than the ATMega. I really have to fight hard and cycle count to get even black and white 320x256 PAL out of the ATMega. But I like the challenge! :)
Even with the Propeller running at 80MHz or overclocked at 100MHz, getting the timing right was a difficult problem, especially with all that multiplexing, and multiple cogs (=cores) having to operate in sync to get to the buses at exactly the right time. I had to use a spreadsheet to get the timing exactly right.

Also, when I wanted to write an Apple-1 emulator, I ran out of cycles pretty quickly: with the 6502 running at 1MHz, and the Propeller at 80MHz, the Propeller simply doesn't have enough time to get the work of a simple chip like the PIA done in one cycle. Fortunately because I figured out that there's no way that the 6502 would read or write the same address twice in two successive clock cycles, I could cheat a little bit. The PIA emulation cog is ready to go on every 6502 cycle, and when the 6502 reads from or writes to the PIA addresses, it gets the information right away in the same clock cycle, but the PIA cog is actually doing "background work" during the next clock cycle.

As a short term side project, I'm working on a simplified version of Propeddle called L-Star, which consists only of the Propeller and the 6502 (and some peripheral chips such as the EEPROM and FTDI serial converter and power supply, but no RAM chip, and no glue logic). It's currently only capable of emulating the Apple-1 but it works great. There's no documentation yet but you can find it in my Github in the L-Star repository (no link here for now, because it's under development; you'll find it if you look for it). See the Hardware.spin file to find out how I connected the WDC65C02 to the Propeller, with only the address bus, data bus CLK0 and R/W pins. That leaves 7 pins on the Propeller that are used for a serial port, a PS/2 keyboard, a 1-pin monochrome TV output. The CLK0 pin is shared with the SCL pin on the I2C EEPROM from which the Propeller boots, and the SDA line to that EEPROM has to be kept high to keep the EEPROM from getting confused by the 1MHz clock on SCL. There's not even a pin available for the reset line (though a 1-pin PS/2 keyboard driver exists but I have plans with the "spare" keyboard clock pin), so I use a trick to simulate a RESET with a BRK instruction (which should work in most cases but is not guaranteed).

===Jac
Attachments
L-Star running the "30th anniversary demo" for Apple-1
L-Star running the "30th anniversary demo" for Apple-1
User avatar
BitWise
In Memoriam
Posts: 996
Joined: 02 Mar 2004
Location: Berkshire, UK
Contact:

Re: ERIC-1: My homebrew computer project

Post by BitWise »

phvic wrote:
Unfortunately I've hit a major snag. I'm using ATMega's SPI hardware to output the pixels. It's the fastest method to gets bits out of the chip, achieving 8 MHz pixel clock, enough for 320x256, when the chip is clocked at 16 MHz. Unfortunately I've now found out the hard way that the SPI hardware cannot generate a gapless signal. After sending a byte, there is a small gap (1 pixel?) between pixels. This seems to be a AVR hardware limitation and there is no way to workaround this as far as I know..
I had the same issue when I used a PIC18F to do the same thing. On the PIC24/33 and PIC32 I can be avoided using hardware DMA but then you can hit limits on maximum SPI transfer rates at high resolutions. In my current VT-220 design I just bit bash the signal.
Andrew Jacobs
6502 & PIC Stuff - http://www.obelisk.me.uk/
Cross-Platform 6502/65C02/65816 Macro Assembler - http://www.obelisk.me.uk/dev65/
Open Source Projects - https://github.com/andrew-jacobs
Klaus2m5
Posts: 442
Joined: 28 Jul 2012
Location: Wiesbaden, Germany

Re: ERIC-1: My homebrew computer project

Post by Klaus2m5 »

phvic wrote:
Unfortunately I've hit a major snag. I'm using ATMega's SPI hardware to output the pixels. It's the fastest method to gets bits out of the chip, achieving 8 MHz pixel clock, enough for 320x256, when the chip is clocked at 16 MHz. Unfortunately I've now found out the hard way that the SPI hardware cannot generate a gapless signal. After sending a byte, there is a small gap (1 pixel?) between pixels. This seems to be a AVR hardware limitation and there is no way to workaround this as far as I know..
Have you tried to use one of the USARTs in SPI mode? The USARTs have a buffered transmitter and should be able to generate a seamless bitstream.
6502 sources on GitHub: https://github.com/Klaus2m5
lordbubsy
Posts: 207
Joined: 11 Sep 2013
Location: The Netherlands

Re: ERIC-1: My homebrew computer project

Post by lordbubsy »

Great blog and project. I’m also using an ATMega1284P for the same tasks, except for the video generation.

Perhaps a very option, but the ATMega1284P can easily run at 24MHz, then you could run the 6502 at 1,5MHz or 3MHz. Of course this results in recalculate everything.
phvic
Posts: 36
Joined: 22 Nov 2014

Re: ERIC-1: My homebrew computer project

Post by phvic »

Thank you for the kind words and interest in my project!

I finally found a workaround for the gap between pixels! I can now generate a stable 400x256 signal (50x25 chars).

Full battle report on my blog:
http://petenpaja.blogspot.com/2014/12/e ... ignal.html

I also received my WDC 6502s in the mail from Coltek UK today. So I can upgrade my computer to ran at 8 Mhz and get rid of the address line 74HC541 buffers. 8 Mhz probably does not run robustly on a breadboard tho, but it's nice to have the option when I rebuild this on a PCB.

The nice thing about this design is that the video chip (the ATmega1284P) and the 6502 can run at their own clock rates, as long as the ATmega is able to generate the necessary clock frequency for the 6502.
Attachments
400x256 PAL, black and white for now, bit banged using USART in MSPI mode.
400x256 PAL, black and white for now, bit banged using USART in MSPI mode.
phvic
Posts: 36
Joined: 22 Nov 2014

Re: ERIC-1: My homebrew computer project

Post by phvic »

Klaus2m5 wrote:
phvic wrote:
Unfortunately I've hit a major snag. I'm using ATMega's SPI hardware to output the pixels. It's the fastest method to gets bits out of the chip, achieving 8 MHz pixel clock, enough for 320x256, when the chip is clocked at 16 MHz. Unfortunately I've now found out the hard way that the SPI hardware cannot generate a gapless signal. After sending a byte, there is a small gap (1 pixel?) between pixels. This seems to be a AVR hardware limitation and there is no way to workaround this as far as I know..
Have you tried to use one of the USARTs in SPI mode? The USARTs have a buffered transmitter and should be able to generate a seamless bitstream.
Oh, I wish I had noticed your response earlier. This is actually what I did, and it took me quite a while to figure it out! :)
phvic
Posts: 36
Joined: 22 Nov 2014

Re: ERIC-1: My homebrew computer project

Post by phvic »

What's the typical current drawn by a 6502 system? My computer is currently using 70mA and the 7805 working at 12V is already running too hot to touch… I think I need to add a heat sink soon.
User avatar
jac_goudsmit
Posts: 229
Joined: 23 Jun 2011
Location: Rancho Cucamonga, California
Contact:

Re: ERIC-1: My homebrew computer project

Post by jac_goudsmit »

phvic wrote:
What's the typical current drawn by a 6502 system? My computer is currently using 70mA and the 7805 working at 12V is already running too hot to touch… I think I need to add a heat sink soon.
The reason the 7805 gets hot is probably because you're making it work too hard, sinking 7V over 70mA is almost half a Watt. If you can, use a lower input voltage like 9V or 7.5V.

You can also replace the 7805 by an LDO regulator and use an ever lower input voltage.

Or you can use a switching regulator (there are many switching regulators that can be used as a drop-in replacement for the 7805: same package, same pinout) and generate even less heat, even at 12V input voltage.

===Jac
Post Reply