6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sat Sep 28, 2024 11:29 pm

All times are UTC




Post new topic Reply to topic  [ 46 posts ]  Go to page 1, 2, 3, 4  Next
Author Message
PostPosted: Sat Nov 29, 2014 11:35 am 
Offline

Joined: Sat Nov 22, 2014 6:49 pm
Posts: 36
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.


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 30, 2014 4:38 am 
Offline

Joined: Sat Dec 26, 2009 2:15 am
Posts: 39
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


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 30, 2014 8:36 am 
Offline

Joined: Sat Nov 22, 2014 6:49 pm
Posts: 36
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:
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:
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:
// 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;
}


Top
 Profile  
Reply with quote  
PostPosted: Sun Nov 30, 2014 10:24 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
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


Top
 Profile  
Reply with quote  
PostPosted: Mon Dec 01, 2014 8:29 pm 
Offline
User avatar

Joined: Thu Jun 23, 2011 2:12 am
Posts: 229
Location: Rancho Cucamonga, California
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 02, 2014 5:55 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8404
Location: Midwestern USA
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!


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 02, 2014 3:36 pm 
Offline

Joined: Sat Nov 22, 2014 6:49 pm
Posts: 36
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.


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 02, 2014 7:07 pm 
Offline
User avatar

Joined: Thu Jun 23, 2011 2:12 am
Posts: 229
Location: Rancho Cucamonga, California
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:
File comment: L-Star running the "30th anniversary demo" for Apple-1
2014-11-28 23.59.22.jpg
2014-11-28 23.59.22.jpg [ 3.49 MiB | Viewed 3914 times ]
Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 03, 2014 9:39 am 
Offline
User avatar

Joined: Tue Mar 02, 2004 8:55 am
Posts: 996
Location: Berkshire, UK
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


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 03, 2014 10:25 am 
Offline

Joined: Sat Jul 28, 2012 11:41 am
Posts: 442
Location: Wiesbaden, Germany
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


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 03, 2014 12:45 pm 
Offline

Joined: Wed Sep 11, 2013 8:43 pm
Posts: 207
Location: The Netherlands
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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 03, 2014 4:17 pm 
Offline

Joined: Sat Nov 22, 2014 6:49 pm
Posts: 36
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:
File comment: 400x256 PAL, black and white for now, bit banged using USART in MSPI mode.
usart_spi_400x256.jpg
usart_spi_400x256.jpg [ 815.13 KiB | Viewed 3863 times ]
Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 03, 2014 4:19 pm 
Offline

Joined: Sat Nov 22, 2014 6:49 pm
Posts: 36
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! :)


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 03, 2014 4:23 pm 
Offline

Joined: Sat Nov 22, 2014 6:49 pm
Posts: 36
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.


Top
 Profile  
Reply with quote  
PostPosted: Wed Dec 03, 2014 5:09 pm 
Offline
User avatar

Joined: Thu Jun 23, 2011 2:12 am
Posts: 229
Location: Rancho Cucamonga, California
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


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 46 posts ]  Go to page 1, 2, 3, 4  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 9 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: