6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Fri Nov 22, 2024 12:56 pm

All times are UTC




Post new topic Reply to topic  [ 82 posts ]  Go to page Previous  1, 2, 3, 4, 5, 6  Next
Author Message
PostPosted: Wed Sep 01, 2021 8:04 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
Is it too early in this diversion to suggest we get back to the topic of the thread, and if we want to argue (again) about assembler syntax, we can make another thread for it?


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 01, 2021 1:39 pm 
Offline
User avatar

Joined: Sat Dec 01, 2018 1:53 pm
Posts: 730
Location: Tokyo, Japan
BillG wrote:
I never liked the split format. In those days of slow and small storage devices, that added space was wasteful.

The added comma, you mean? I suppose that's easily made up for by removing a few spaces here and there from comments in your code, or abbrevating some words in those comments.

Quote:
It is insightful that the split format was deprecated in documentation for the 6809 and more notably, the 6801/6803 which sported some extensions of the original instruction set but was otherwise source and binary compatible.

Sure, maybe Motorola decided they didn't like their own standard. I'm fine with either, myself, and I think it's not only reasonable but desirable for assemblers to accept both. But keep in mind we're not talking about that: we're talking about BDD's claim that "the ancestral 6800 language" does not follow "exclusive use of three character mnemonics." Putting that together with his claim that the exclusive and ultimate standard for mnemonics is what the manufacturer published, I'm just pointing out that he's at the very least not entirely correct: Motorola exclusively used three character mnemonics when they created the 6800. By what seems to be BDD's definition, Motorola later switched to allowing and perhaps even preferring non-standard 6800 mnemonics.

If this all seems rather silly to you, well, yes, it does to me, too, which is why I don't go around yelling at people who don't use whatever I feel should be "standard" mnemonics while making statements that are either ignorant or deliberately misleading. (BDD has never addressed the fact that the initial manuals used only three-character mnemonics, and clearly did not consider the "A," or "B," in the operand field to be part of the mnemonic.)

_________________
Curt J. Sampson - github.com/0cjs


Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 02, 2021 5:40 am 
Offline

Joined: Sun Oct 07, 2018 6:04 pm
Posts: 30
BigDumbDinosaur wrote:
Speaking of the user guide, I did see some information that was presented about the 65C816's memory model that I'd like to discuss in the interest of clarity. Also, I have some curiosity about how the compiler resolves some things that are more-or-less 65C816-specific. Please note that the following is not criticism, just an attempt to reconcile what the guide says with what I know about the 816's behavior.

[...]

In 6502-family architecture, a "page" is defined as 256 contiguous bytes, not 64KB. In 65C816 architecture, a "bank" is defined as 256 contiguous pages, with any given bank starting at $xx0000, where $xx is the bank number, $00-$FF.¹



Thank you for the input. I especially appreciate getting input on the documentation. Having proof read documentation in the past I know it takes time to make it good.

I agree about the 'page' being incorrect. However, while bank is probably according to the 65816, I think it can be misleading too, as I often regard bank to be something that is switched in and out in some address range.

I will give it some further thought (sleep on it), but I think segment may be a better universal term as you suggest in the footnote. Not everyone that uses the compiler can be expected to be familiar with the target and one reason for using a C compiler is to avoid having to learn and write in the native assembly language.

Quote:

As for the statement about efficiency, I question that. The 65C816 assembly language makes it possible to treat the full address space as linear space for data purposes, using succinct code. This possibility is fully exploited if "long" pointers are handled as 32-bit entities instead of 24-bit so frequent use of REP and SEP in pointer arithmetic sequences can be avoided.²[/color]



The compiler uses 32 bit data pointers. Using the data memory as a linear address space and allow objects to cross 64K boundaries is possible with Huge pointers in this compiler. The somewhat related Far pointer is also 32 bits wide, but assumes that objects are placed so that they never cross a 64K boundary (enforced by the linker rules file).

Accessing as memory location using either a Far or Huge pointer will most likely result in the same code. There are two cases where they differ. The most important one is in pointer arithmetic, which can be adding a value to the pointer (stepping it). In some cases this does not matter as an addressing mode can be used, but in other cases it needs to actually perform pointer arithmetic and with a Far pointer this is done on the low 16 bits, while a Huge pointer needs 32 bits arithmetic. It also matters for size_t, which depending on how the compiler is configured can be 16 bits when Far is used, but if Huge is enabled size_t is 32 bits. The size_t type is used in some C library functions.

As an example, consider adding one to a pointer and passing it on. In this case the pointer needs to be updated, there is no addressing mode to help as it is going to pass an update pointer value. With a Far pointer this can typically be done using a single INC instruction. With a Huge pointer it would need an INC-BNE-INC sequence.

So I think that there is a performance difference between them, but I suppose it depends on what operations you actually do.

Quote:

Is the "stack" being referred to in the above the MPU's hardware stack or a LIFO in bank $00 being treated as a stack, e.g., like the data stack commonly used in Forth? If the latter, perhaps that should be clarified for the benefit of the reader.

If the former, I'm a little confused by the As we may want to point to object in the stack, they must be in the same page. statement. Wouldn't such an object be accessible with <offset>,S (stack-relative) addressing, which implicitly refers to bank $00 and does not involve DB in any way?



It is the hardware MPU stack, there is only that stack used by the compiler runtime.

The Small data model assumes a 16 bits default data pointer. Yes, you can access an object on the stack using an addressing mode even the bank register points elsewhere. This is utilized in all data models.

You an also place a static or global object in a bank that is not 0 and address it using the absolute addressing mode.

Now consider that you want the address of either of these objects, a stack object or a data object in some other bank pointed to by the bank register. It may be a buffer that to pass to sprintf(). If you make the pointer 16 bits, which bank should sprintf() access? There is no way for it to know and both can be used by normal C code.

To make it work, both are forced to be in bank 0 in the Small data model. This allows for 16 bits default (untyped) pointers that can point to any data object.

If you want to use separate banks, then you need a 32 bits pointer and this is what the Medium data model is all about.

Quote:

[color=#000000]What defines a "memory-constrained" system? In other words, is there a total RAM threshold below which a system becomes memory-constrained from the compiler's perspective? Aside from the possibility of the heap becoming fragmented from numerous malloc() and free() calls (which is really a separate issue, I think), what other (possibly bad) things could happen in a memory-constrained environment? Also, how and when is the size of the heap determined? Is the heap limited to a single bank or can it be defined to span multiple banks to accommodate malloc() calls that request more than 64KB?



Memory constrained systems are any system that does not have seemingly infinite amounts of memory. A modern desktop computer has multiple GB of memory today. We use abstraction and care little about how much memory we use. If you write programs that need to fit a certain memory budget and this might influence how you approach the problem, you need to take it in account when you write your program, then you are on a memory constrained system as I see it.

The bad thing that can happen in a memory constrained system apart from heap fragmentation (as you mention) is that you try to fit too much program into the available memory and run out of memory space. If you write a program for you Linux desktop, I doubt you worry that will happen.

The heap is set up in the linker memory rules file (.scm extension). You can set the heap size and stack size there.

At the moment there is only one heap and it is not possible (in its prebuilt form) to make it span multiple banks. The library C code itself can actually handle it, but it needs to be properly configured and rebuilt for it. I need to fix the library build tool so end user can do it. This is one thing that is not done yet and it is mentioned in the release notes. If you actually use the compiler and run into issues with this limitation, I will put higher priority on fixing it, otherwise it will come at some point.

Quote:

    [color=#000080]The tiny address space is 256 bytes of memory located somewhere in the first 64K of memory. It has an address range 0x00-0xff...Being only 256 bytes and also shared with pseudo registers, you are somewhat limited on how much you can store in the tiny area.

I interpret the above to mean a data structure could be placed on direct page, which is unusual in most code—direct page is generally considered to be too valuable to be used in that fashion, except in narrowly-defined cases. Please clarify. Also, if I write REGISTER INT X=0 in my C program, where is X being stored?



You can put small static or global data objects on the direct page and benefit from the fast direct page addressing.

If you write 'register int x=0' inside a function it will either be located in a register or on the hardware stack.

Quote:

[color=#000000]I've not seen any 65C816 system with more than 4MB of RAM. How does the compiler reconcile the theoretical 16MB address space to the actual address space? For example, if I were to compile a program using "huge" addressing to run on my POC V1.3 unit (128KB, of which 64KB are in bank $01), how would the program "know" that the highest-accessible physical address is $01FFFF? Also, does the compiler have a way to handle memory "holes" caused by idiosyncratic address decoding?



The compiler has no idea, it will just create data objects that go into different sections. You need to tell the linker about your memory system. It will place sections in the available memory space and resolve relocations to make a working program. If there is need for gaps, perhaps due to alignment constraints or you give it very specific directions on how to place things, that will be done. There may be gaps if needed or desired.

The Foenix C256 comes with 6Mb and the coming GenX model will fill the entire 16Mb address space and then add some banked (!) memory on top of that (it has some 64MB in total), but I do not plan to support that anytime soon. I am happy to limit it to 16MB and I doubt I will write any program I want to run on my 65816 system that uses all that memory.

Quote:

    [color=#000080]Assembly language files usually have the file extension .s or .asm, but it varies wildly as assembly language itself is not standardized in any way.

[color=#000000]Although source code file naming conventions do vary, the 6502 assembly language itself is standardized—MOS Technology wrote the original standard, which compliant assemblers will implement. The 65C816 assembly language is also standardized—WDC promulgates that standard in the data sheet. The language standards intentionally ignore assembler pseudo-ops, which is nothing unique to the 6502 universe.

Regrettably, there are all sorts of 6502 assembly language bastardizations in hobbyist-developed assemblers, some borne of ignorance of the MOS Technology/WDC standards that have existed some 46 years, and others the result of the "I don't like it, so I'm going to come up with my own 'standard'." line of thinking. So it probably should be clarified that there is a standard, even though it may not seem so to the casual observer.



I am aware of the there are standards or ways that people expect assemblers to behave. However, this is a C compiler and the most important products in the package are the compiler and the debugger as I see it. The assembler is mainly there to support the compiler. I did not write this to be a 6502/65816 compiler tool chain, that sort of happened by accident. The code base will be used to make additional targets, this work is in progress. I decided not to care too much about assembler expressions and specific vendor features. I do try to follow defined mnemonics and addressing mode syntax. In the end I provide what is needed for myself and the compiler in a way that makes it efficient for me to work with it.

I have little hope for that my assemblers will make anyone switch from their favourite tools they been using for a decade or two. My take is that people who use a C compiler tool chain do it because they want to write as little assembly language as possible.

Quote:

[color=#000000]Can or does the compiler treat the run-time data that was generated during compilation, e.g., a lookup table associated with, say, a switch() statement, as read-only data, as in:

Code:
switch (i) {
  case 1:  printf("i = 1.\n");
           break;
  case 2:  printf("i = 2.\n");
           break;
  ...etc...
  default: printf("i is not 1 or 2.\n");
}

At least in assembly language, there would have to be some sort of address lookup table to vector the MPU according to the result of the switch() statement. Would your compiler place that lookup table in the rodata segment, even though no ROM may be involved?



Yes, switch tables are placed in a separate 'switch' section that is rodata and can be placed in the same place as code. It can actually be placed in any bank and does not need to be in the same bank as the function that use it.


Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 02, 2021 5:53 am 
Offline

Joined: Sun Oct 07, 2018 6:04 pm
Posts: 30
BigDumbDinosaur wrote:
BigDumbDinosaur wrote:
hth313 wrote:
    The huge address space covers the entire 16MB address range. The maximum size of an object is 16MB (minus one byte).
I've not seen any 65C816 system with more than 4MB of RAM. How does the compiler reconcile the theoretical 16MB address space to the actual address space? For example, if I were to compile a program using "huge" addressing to run on my POC V1.3 unit (128KB, of which 64KB are in bank $01), how would the program "know" that the highest-accessible physical address is $01FFFF? Also, does the compiler have a way to handle memory "holes" caused by idiosyncratic address decoding?

The thought has occurred to me that the compiler has to be aware of the environment on which the executable will be run, since no program is truly insular, even if no I/O is involved. As calls to malloc() tap into the heap, which I understand to be a finite size determined during compilation, it would seemingly set a hard limit on how much memory could be offered by malloc(), unless...

In the UNIX/Linux environment, sbrk() would be called by malloc() when the heap was (nearly) exhausted and more memory was needed to satisfy future requests (I'm cheerfully assuming that no free() calls are made in the running program, which means it will likely increase its memory consumption the longer it runs). sbrk(), in turn, would try to "find" memory, either physical or virtual, with the latter possible in a machine whose MPU supports the concept of virtual memory.¹

Given that, the Calypsi compiler's rendition of malloc() would have to have some way to know how to enlarge the heap when nearly exhausted. Doing so would either require the malloc() code have knowledge of the machine's physical memory map, or malloc() would have to know how to request more memory from the operating environment on which the executable is running.

Please clarify.

——————————
¹It is theoretically possible to build a virtual-memory system using the 65C816. The ABORTB interrupt input provides the basic means by which program execution may be temporarily stopped to allow the kernel to deal with a page fault. ABORTB' behavior is sub-optimal, but that is not an insurmountable obstacle in a system that uses a CPLD or FPGA to implement glue logic.


The Calypsi tool chain is intended to be used on embedded systems, or bare metal programming. I provide some support to make it (somewhat) usable on certain hosted platforms. Foenix C256 being one of them. I consider providing OMF file support for Apple IIgs at some point.

As this mainly is for bare metal programs, the heap for malloc() is statically allocated at link time in a fixed address range at the moment. There are no means for growing it beyond what you have defined it at the time of linking the program.

If you want to run on some theoretical operating system that can invent memory, you would need to replace some C library routines. As I mentioned in my previous answer, it will be possible to rebuild the library at some point. In theory, that would allow anyone to make their own C library flavour. This is however beyond what I plan to do with the tool chain.


Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 02, 2021 5:54 pm 
Offline

Joined: Sun Jan 10, 2021 11:25 pm
Posts: 64
hth313 wrote:
I did not write this to be a 6502/65816 compiler tool chain, that sort of happened by accident.


I'm actually really curious how this situation came to be, particularly with the 6502. Generating good code for the 6502 is a considerable technical challenge, given its paucity of registers, and in particular, the register offset addressing modes typically used to access the C stack. Accordingly, I'm very surprised to see another 6502 C compiler pop into existence. I haven't had much time to take a look at the code it generates, but I'm curious where it fits in the existing landscape of 6502 compilers (llvm-mos, gcc-6502, vbcc, cc65), and what its take is on these challenges.


Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 02, 2021 5:58 pm 
Offline
User avatar

Joined: Thu May 28, 2009 9:46 pm
Posts: 8505
Location: Midwestern USA
mysterymath wrote:
hth313 wrote:
I did not write this to be a 6502/65816 compiler tool chain, that sort of happened by accident.

I'm actually really curious how this situation came to be...I'm very surprised to see another 6502 C compiler pop into existence.

It appears this compiler is specific to the 65C816, which is a much better target for a C compiler than the 65(c)02. The user guide goes into some detail in that regard.

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


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 15, 2021 3:19 pm 
Offline

Joined: Sun Oct 07, 2018 6:04 pm
Posts: 30
mysterymath wrote:
hth313 wrote:
I did not write this to be a 6502/65816 compiler tool chain, that sort of happened by accident.


I'm actually really curious how this situation came to be, particularly with the 6502. Generating good code for the 6502 is a considerable technical challenge, given its paucity of registers, and in particular, the register offset addressing modes typically used to access the C stack. Accordingly, I'm very surprised to see another 6502 C compiler pop into existence. I haven't had much time to take a look at the code it generates, but I'm curious where it fits in the existing landscape of 6502 compilers (llvm-mos, gcc-6502, vbcc, cc65), and what its take is on these challenges.


It started out with the idea of making a C compiler tool chain that could be easily be used to implement several targets. The 6502 was selected as an early target as I like it and thought it deserved a really good C compiler. The 65816 was not at all planned for.

Around the time when I released the 6502 product I ran into the C256 Foenix people. This caused me to take an additional look at the 65816 and I decided to make a product for it too, as it looked like an interesting challenge. So it happened due to this.

Otherwise there are other targets I am working on to be released in the future. This includes a variety of 8, 16 and 32 bit targets.

Making it work on several targets early on and more or less at the same time helps to avoid the trap of making a product suitable for one or few styles of targets. Yet, I need to make it possible to utilize the various idiosyncrasies of the targets, so it is a balance.


Top
 Profile  
Reply with quote  
PostPosted: Wed Sep 15, 2021 11:39 pm 
Offline

Joined: Sun Oct 07, 2018 6:04 pm
Posts: 30
New release, version 3.4.1 of my C compiler for 6502 and 65816.

The user guides now contain a tutorial showing how to build a simple Hello World for running either on the included debugger (using its simulator) or on target hardware/emulator using VICE for Commodore 64 (6502) and the C256 Foenix emulator (65816).

Short overview of what is new (there are more details in the release notes in the installation):

  • The optimizer can now perform inlining
  • Custom section names can be used for code and data objects
  • Alignment can be specified on C objects
  • Better support for replacing the C startup module

User guides can be downloaded separately (useful if you want to take a look at it and also useful as it shows how to install the product).

Installers are available here:

6502
User guide (pdf) https://tinyurl.com/38m6u67r
Arch https://tinyurl.com/5wtzdb74
Debian https://tinyurl.com/26xbeebm
macOS https://tinyurl.com/yz6pefn6

65816
User guide (pdf) https://tinyurl.com/4yy9u3jb
Arch https://tinyurl.com/2dm3vh7k
Debian https://tinyurl.com/be74jffd
macOS https://tinyurl.com/5cj283b7


Top
 Profile  
Reply with quote  
PostPosted: Thu Sep 16, 2021 11:06 am 
Offline

Joined: Thu Mar 12, 2020 10:04 pm
Posts: 704
Location: North Tejas
I am curious what your compiler can do with these two benchmarks:

viewtopic.php?p=78835#p78835


Top
 Profile  
Reply with quote  
PostPosted: Tue Dec 07, 2021 7:02 pm 
Offline

Joined: Sun Oct 07, 2018 6:04 pm
Posts: 30
New version 3.4.3 available. This is a maintenance release with bug fixes.

65816

6502


Top
 Profile  
Reply with quote  
PostPosted: Fri Jan 07, 2022 8:22 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10985
Location: England
Great to see it, thanks Håkan!


Top
 Profile  
Reply with quote  
PostPosted: Sat Jan 08, 2022 10:28 pm 
Offline
User avatar

Joined: Fri Aug 03, 2018 8:52 am
Posts: 746
Location: Germany
wouldn't it make more sense to make a github repo for this? so you wouldn't need to post new links for every update, and you wouldn't need version numbers when installing as it would just grab whatever is the newest.

i tried installing the 65816 version via the commandline (Ubuntu, WSL2) and running "sudo gdebi calypsi-nut-3.4.3.deb" just gives me a "file not found" error.
the user guide says 3.4.1 but i assume you're supposed to replace that with whatever version is the current one. even changing it to 3.4.1 still gives me the same error.
i'm sorry but i don't know how you're supposed to install this.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 31, 2022 3:49 am 
Offline

Joined: Sun Oct 07, 2018 6:04 pm
Posts: 30
Proxy wrote:
wouldn't it make more sense to make a github repo for this? so you wouldn't need to post new links for every update, and you wouldn't need version numbers when installing as it would just grab whatever is the newest.

i tried installing the 65816 version via the commandline (Ubuntu, WSL2) and running "sudo gdebi calypsi-nut-3.4.3.deb" just gives me a "file not found" error.
the user guide says 3.4.1 but i assume you're supposed to replace that with whatever version is the current one. even changing it to 3.4.1 still gives me the same error.
i'm sorry but i don't know how you're supposed to install this.


I hope that I can add a web site at some point in the future, that should make it easier. For now we have to suffer with the links.

Do you have gdebi installed? The installer .deb file is just the file you downloaded. If it goes to a downloads directory and you are in another directory, you need to specify the path to it.


Top
 Profile  
Reply with quote  
PostPosted: Mon Jan 31, 2022 3:55 am 
Offline

Joined: Sun Oct 07, 2018 6:04 pm
Posts: 30
I have made a new release version 3.5.1.

This release adds support for 64 bit IEEE floating point and the debugger can be used for target debugging. At the moment I only have a debugger agent for the C256U here https://github.com/hth313/Calypsi-remote-debug.git

6502

65816

There are also tools for 68000 now, but that is maybe off topic here?

68000


Top
 Profile  
Reply with quote  
PostPosted: Sat Feb 05, 2022 4:22 am 
Offline
User avatar

Joined: Mon May 12, 2014 6:18 pm
Posts: 365
Thanks for the updates! Having the sources to build things ourselves is a neat idea, though I do prefer the .deb files you've been offering.


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

All times are UTC


Who is online

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