6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Sun Oct 06, 2024 10:40 pm

All times are UTC




Post new topic Reply to topic  [ 20 posts ]  Go to page Previous  1, 2
Author Message
PostPosted: Fri Jul 05, 2013 8:23 pm 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
White Flame wrote:
Speaking of which, is there any high-level language that exposes the underlying Carry flag to the programmer?


PL/M (at least some implementations) does. I don't know of any PL/M implementation for the 6502 family, though.

In Forth, I've thought about experimenting with words that operate on the carry, but I haven't actually tried this. For example, in a sequence like U< IF, the U< does a CMP then pushes TRUE or FALSE (onto the Forth data stack), and the IF pulls (from the data stack) and does a BEQ. My thinking was it would be better to simply do a CMP and a BCS or BCC (maybe using differently-named words than U< and IF, though). If there were a situation where you actually wanted the TRUE/FALSE value (i.e. you were planning on doing something with it other than branching), defining a primitive to turn the carry into a TRUE/FALSE value on the stack would be trivial.


Top
 Profile  
Reply with quote  
PostPosted: Fri Jul 05, 2013 8:56 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
dclxvi wrote:
In Forth, I've thought about experimenting with words that operate on the carry, but I haven't actually tried this. For example, in a sequence like U< IF, the U< does a CMP then pushes TRUE or FALSE (onto the Forth data stack), and the IF pulls (from the data stack) and does a BEQ. My thinking was it would be better to simply do a CMP and a BCS or BCC (maybe using differently-named words than U< and IF, though). If there were a situation where you actually wanted the TRUE/FALSE value (i.e. you were planning on doing something with it other than branching), defining a primitive to turn the carry into a TRUE/FALSE value on the stack would be trivial.


Of you could not bother exposing it at all and instead implement "IFU<" that does all of this internally. It's such a low level implementation detail that it should be managed by the compiler. The compiler can keep track of such things, and potentially reorder operations to better leverage things like the CPU flags. Granted this falls in to the "sufficiently smart compiler" trap, but the entire point of a higher level language is to abstract aspects such as this.

Consider the Java VM -- it's a "CPU", and it doesn't even have flags. It doesn't need them as part of its CPU model. Forth chips don't have status flags either.

If you're dealing with very low level operations like flags, then you're fighting your compiler, or the compiler isn't doing it's job. May as well just drop in to a decent macro assembler at that point.

I appreciate the specific desire for the Carry case to handle high precision arithmetic, but frankly you have so much more involved in that than simply managing the carry flag, that odds are that little capability isn't going to make you're 24 bit, or 48 bit, or whatever "not" 8, 16, 32, 64 bit math you want to do more efficient than simply working with the higher bit word size in your compiler. And, yes, it's not lost on me that many 6502 compilers don't support 64 bit math.

So, drop in to machine code to handle these kind of edge cases.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 06, 2013 6:59 pm 
Offline
User avatar

Joined: Thu Mar 11, 2004 7:42 am
Posts: 362
whartung wrote:
Of you could not bother exposing it at all and instead implement "IFU<" that does all of this internally.


U< IF is just one example. Forth is atypical in that you can use IF to create your own control structures. To branch backward you'd have UNTILU<. Then there'd be WHILEU<. Then you've got words like WITHIN < and > and so on, so you'd have IFWITHIN etc. It can get out of hand quickly. It may turn out that experimenting will suggest that defining IFU< on occasion is the way to go, but the purpose of the experiment is to see if there's a reasonably general approach (to operating on the carry flag) that doesn't make too much of a mess of things.

whartung wrote:
Granted this falls in to the "sufficiently smart compiler" trap, but the entire point of a higher level language is to abstract aspects such as this.


In my experience, embedded compilers (free or pay) aren't sufficiently smart enough, at least not yet, to really utilize the carry flag very effectively. Compilers don't yet seem to be able to turn a line like:

crc = (data & 0x80) ? ((crc << 1) ^ POLY) : (crc << 1);

into this:

Code:
   ASL
   BCC .1
   EOR #POLY
.1


They can usually (under high enough optimization settings) eliminate an AND #$80 and use a BPL or BMI, but they don't use the carry. That's why it would be helpful to have a keyword (or something) that would tell the compiler to consider using the carry. The idea is that you'd use this new keyword on occasion to better communicate your intent to the compiler. You could use assembly in these cases, and in the example above it's short and simple, but if you've got to write one routine for the 6502, one for the AVR, one for the PIC, etc. it can add up quickly. I wouldn't expect a compiler to eliminate any need for assembly, but it seems to me that there's some room for improvement with the code currently generated by compilers in some reasonably common cases.

whartung wrote:
Forth chips don't have status flags either.


On Forth chips, pushing to and pulling from the data stack (usually) happens within a cycle, so there's no benefit to having flags. On the 6502, using flags does have benefit compared to pushing to and pulling from a data stack. Using, e.g., CLC is smaller and faster than pushing FALSE; if a pull can be eliminated, even better. But if it makes the high-level language that much more complex, it may not be worth it. That's what I'd try to learn from the experiment.


Top
 Profile  
Reply with quote  
PostPosted: Sat Jul 06, 2013 8:48 pm 
Online
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8521
Location: Southern California
Quote:
Of you could not bother exposing it at all and instead implement "IFU<" that does all of this internally. It's such a low level implementation detail that it should be managed by the compiler. The compiler can keep track of such things, and potentially reorder operations to better leverage things like the CPU flags. Granted this falls in to the "sufficiently smart compiler" trap, but the entire point of a higher level language is to abstract aspects such as this.

There are certain secquences that I observed coming up frequently when I wrote my '816 Forth, so I counted how many times they ocurred and decided on ones to make primitives. DUP >R is of course common so I made it a primitive DUP>R with only LDA 0,X PHA. SWAP ! comes up frequently, so I made that a primitive SWAP! with only LDA 0,X STA (2,X) JMP POP2. There are of course others. My onboard compiler however is only 36 bytes, much too simple to be looking for things like U< and IF that could be merged, and then know how to write it.

If it were needed often enough to justify the added assembly-language instructions, the words that result in a C flag that might be interesting later could store it in a one-byte ZP flag variable (not even on the stack), and subsequent words that want it could examine it. I don't think it'd be worth it. You would be constantly paying the performance penalty and seldom taking advantage of what it's there for.

Something I do that's similar is for the DO...LOOP where I use a flag variable that can be used later to tell if the loop completed or if it was aborted with a LEAVE. LEAVE sets the flag variable (to $FF), and LOOP and +LOOP clear it if they drop through, so there's no need to initialize it. That also makes it nestable. SYSIRQ does save it though so interrupt service won't step 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: Sun Jul 07, 2013 1:49 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 674
I would make words that affect carry be explicit versions. It'd only be a handful of necessary instructions depending on what's needed, namely some subset of add, subtract, shift left/right, roll left/right, ToS->carry, and carry->ToS.

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


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

All times are UTC


Who is online

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