6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Nov 24, 2024 7:21 pm

All times are UTC




Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Wed Mar 22, 2017 2:58 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
Ok, I downloaded the ACME assembler, and the Joe editor.

I'm trying to create the absolute simplest of assembly programs to both test my build, and test my understanding of the tool chain for programming.

I have books and online references on 6052 assembly, which I am going through. Good references all.

What I lack is an example of a complete text file that can be successfully assembled by ACME.

Here is what I want to do:

Write a simple program that "proves things work". Like maybe LDA a numerical constant , STA that constant in a specific memory location in RAM, LDA that same data from memory, and STA it on a VIA port. I'm super new at 6502 assembly;y, so hopefully even that came across right!

What I need is an example of the bare minimum that will assemble. Maybe those instructions are enough, but I feel I need some sort of boiler plate stuff to set things up maybe? Maybe not?

Can you tell I'm not even sure what to ask here?


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 3:24 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
False alarm :roll:

I got something to assemble. Didn't realize I had to set the program counter. Since I'm putting this thing in EEPROM for now, I just figured I put the instructions where I wanted them and that was that. Makes sense now.


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 3:36 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
actually, about that.

Why DO I have to give a specific program counter location? If I put the binary in ROM, isn't it at the specific address I burn it to no matter what I say in the code?

for instance, in order to get my code to assemble, I adde the line *=1000 at the beginning. But then I actually putt it at location 0000 in my eeprom . I didn't actually burn it, I just did this in the programmers software.

In imple terms, what is the purpose of the *= statement? I assume it's an assembler directive, and not an opcode, right?


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 4:05 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
Ok, I think I can clarify my questions a little.

Why does the ACME assembler give my an error unless I have a *= $(some address) at the beginning. Is this a neccesity of 6502 assembly, or ACME?

what does .ORG do specfically, and how come if I put , say, .ORG $4000 in my code, I get a "implicit label definition not in left most column" error.?

Is .ORG so that I don't have to place things by hand in specific EEPROM memory locations?


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 4:30 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
Although not specific to a particular assembler (as there are so many and I'm only familiar with a few), chapter 18 of the 6502 primer is "Program-Writing: Where Do I Start?" I'll try to improve it depending on what shows up in this topic.

It looks like your assembler uses *=<addr> to set the address origin of the subsequent code. Many other assemblers would use ORG or .ORG (for "origin"). This needs to be the address in the 6502's memory map, not the EEPROM. It might be 0000 in the EEPROM; but everywhere you have an address reference in the program, it would go to the wrong place, somewhere outside the EEPROM. For example, suppose you have a subroutine at $C314 in the memory map. You would call it with JSR <subroutine_name> which would assemble to 20 14 C3. Suppose the EEPROM's address 0 was at address C000 in your memory map, so $C314 would be at $0314 of the EEPROM. Now a call to that subroutine would send the processor to $0314—which is almost guaranteed to be in RAM instead of ROM and might contain almost anything, but not the subroutine you expected. The EEPROM programmer software has to subtract the right value to get the finished code into the EEPROM. You tell the EEPROM programmer software what address the EEPROM starts at. There could be several EEPROMs, especially back in the day when there weren't any to fit the whole job into one. In the automated test equipment I did 25+ years ago shown in my project pages on this site, there were four 8KB EPROMs IIRC, with sockets for up to six. (There were jumpers to select between EPROM and SRAM for each of the sockets, and then there was an 8KB segment for SRAM only and an 8KB segment for I/O.)

Remember also that pages 0 and 1 in the 6502 address map have special meaning, unlike a ROM's page 0 or 1. Both must be writable, so pages 0 and 1 have to have RAM in them, which is why there's never ROM at address 0.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 4:32 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
Dan Moos wrote:
Why DO I have to give a specific program counter location? If I put the binary in ROM, isn't it at the specific address I burn it to no matter what I say in the code?

An explanation might help.

My POC V1.1 has ROM from $00E000-$00FFFF. I use a 256Kb × 8 EPROM, whose internal addresses extend from $0000-$7FFF. In order for the ROM to appear at $00E000 in MPU address space, A0-A12 of the ROM are wired to A0-A12 of the MPU. The ROM's chip select is wired to the glue logic so it is asserted any time the address is $00E000-$00FFFF, that is, if A15-A13 is %111. That makes a byte at $0000 in the ROM appear at $00E000 in MPU address space, a byte at $0001 in the ROM appear at $00E001, etc. Hence the code that is to be burned into the ROM must be assembled with a starting address of $E000 in order for jump targets and static data references (e.g., text strings) to make sense to the MPU. If the code were assembled at $0000, none of the jump target addresses would be valid, since it is seeing the code at $00E000, not $0000. Ditto for static data references.

Hence when I assembled POC V1.1 firmware I use $00E000 as the starting address, using the assembler directive *= $00E000. The resulting object code is written into a binary file, starting at byte $00 in the file. The EPROM burner software loads that binary file into a buffer at $0000 and then into the EPROM starting at $0000.

Quote:
In imple (sic) terms, what is the purpose of the *= statement? I assume it's an assembler directive, and not an opcode, right?

The * = statement sets the program's origin so the assembler will know where to start assembly. In almost all assemblers, * refers to the current address at which instructions and data are being assembled. The need for this feature is due to the fact that many instructions refer to specific locations from which to load data, or to jump to (e.g., JSR SOME_SUBROUTINE). These absolute addresses are dependent on at what point assembly started, which you set with * =.

Quote:
Why does the ACME assembler give my an error unless I have a *= $(some address) at the beginning. Is this a neccesity of 6502 assembly, or ACME?

The assembler doesn't know at which address to start assembly unless you tell it. Hence the error.

Quote:
what does .ORG do specfically, and how come if I put , say, .ORG $4000 in my code, I get a "implicit label definition not in left most column" error.?

Some assemblers recognize .ORG as a synonym for * =. I'm not familiar with Acme, so I can't tell you why that error is occurring. It could be because Acme has some requirements on how fields are place in a line of code. As general rule, labels and symbols should start at the left-most column, and all other fields at least one column away from the left margin, e.g.,:

Code:
LABEL    = 12345               ;set LABEL to 12345
;
SYMBOL   LDA #LABEL            ;load accummulator with 12345

The above is the format that I have used for some 40 years.

Incidentally, it's helpful to know and use the correct terminology when discussing programming. The above is a simple example of an assembly language (not "assembly," which term refers to a process, or "assembler," which is a piece of software) program. The above code is called source code. You use an assembler to assemble (not "compile") your source code, resulting in the generation of object code. The object code may be machine-executable (i.e., machine code) or may be in a relocatable format that is subsequently processed by a linker to generate machine code. The machine code is what is loaded into memory (RAM or ROM) for the MPU to execute. Most 65C02 machine code is position-dependent, which means it can be run from only one location in memory without error. Position-independent code can be loaded into memory at any convenient location and will run without error.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 4:39 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
I see BDD posted while I was writing. I'll post anyway, then perhaps edit or augment.

Quote:
and how come if I put , say, .ORG $4000 in my code, I get a "implicit label definition not in left most column" error.?

The ORG or .ORG or *= assembler directive should not require a label on that line. But if something doesn't appear to be a assembly-language instruction or an assembler directive or a macro call (did I forget anything?), the assembler will assume you wanted a label, but may be confused if it didn't start in column 1 or have a colon after it. Many assemblers require labels to start in column 1. I wish they would not make that requirement, because I like to indent labels of only local interest by one space so when I put my text editor into condensed mode where only things that start in column 1 show, only the global labels show, which is a nice feature. You pick one, and press <Enter> to land on it.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 5:39 am 
Offline

Joined: Sat Mar 11, 2017 1:56 am
Posts: 276
Location: Lynden, WA
OK, this is starting to make sense. The lowest level language I'm knowledgeable on so far is C, and in a high level language, having your code so machine specific is drilled into you early on as "bad".

When I realized that you guys were saying that my code needs to be specific to the memory map of my particular build, my brain was going "but... but...but..."

As Yoda taught, I must unlearn what I have learned.

So it sounds like *= and .ORG are likely same thing, and that the ACME assembler I'm using uses *=. I need to find some documentation on this thing.

What I would like to find is an assembler that is as "by the book" as possible, so I don't get hosed by these things!


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 5:46 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 679
The root of the issue here is that C has a linker, which resolves addresses for you, and generally uses MMUs to have a process's start address always be the same, so you don't have to specify it. It can figure out exactly what addresses your functions, global vars, etc are at, and output numeric pointers to them, all generally laid out to an OS's specification by default.

This is more raw, so the assembler needs to form its idea of which address an instruction is at, in order to figure out those final numeric pointers/addresses which get mapped to labels.

Some assemblers also have more twisted operators, like having source code starting a $1000, but some chunk in there is going to be relocated to $3000, so even though it's in $1xxx it assembles such that it spoofs the code already being at $3xxx, ready for copying and execution in the new location.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 5:56 am 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
This is where it's important to have your origin set:

Code:
    * = $1000

LABEL    LDA #0
         JMP LABEL

Without the origin, the assembler does not know what value to assign LABEL. There are other issue with linker and modules and what not, but for the most basic, you need to set the location of your code so the assembler can better fill out the absolute addresses.


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 6:12 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8546
Location: Southern California
Assemblers can have linkers too, and in fact the first one I used, the 2500AD assembler for the 6502/65c02, did, although I never learned how to use the linker. Another engineer who worked with me briefly figured it out (with some calls to the technical-help people) and wrote a batch file which I then used for several years, sometimes modifying it slightly.

The assembly language for 6502 is pretty well standardized, but there will be small differences from one assembler to another, especially in the non-basics, like conditional assembly, macros, etc..

The reason those things were drilled into you as "bad, bad, bad" in C is that they want portability. That's a good goal, but it will come at the expense of some control and performance. Although 65xx assembly language is not portable to other processors outside the family, at least it's an easy one to envision solutions in, unlike many other processors which are unsuitable for the mere mortal to ever hope to do well in assembly.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 6:57 am 
Offline
User avatar

Joined: Tue Nov 16, 2010 8:00 am
Posts: 2353
Location: Gouda, The Netherlands
The ca65 assembler, which is part of the cc65 compiler at http://www.cc65.org/ has a separate linker. With that, you can write assembly code without ORGs. Instead, you assign your code and data to different segments. The linker then reads your linker script file to determine where the different segments go in memory, exactly the same as a typical C environment.

It's more complicated to set up, but it gives you more flexibility later, especially for complex builds. Say you want one image for testing in RAM, and another for burning to EPROM, you can use the same code, but have different linker scripts.


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 7:10 am 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8514
Location: Midwestern USA
Dan Moos wrote:
OK, this is starting to make sense. The lowest level language I'm knowledgeable on so far is C, and in a high level language, having your code so machine specific is drilled into you early on as "bad".

C is a "high level" language only in the sense that one C statement can result in the generation of dozens or hundreds of machine code instructions. C lacks a lot of the features found in true high level languages, especially when compared to timesharing BASIC. Lacking wired-in I/O functions, C is a compute-bound language that depends on libraries to enable interaction with the outside world.

Ritchie's aim when he originally developed C was to avoid the need to write the UNIX kernel in assembly language on the PDP machines, as doing so was a tedious process with long assembly times. The gain with C was in programmer productivity and once compilers became available for other machines, portability (which, however, was not a new concept introduced with C—FORTRAN and COBOL were very portable by the time C came on the scene). The loss with C was in performance, as the assembly language generated by the compiler was inefficient compared to what an expert programmer could write.

Incidentally, for a long time not all of the UNIX kernel was written in C. Thompson had to use some assembly language for the clock interrupt handler and a few other time-critical functions. As machines got faster, the performance penalties of using C were effaced and eventually all raw assembly language vanished from the UNIX kernel.

Quote:
When I realized that you guys were saying that my code needs to be specific to the memory map of my particular build, my brain was going "but... but...but..."

As Yoda taught, I must unlearn what I have learned.

Writing software in assembly language is nothing like writing in any high level language. I often use an analogy of building a house to explain the difference between writing in a high level language and writing in assembly language. In the former, your house is built out of prefabbed structures like framed walls and roof trusses, and you get your bricks from the brickyard. A machine mixes the mortar for laying the brick. The local city government tells you where to build the house.

In assembly language, you go into the forest to fell trees for lumber and cut your own two-by-fours from those trees. You have to build a kiln in which to fire your bricks and you have to mine aggregate, lime and such to make Portland cement, from which you can mix your mortar. You have to decide where you are going to build your house and you have to make sure that said location is a good one—no rivers nearby to overflow and flood you out, or a noisy, 24 hour gas station next door.

This is not to say that you can't get some high level concepts involved. An assembler with a good macro language can assist you in many ways. Garth covers some of that with his techniques for using macros to write (semi-)structured assembly language code. I don't think at that high a level when writing 6502 code, but do use macros a lot for doing such things as generating stack frames and other operations that are tedious to write in raw assembly language.

Quote:
So it sounds like *= and .ORG are likely same thing, and that the ACME assembler I'm using uses *=. I need to find some documentation on this thing.

What I would like to find is an assembler that is as "by the book" as possible, so I don't get hosed by these things!

Both .ORG and * = were supported in the original MOS Technology assembler of the 1970s, along with .EQU as a synonym for the equals sign in setting equates. 6502 cross-assemblers that are 100 percent "by the book" are rare animals, as many of the ones available today have been written by hobbyists who may have had little to no familiarity with the MOS Technology reference assembler and may not have even read the assembly language standard for the 6502 family.

From what I did learn about the Acme assembler it appears to be reasonably close to standard.

_________________
x86?  We ain't got no x86.  We don't NEED no stinking x86!


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 8:49 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
It sounds like you might want to take a look at a book first. I found Salomon to be very useful: https://www.davidsalomon.name/assem.advertis/asl.pdf It includes the reasoning on using linkers etc.


Top
 Profile  
Reply with quote  
PostPosted: Wed Mar 22, 2017 9:00 am 
Offline

Joined: Mon Jan 07, 2013 2:42 pm
Posts: 576
Location: Just outside Berlin, Germany
Dan Moos wrote:
The lowest level language I'm knowledgeable on so far is C, and in a high level language, having your code so machine specific is drilled into you early on as "bad".
Heh. Wait to we get you to write your own bare-metal Forth, where the object is to get as much performance out of the hardware as possible by hand-crafting everything specifically to the target system. It's not "optimization" until you've spent two hours finding a variant of a ten-byte code sequence that will save you two cycles :D


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

All times are UTC


Who is online

Users browsing this forum: No registered users and 8 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: