Jump to content
IGNORED

Has 'C' replaced assembler as the programmers preferred language of choice


Recommended Posts

But even with Pascal, the problem of the call stack and its poor support on the 6502 does not go away. There is a reason why companies like Oss tailored specific languages like Action! just for the 6502. Global variables, or only static variables, no recursion, and you are fine. Of course, something like this could also be done within a language that has a syntax that is close to C.

Maybe I misunderstood you but something can be done like that in C already. Define variables as global or static, don't use recursion and minimize layers of function calls. Variables that are defined global or static should end up in the bss or data section of the compiler output, not on the stack.

Here is a perfect example of a game written in C for the 6502 and it uses that approach:

http://forum.defence-force.org/viewtopic.php?f=20&t=684

 

I haven't seen Action's output but you are never going to get away from using the stack for function calls. You have to save the processor state somewhere no matter what language you use. You either use the hardware stack or store things somewhere else. The 6502 just happens to suck at any stack operation beyond saving or restoring the accumulator. FWIW, as long as you are careful not to overflow the hardware stack there is no reason you can't use it and it's faster than a stack managed with a pointer on page zero.

 

BTW, check out how the C compiler in the Oric sdk generates code if you don't like cc65. It's available for download from that site.

Link to comment
Share on other sites

Interleaved parameter stacks at fixed locations using ABS,X addressing were something mentioned in an article I referenced a while ago on this same topic. I can't help but think they'd be greatly more efficient than (ZP),Y addressed stacks.

While it's certainly faster, the compiler has no way of knowing how much stack will be used by the program and you could overflow the software stack just as easily as using the regular hardware stack. You can get around it by allowing the source code to define the ABS value but the compiler/linker have no way of doing it automatically.

 

Allocating registers on page zero also has it's drawbacks. It eliminates complex addressing modes once you are in the body of the code (saving memory and clock cycles), but you have to save/restore page zero registers on entry/exit to functions which is slow. You can speed things up a little if you allow a compile time selectable set of alternate page zero registers for critical code and pass parameters in registers.

 

While I think 6502 C code could be sped up by at least 10%, the bottom line is still going to be that C can't fully replace assembly.

Link to comment
Share on other sites

While it's certainly faster, the compiler has no way of knowing how much stack will be used by the program and you could overflow the software stack just as easily as using the regular hardware stack. You can get around it by allowing the source code to define the ABS value but the compiler/linker have no way of doing it automatically.

Yeah, I think the idea posited (IIRC) was that there's a fixed stack location (purely for example) at the load address and the linker then relocates all stack references to that absolute address. Obviously using ABS,X there's a maximum of 256 stack entries, but at least the bit width is variable (via compiler directives, I guess), so 16-bit parameters take 2 pages, 32-bit long ints take 4 pages, and you could even use 6 pages to cater for FP arguments. Overflow's certainly a consideration, as you say; I'm sure the downward-growing (ZP),Y stack model frequently pushes its way more than 512 bytes down from the top of RAM.

 

While I think 6502 C code could be sped up by at least 10%, the bottom line is still going to be that C can't fully replace assembly.

And much as I like compilers, I think the difference in development times between 6502 and C (using modern cross-assemblers and debuggers, coupled with a good encapsulated 6502 library) is pretty marginal.

Edited by flashjazzcat
  • Like 1
Link to comment
Share on other sites

 

And much as I like compilers, I think the difference in development times between 6502 and C (using modern cross-assemblers and debuggers, coupled with a good encapsulated 6502 library) is pretty marginal.

I beg to differ. As it strongly relates to the type of code you want.

If you have numerous loops and if-else constructs - everything nested of course :) - then the development with a "higher" languiage is faster and more safe. As it is easy to get the nested stuff wrong.

It is not impossible or even very hard on the 6502, but in C its faster and less error prone (if you are an experienced C coder).

Link to comment
Share on other sites

I beg to differ. As it strongly relates to the type of code you want.

If you have numerous loops and if-else constructs - everything nested of course :) - then the development with a "higher" languiage is faster and more safe. As it is easy to get the nested stuff wrong.

It is not impossible or even very hard on the 6502, but in C its faster and less error prone (if you are an experienced C coder).

Yes, you're right there: it's easier to create structured code with C. I suppose it depends on how long you've spent writing 6502, though. Handling and following structure in 6502 is a non-issue from my point of view, and this includes recursion using proprietary stacks, complex data structures, etc. So I can only reiterate what I said: the extra amount of time it would take me to develop something on the A8 in assembler as opposed to in C is marginal.

Edited by flashjazzcat
  • Like 1
Link to comment
Share on other sites

I beg to differ. As it strongly relates to the type of code you want.

If you have numerous loops and if-else constructs - everything nested of course :) - then the development with a "higher" languiage is faster and more safe. As it is easy to get the nested stuff wrong.

It is not impossible or even very hard on the 6502, but in C its faster and less error prone (if you are an experienced C coder).

I think the larger a program is the more of an advantage there is to using a high level language.

The problem with that is we are talking about a maximum of 64K and stuff I've done for work would wouldn't even fit in RAM.

 

If we were talking about C++, templates and objects can make development much faster if you can use existing data structures/objects.

Link to comment
Share on other sites

Maybe I misunderstood you but something can be done like that in C already. Define variables as global or static, don't use recursion and minimize layers of function calls. Variables that are defined global or static should end up in the bss or data section of the compiler output, not on the stack.

Maybe my point was not clear enough. Of course a limited C is realizable on a 6502 without all the hassle of emulating a stack, i.e. only using the hardware stack. Same with Pascal. However, this is no longer C (or Pascal, for that matter). If you remove these features from the language, however, you do not need the hardware stack for parameter passing. Instead, the code generator allocates statically(!) global memory cells for all parameters that go ever into a function, and the function just takes them from there. As long as there is no recursion, this method works without requiring ever any type of argument stack.

 

The program stack of course remains (and is certainly limited), but, and this is my point, without recursion you *do not need* the complicated stack emulation, and all the overhead of pulling or pushing arguments to or from a hardware stack. Actually, early microprocessors did not even have a hardware stack (and some RISCs neither), but instead a "link" register that stores the last PC on a "jump and link" instruction. Instead, the called "function" then stores the contents of the link register into the target address of a "jump" instruction at the very end, which then returns program flow to the caller. Of course, recursion is not possible this way either, for the same reason. Modern risc compilers store the link register then to a "stack" that is "emulated" by one of the many registers, older processors had to use more complicated approaches.

 

It is not a miracle that very early dialects of FORTRAN did not allow recursion. Hardware stacks are "relatively modern" and even were outdated by some architectures later on again.

Link to comment
Share on other sites

Actually, the C standard does not require implementations to use a stack for passing parameters or allocating local variables.

They specifically left that out of the standard to support systems that do not have a hardware stack.

The same is probably true for Pascal but I'm not certain.

 

Maybe I didn't make this clear, if you are using global or static variables, they do not have to be allocated on the stack. The compiler normally reserves space for them on the heap and you don't need indexed addressing to access them.

Link to comment
Share on other sites

Rough thought: Ideal processor would have stack relative addressing for passing parameters. It would help if some mechanism was there to auto increment a memory locations like some processors have i.e. Load via X register and increment.

 

The first part of the code would just be a JSR to function which would jump over the parameters. Something like

JSR routine

.byte parameter1

.word parameter2

.byte parameter3

continuation code here

 

Since that is a relatively well known way of passing parameters, but with stack relative addressing you wouldn't need the TSX to find the data. Load via X and auto increment would work on the stack such that when all the data was transferred if necessary, the RTS would hit continuation code, saves a few more bytes/ticks. All routines would have to know how many parameters have been passed or that number would have to be passed also. Pipe dream of course and this would FAIL recursion as it is.

 

You probably could get away with some of it on a 6502 by just mirroring stack to page one. I've followed the stack with a monitor on an 8 bit and it seldom goes more then 8 bytes deep. I often put fairly large routines on page two and have never had a problem with the stack trashing them.

 

IMHO: Recursion is over rated. I once wrote a recursive decent parser for a BASIC I did in C for IBM/MS DOS. Properly behaved, it just never gets that deep. I can't think of another program I wrote in the last 30 years that used recursion other then demos or bench marks. Recursion in Action is trivial, just a two byte code block to pop the stack and one local variable.

 

Thinking about it, a 65816 would improve the situation but the instruction set is still not optimized for C. All the same problems you run into in assembler are still there when you are writing a compiler. I've often got into comparisons discussions about the 6502 relative to other processors. Since I am currently working on my ATR8000 the Z80 is kind of fresh in my mind. Figure the ATR8000 only has a 4k ROM and with that is able to handle 4 disks drives of everything from SSSD to 8" DSDD, variable sector length, serial port, printer port, printer buffer, all SIO transactions for them, and boot CP/M. Compared to the 4k ROM we have in our 1050s, it gets a lot accomplished with the same ROM size with penalties of course.

Link to comment
Share on other sites

IMHO: Recursion is over rated. I once wrote a recursive decent parser for a BASIC I did in C for IBM/MS DOS. Properly behaved, it just never gets that deep. I can't think of another program I wrote in the last 30 years that used recursion other then demos or bench marks. Recursion in Action is trivial, just a two byte code block to pop the stack and one local variable.

 

Ditto. I've written recursive routines twice in 30 years in IT. One is the usual binary tree traversal. The other was for scanning a large volume of text and identifying the page breaks for a dozen sizes of paper. These were for unix systems churning through megabytes at a minimum, up to gigabytes of data.

Link to comment
Share on other sites

This looks like an interesting C/assembler hybrid:

 

http://neshla.sourceforge.net/

 

I'm sure the output could be quite easily modified to suit the A8.

 

EDIT: And there was already a thread on it, courtesy of tebe, but no interest:

 

http://atariage.com/forums/topic/114459-6502-high-level-assembler-neshla/

Edited by flashjazzcat
Link to comment
Share on other sites

Rough thought: Ideal processor would have stack relative addressing for passing parameters. It would help if some mechanism was there to auto increment a memory locations like some processors have i.e. Load via X register and increment.

Auto increment, auto decrement, the ability to push or pull any or all registers with a single instruction and the ability to perform address calculations without needing the accumulator... which is why the 6809 is so good at supporting high level languages.

 

The first part of the code would just be a JSR to function which would jump over the parameters. Something like

JSR routine

.byte parameter1

.word parameter2

.byte parameter3

continuation code here

 

Since that is a relatively well known way of passing parameters, but with stack relative addressing you wouldn't need the TSX to find the data. Load via X and auto increment would work on the stack such that when all the data was transferred if necessary, the RTS would hit continuation code, saves a few more bytes/ticks. All routines would have to know how many parameters have been passed or that number would have to be passed also. Pipe dream of course and this would FAIL recursion as it is.

 

You probably could get away with some of it on a 6502 by just mirroring stack to page one. I've followed the stack with a monitor on an 8 bit and it seldom goes more then 8 bytes deep. I often put fairly large routines on page two and have never had a problem with the stack trashing them.

Most C code will only go a few levels deep but local variables and parameters are what take up space on the stack.

By using global and static variables even to pass parameters a 256 byte hardware stack would be sufficient.

 

IMHO: Recursion is over rated. I once wrote a recursive decent parser for a BASIC I did in C for IBM/MS DOS. Properly behaved, it just never gets that deep. I can't think of another program I wrote in the last 30 years that used recursion other then demos or bench marks. Recursion in Action is trivial, just a two byte code block to pop the stack and one local variable.

I think the only time I've resorted to using recursion for a project was for navigating a tree. But recursion is in C if you need it.

 

Thinking about it, a 65816 would improve the situation but the instruction set is still not optimized for C. All the same problems you run into in assembler are still there when you are writing a compiler. I've often got into comparisons discussions about the 6502 relative to other processors. Since I am currently working on my ATR8000 the Z80 is kind of fresh in my mind. Figure the ATR8000 only has a 4k ROM and with that is able to handle 4 disks drives of everything from SSSD to 8" DSDD, variable sector length, serial port, printer port, printer buffer, all SIO transactions for them, and boot CP/M. Compared to the 4k ROM we have in our 1050s, it gets a lot accomplished with the same ROM size with penalties of course.

The 65816 is a band aid attempt to compete with the 6809 and 16/32 bit CPUs.

The register mode switching (8/16 bit), lack of auto increment/decrement, limited address calculation (no LEA instructions), poor support of the new B accumulator and lack of optimal stack push/pull instructions make the code much larger and less efficient than the 6809's.

But it's passable for compilers.

Edited by JamesD
Link to comment
Share on other sites

  • 2 years later...

I completed a Master's in Software Engineering about 10 years ago, it's all C/C++ based learning. I have some rudimentary assembler skills from my youth when I would program my A8, but C++ is (at least my perception) so much easier to code with that I wouldn't bother with anything else.

 

Note, I'm not a programmer by trade, FWIW.

Link to comment
Share on other sites

I completed a Master's in Software Engineering about 10 years ago, it's all C/C++ based learning. I have some rudimentary assembler skills from my youth when I would program my A8, but C++ is (at least my perception) so much easier to code with that I wouldn't bother with anything else.

 

Note, I'm not a programmer by trade, FWIW.

 

Pretty much what I was expecting to hear. Even the Linux kernel is written in C and not assembly. These days in most computing environments optimizing for speed to the point of needing assembly is rarely necessary, and code space constraints are even less of an issue than that. I would imagine assembly mostly just lives in (some) hardware drivers and certain high tech specialty cases like missile guidance and the like.

Link to comment
Share on other sites

I work in the game industry. I'm a rendering software engineer for consoles.

 

The PS1 started the C era in games back in 1995. Today games are made in C++ and with some embedded scripting like Lua or Python or even home based scripting solution. The scripting is used for the game logic and hud control. For example: killing a monster spawns a box, opening the box spawns a power up. We don't make this logic in C++ as it would be crazy, instead they are programmed by technical game designers and can be easily changed without recompiling the code.

 

x64 platform C/C++ compilers don't allow you to embed asm instructions in your code, like _asm { }. Instead you need to use intrinsic functions. We use them for SIMD operations like SSE, AVX, etc. The reason for this is to not mess with the compiler optimization logic.

 

But I do check the generated asm code very often, specially when changing a shader, I need to check in impact on the GPU asm code. Also some very intensive routines you may want to take a look in the CPU asm code.

  • Like 3
Link to comment
Share on other sites

Except the bits that are written in machine-specific assembly language. It would be difficult to write a kernel entirely without recourse to machine code, and this is regardless of speed/brevity considerations.

 

You mean like the "hardware drivers" that I originally mentioned? Since in Linux, the device drivers are part of the kernel, that means I'm aware that not 100% of it is in C. My point is that much of it is in C, which is in contrast to the old 8-bit machines (and even other older systems) that a lot of us cut our teeth on, which almost always used assembly.

 

I am very curious though, if you could provide an example of what part of a kernel would require machine code that is not due to speed/timing or code size considerations.

Link to comment
Share on other sites

 

You mean like the "hardware drivers" that I originally mentioned? Since in Linux, the device drivers are part of the kernel, that means I'm aware that not 100% of it is in C. My point is that much of it is in C, which is in contrast to the old 8-bit machines (and even other older systems) that a lot of us cut our teeth on, which almost always used assembly.

 

I am very curious though, if you could provide an example of what part of a kernel would require machine code that is not due to speed/timing or code size considerations.

No, not just drivers. I believe boot code for one, but anyone sufficiently interested can go and look it up.

Link to comment
Share on other sites

IMHO There are no C compilers which are have any chance to be usable as Action! in Atari8 world.

 

But anyway Action! was never been THE FIRST Programming Language in Atari World.

 

We all need another evolution step (or revolution) in ACTION! development!

 

In C direction of course.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...