Page 1 of 1
Programming the 6502
Posted: Sun Nov 16, 2003 9:04 pm
by Daniel_kendell
Hi,
My name is Daniel and I am trying to build a 6502 based sbc. I seem to be (theoreticly) doing rather well with the hardware. But I have a problem and that is that I haven't got any idea how to program it!
(note: I like to use theories, I won't actually do something unless it is theoreticly workable. My hardware is, but as it has no program it won't do anything so I haven't constructed it yet.)
How do I progam it?
I want to use EPROMs to store the program. However, my problems are thus:
1.) I don't know assembly with the exception of LDA and STA
2.) Once I have an assembly program, how would I write it to the EPROM? - Note, if I need a PC programmer, I would go looking for schemetics for a home made one as I can't afford a 'proper' one.
Does anyone have time to spare to teach me some basics?
How can I make decisions in assembly? For example:
Does 8000h = 00000001 ?
If yes then 8001 = 00000010
If no then 8001 = 00000100
can anyone translate that into Assembly? (As you may have been able to see, I a comfortable and used to BBC Basic/QBasic)
I will have a look at EhBasic but from what I saw last, that confused me even more!
Thanks a lot,
Dan
Posted: Sun Nov 16, 2003 11:39 pm
by orac
Hi Daniel,
You bring up some very good questions. However it would take quite a few posts to give a good explanation.
Try and find a vintage book on 6800/6502/8080/Z80 assembly language from the 1970's. These books typically give a great introduction to the world of binary arithmatic, hex notation, EPROM memory cells and the like. Goto the "book section" of 6502.org for some suggestions.
From there you could practice a little assembly using a 6502 simulator on the PC. Once you get a feel for simple assembly language programs in the simulator, you could try buring an EPROM for your 6502 SBC.
EEPROM's are actually easier to use than EPROM's because EEPROM's can
be erased without an ultraviolet light eraser. EEPROM's are generally slower, but they are plenty fast for a 1/2Mhz 6502.
Cheers,
Paul
Posted: Mon Nov 17, 2003 3:31 am
by GARTHWILSON
As Paul says, it would take a lot to fully explain all these things, but I'll give a start, and you might decide to follow it up with more questions.
Today a fraction of a percent of computer users do any programming. They're just appliance operators. Contrast that to 20-25 years ago when almost everyone buying a computer expected to do some programming of one sort or other. If you're on such a tight budget, get the programming manual that went with any of the 6502 computers from the early days of home computers, whether it be the Commodore 64, Apple II, AIM-65, or other one. If you don't already have such a book or know someone who has one in a box in the garage, you could probably get one from a used book store for a couple of bucks. The title will usually have something about "Assembly Language" or "Machine Language" in it to diferentiate from BASIC. The older books won't have all the extra CMOS instructions and addressing modes, but you will probably be able to understand most of those well enough from a simple CMOS op code chart once you get the hang of how the original instructions worked, what registers the processor has, what the various addressing modes do, how many bytes the various instructions take, etc..
Once you understand these things, you'll be able to assemble (translate assembly language into machine language) by hand. Hand-assembly is only suitable for beginning, when your code is short and you don't need to do much changing of jump addresses or relative branch distances, variable addresses, etc. as you modify and expand your code. Still, many of us started this way.
Any EPROM programmer you make will also require appropriate software to run it, unless it it hand-operated. The latter is not out of the question (my first EPROM programmer was hand-operated), but it is very slow, and worse, very prone to human error. Several distributors have programmers to use with your PC for under $200. I think my ERPOM eraser was $40 at Jameco.
The decisions in assembly are done based on flags in the processor status register P. For example, an operation may set or clear the C (carry) flag, and you follow it up with a BCC (Branch on Carry Clear) or BCS (Branch on Carry Set) instruction. The operand for the instruction tells how far to branch and in which direction.
There are several ways you could write your little program in assembly. If I correctly understand what you want, one way would be:
Code: Select all
LDX #1 ; Put a 1 in the X register.
CPX $8000 ; Compare it to what's in address 8000.
BEQ label_1 ; If it's equal (Zero flag set), then branch.
LDX #3 ; Put 3 here instead of 4 to avoid a branch around the INX.
label_1: INX ; Increment the 1 to a 2 or the 3 to a 4,
STX $8001 ; and put the result in 8001
If address 8000 contained 1, the whole thing will take 15 clocks, meaning 15 microseconds if you're running at only 1MHz. If 8000 did not contain 1, it would take 16 clocks. I normally would have used the accumulator (A) instead of X, but you won't have an increment-accumulator instruction if you have an NMOS 6502. INC A (or INA) came with the CMOS versions.
If you can afford about $60, I strongly recommend (and that's an understatement) WDC's book, "Programming the 65816 Including the 6502, 65c02, and 65802".
Garth
Posted: Mon Nov 17, 2003 7:03 am
by Nightmaretony
One sugestion I would have is copy, copy copy. There is a GREAT wealth of information here from some great folks who share their knowledge. Part of my own SBC is based on a memory addressing scheme from Darryl Rictor, but modified for some other needs. His page includes schematics on a great SBC type unit. For my other hardware references, arcade game schematics helped out.
For the software side, there is always good code. Garth, I still owe you lunch, Lee and Darryl, you both have fantastic and fun code, and it all served as reference towards making my own SBC working out.
PROGRESS: Garth, will find the time and place and once again, sthanks for putting up with all my questions. The selft test is now running the entire cycle. Sadly, I think the 6522 is not capable of the bit walk stunt that Ed Khrysky used for the 6532 testings. Right now, I am working on cracking some pinball machine code towards a better understanding of how it all works. That will help towards my own pinball design projects.
Code: Select all
WriteIndividualLight:
STX z44 ; This saves off the AXY registers.
STY z45
STA z26 ; Original A, will be used.
WriteIndividualLight1:
AND #$3F ; Strips off the 2 hi bits
LDX #$03
JSR e2389 ; Massage the light # for the routines below.
LDA BitLookupTable01,Y
LDY z65
BEQ WriteIndividualLight2
RTS ; Don't do anything, just go back, cause the
; light is going to stay the same.
WriteIndividualLight2: ; This is where the light fun begins.
BIT z26 ; original A value
BMI TurnONIndividualLight
BVS ToggleIndividualLight
TurnOFFIndividualLight:
EOR #$FF
AND LightMemoryArray,X
BNE WriteIndividualLight3
ToggleIndividualLight:
EOR LightMemoryArray,X
BNE WriteIndividualLight3
TurnONIndividualLight:
ORA LightMemoryArray,X
WriteIndividualLight3:
STA LightMemoryArray,X
TAY
AND #$0F
STA SLRW_OP_B ; Solonoids/Lamps R/W Output Register B
STY SLRW_OP_B ; Solonoids/Lamps R/W Output Register B
LDX z44
LDY z45
RTS
This is the code for turning off and on individual playfield lights. I personally find the code to be a little bizarre, but thats because I think that the flag selection for turning off and on or gtoggling is a tad uinclear to me.
On the hardware side, the Light MemoryArray is about 12 bytes of RAM which hold the lamp data. Each location holds a 4 bit nibble to light 4 lights, and eahc location corresponds to an enable line for each light latch wihch is 4 bit, so this system can handle 48 lamps this way. I am still working on clearing up how it inputs the data and the flagwork, but I will get there

.
So if you are wondering, this is code fro an arcade game whihc is 6502 based. Lots of fun for the week, methinks
Anyhoo, the important thing is Daniel, get all the reference you can handle, print out and read read read.....
Posted: Mon Nov 17, 2003 9:46 am
by Daniel_kendell
Paul,
I did consider using EEPROMs, especially for some kind of storage system. But unfortunately, every EEPROM I find is Serial EEPROM and that is not what I want...all the PROM types that I do want (non serial ones, parallel?) are EPROMs.
I live in the UK and the only suppliers I know of are Maplin and Rapid. However if you know of a store in the US that sells what I and will deliver to UK mainland then could you give me the address?
Garth,
Thanks for that! I actually understand that! Now I can have a play with that and mess about with it until I have learned something new! Tis how I learned HTML, just poking in other sites sources, that was about a year ago and now I am considered to be a "quali'y" HTML-er by people I know!
I shall have a lookie at Jamaco, Mapiln are selling EEPROM programmers at £250 - £300!
I am also pretty closely tied in with the old BBC Micro commmunity on the internet, they used 6502s in the, BBC and Master series of computers, probably more. So I am sure I can get some books off someone.
Thanks I will probably have a million more questions soon enough.
Dan
BTW, I was absolutly amased at the speed of the responses! This is what I like about being in a 'minority' computer user group (Apple Mac, Acorn, BBC Micros and here) is that the majority of people are nice, friendly people and there is a sense of sharing the wealth of knowlege that the community has to offer. Every time I post a message on a windows list or forum all I get is abuse! I shant name names or the forum.
Posted: Mon Nov 17, 2003 12:42 pm
by Daniel_kendell
Garth,
I have been playing with your code a bit. Would this work?
Code: Select all
LDA $00 ; Load 00h into accumulator
STA $8002 ; Store it in Data direction register 0 of 6522 making all inputs
LDA #FF ; Load FFh into accumulator
STA $8003 ; Store it in Data direction register 1 of 6522 making all outputs
LDX #1 ; Load $1 into X register
CPX $8000 ; Compare X register with Data register 0 of 6522
BEQ does_equal ; If they are both 1h then goto 'does_equal'
LDX #1 ; Load X register with 1h
STX $8001 ; Store it in Data register 1 of 6522 (turning pin 1 on)
JMP $E010 ; Goto beginning or ROM
does_equal: LDX #2 ; Load X register with 2h
STX $8001 ; Store it in Data register 1 of 6522 (turning pin 1+2 on)
JMP $E010 ; Goto beginning or ROM
I couldn't understand what
Code: Select all
LDX #3 ; Put 3 here instead of 4 to avoid a branch around the INX.
or
Code: Select all
INX ; Increment the 1 to a 2 or the 3 to a 4,
was for, could you explain that bit for me?
Anyway, Am I starting to get the basic idea?
Next: Look for Mac 6502 emulator.
Dan
Posted: Mon Nov 17, 2003 4:53 pm
by orac
Hi Dan,
Thanks for the tip about Maplin and Rapid. I added them to my list
of companies.
Go to:
http://www.farnell.com/
They have a UK button to push. After you push it, search on 28C64 and
you will find an 8K EEPROM.
Since they have a button for UK, I would assume that they sell in the UK.
Cheers,
Paul
Posted: Mon Nov 17, 2003 9:07 pm
by GARTHWILSON
Your first line LDA $00 will put the content of address 0000 into the accumulator. What you want is to use the # sign meaning "immediate" so it puts 00 there instead of the content of address 0000. If you have a 65c02 (CMOS) however, you can skip the LDA and do an STZ $8002 (STore Zero). I might point out too that the VIA comes out of reset with the port bits all set as inputs anyway, so you may be able to completely skip this step in some situations.
Right after your BEQ, you have the LDX #1 again, but nothing has changed X since the previous LDX #1 so it's redundant. And after your first JMP, the LDX #2 could be shortened to INX (INcrement X), to increment from the 1 that was previously there, to 2. It will take 2 clocks either way, but the INX is one byte shorter than LDX #2.
My INX was just to shorten the code. You wanted to store either %00000010 or %00000100 (2 or 4), so to set it up so you can quickly increment from a 1 (which was already there) to a 2, or from 3 to 4, saved having to make the first option branch around the code for the second one when done. When you get some experience with it, you'll begin to see ways like this to write code that's much shorter and faster, and in most cases (but not all), clearer than the way you did it when you were new to it.
To improve the readability of the code and not have to change tons of lines after a small change in addresses (like if you had a reason to change the address decoding and put your VIA at a different address), you should not use actual numbers so much. Replace them with names like DDRB (Data Direction Register B), and let the assembler substitute in the right number from your constant DDRB. "DDRB" might seem cryptic at first, but you'll probably be using the 6522 a lot so the various registers will become very familiar-- PB (Port B), PA (Port A), T1CL (Timer 1 Counter Low byte), T1CH (Timer 1 Counter High byte), SR (shift register), ACR (Auxiliary Control Register), etc.. These abreviations are pretty much straight out of one of my data books so I know I'm not the only one using them.
Then if you still use LDX #2, maybe you can replace the 2 with a descriptive constant name that tells you what it's for. For example, if that turns on LED number 2, you can put LDX #LED_2. If after making a prototype and getting it working you find out when you're laying out a PC board that it's a challenge to route and you can save the day by swapping a couple of LED positions, you might want to change your code later so LED#2 has a value of 4 and LED#3 has a value of 2. You can change it in two lines of your constants in the code, and the assembler will fix everything else without your having to find and manually change every line that references those two LEDs.
To answer your last question, yes, it looks like you're getting the basic idea.
Garth
Posted: Tue Nov 18, 2003 6:40 pm
by 8BIT
Dan,
Try this link:
http://www.geocities.com/oneelkruns/65index.html
I found it on the 6502.org website. There are some useful descriptions of the 6502's registers, flags, opcodes and addressing modes.
Good Luck!
Daryl
http://65c02.tripod.com/
uip
Posted: Tue Feb 24, 2004 7:35 am
by liuliu791030
i think that use Uip include 6502.h,
and my chip is the 2204 of sitrornix.modify the code of UIP?
Posted: Tue Mar 02, 2004 9:12 am
by BitWise
I have a reference section for the 6502 on my web site with some more examples of coding and a few tools.
You can find it at
http://www.obelisk.demon.co.uk/6502
help me!
Posted: Thu Mar 04, 2004 3:17 am
by liuliu791030
this is 2204.h about 6502 , will i use in uIP?
////////////////////////////////////////////////////////////
sfr PA = 0x00; /* R/W PA[0-7] 1111 1111 */
sfr PB = 0x01; /* R/W PB[0-7] 1111 1111 */
sfr PC = 0x02; /* R/W PC[0-7] 1111 1111 */
sfr PD = 0x03; /* R/W PD[0-7] */
sfr PE = 0x04; /* R/W PE[0-7] */
sfr PSC = 0x05;
sfr PCA = 0x08; /* R/W PCA[0-7] 0000 0000 PORT A DIRECTION Control.*/
sfr PCB = 0x09; /* R/W PCB[0-7] 0000 0000 PORT B DIRECTION Control.*/
sfr PCC = 0x0A; /* R/W PCC[0-7] 0000 0000 PORT C DIRECTION Control.*/
sfr PCD = 0x0B; /* R/W PCD[0-7] 0000 0000 PORT D DIRECTION Control.*/
sfr PCE = 0x0C; /* R/W PCE[0-7] 0000 0000 PORT E DIRECTION Control.*/
sfr PFC = 0x0D; /* R/W PFC[0-7] 0000 0000 */
sfr PFD = 0x0E; /* R/W PFD[0-7] 0000 0000 */
sfr PMCR = 0x0F; /* R/W PULL PDBN INTEG - - - PSGO PSGB 100- --00 */
sfr PSG0L = 0x10; /* W PSG0L[0-7] 0000 0000 */
sfr PSG0H = 0x11; /* W PSG0H[0-7] ---- 0000 */
sfr PSG1L = 0x12; /* W PSG1L[0-7] 0000 0000 */
sfr PSG1H = 0x13; /* W PSG1H[0-7] 0000 0000 */
sfr DAC = 0x14; /* W DAC[0-7] 0000 0000 */
sfr PSGC = 0x16; /* PSG CTRL/PWM DAC CTRL (DACE=0/1).*/
sfr VOL = 0x17; /* W VOL[0-7] 0000 0000 */
sfr BTEN = 0x20;
sfr BTSR = 0x21;
sfr PRS = 0x23; /* R PRS[0-7] 0000 0000 PRESCALER.*/
sfr T0M = 0x24; /* R/W --00 -000 TIMER 0 MODE Control.*/
sfr T0C = 0x25; /* R/W T0C[0-7] 0000 0000 TIMER 0.*/
sfr T1M = 0x26; /* R/W ---0 0000 TIMER 1 MODE Control.*/
sfr T1C = 0x27; /* R/W T1C[0-7] 0000 0000 TIMER 1.*/
sfr DMSL = 0x28; /* DMA SOURCE Register LO BYTE. */
sfr DMSH = 0x29; /* Hi BYTE. */
sfr DMDL = 0x2A; /* DMA DESITINATION Register LO BYTE.*/
sfr DMDH = 0x2B; /* Hi BYTE.*/
sfr DCNTL = 0x2C; /* DMA COUNTER LO BYTE.*/
sfr DCNTH = 0x2D; /* Hi BYTE.*/
sfr SYS = 0x30; /* R/W SYSTEM Control. 0000 00-- */
sfr IRRL = 0x31; /* INTERRUPT BANK Register */
sfr PRRL = 0x32; /* PROGRAM ROM BANK Register.*/
sfr PRRH = 0x33;
sfr DRRL = 0x34; /* DATA ROM BANK Register.*/
sfr DRRH = 0x35;
sfr DMRL = 0x36; /* DMA MEMORY BANK Register.*/
sfr DMRH = 0x37;
sfr MISC = 0x38; /* WATCH-DOG Register.*/
sfr IREQL = 0x3C; /* INTERRUPT REQUEST Register*/
sfr IREQH = 0x3D;
sfr IENAL = 0x3E; /* INTERRUPT ENABLE Register*/
sfr IENAH = 0x3F;
sfr LSSAL = 0x40; /* LCD SCREEN STARTING ADDRESS Register */
sfr LSSAH = 0x41;
sfr LVPW = 0x42; /* LCD VIRTUAL PAGE WIDTH Register */
sfr LXMAX = 0x43; /* LCD SCREEN WIDTH Register */
sfr LYMAX = 0x44; /* LCD SCREEN HEIGHT Register */
sfr LPAN = 0x45; /* LCD PANNING OFFSET Register */
sfr LCTR = 0x47; /* LCD Control Register */
sfr LCKR = 0x48; /* LCD Clock Control Register */
sfr LFRA = 0x49; /* LCD FRAME RATE ADJUST Register */
sfr LAC = 0x4A; /* LCD AC SIGNAL RATE Register */
sfr LPWM = 0x4B; /* LCD PWM CONTRAST Control Register */
sfr PL = 0x4C; /* PL DATA Register */
sfr PCL = 0x4E; /* PL Control Register */
sfr SDATAL= 0x50; /* SPI Data Registers */
sfr SDATAH= 0x51;
sfr SCTR = 0x52; /* SPI Control Register */
sfr SCKR = 0x53; /* SPI Clock Control Register */
sfr SSR = 0x54; /* SPI Status Register */
sfr UCTR = 0x60; /* UART Control Register */
sfr USTR = 0x61; /* UART Status Control Register */
sfr IRCTR = 0x62; /* IrDA Control Register */
sfr BCTR = 0x63; /* BGR Control Register */
sfr UDATA = 0x64; /* UART Data Register */
sfr BRS = 0x66; /* BGR Configuration Registers(BGR=baud rate generator) */
sfr BDIV = 0x67; /* BGR Divider control register */