Jump to content


  • Content Count

  • Joined

  • Last visited

  • Days Won


pzembrod last won the day on November 16 2020

pzembrod had the most liked content!

Community Reputation

32 Excellent

Recent Profile Visitors

79 profile views
  1. Yes, that is entirely possible. Either use the -prg <path/to/program> and -run flag, in case you just want to start a program; actually, it will then not load the program from the sdcard but from the host's file system. Or, if you want to start a program and subsequently send some input in the form of keystrokes to the program, then use the -bas <path/to/textfile> flag with a text file containing PETSCII or ISO (depending on the X16 mode) Basic commands (in this case a LOAD"prg" and a RUN) plus whatever keys you want to send to the program. In https://github.com/pzembrod/cc64/blob/master/emulator/run-in-x16emu.sh you can look at an example of this. The "just run" variant is in line 28 (autostart="-prg ${x16filesdir}/${executable} -run"), and the "load, run and type input" variant is from line 45 where a script is put together, converted to PETSCII and passed in with -bas. Incidentally, since we had a recipe in the opening post on how to create an SD card in Windows (IIUC), here's a link to a script that does the same on Linux, using sfdisk and the mformat tool from mtools: https://github.com/pzembrod/cc64/blob/master/emulator/mk-sdcard.sh
  2. That's fascinating! Did you ever publish it anywhere? What is it called? By conversion service, you mean a service to get 1541 disks onto a modern machine, i.e. create a d64 disk images from them? Do you still have your 1541? And possibly your 64? On a separate note, I got lucky and found the author of ENI Assembler: http://forum.6502.org/viewtopic.php?f=2&t=6475 Caveat is that there are a few challenges involved in accessing the source code. Best read his post linked above.
  3. The challenge to port it to the X16 might be the relatively limited amount of linear RAM space; one would likely have to break out 8k-ish code chunks and move those into the banked RAM; how easy or hard that is depends on the architecture of their compiler. Apart from that, there should be no fundamental problem. I will say, though, that I found the Data Becker C64 C compiler to produce relatively slow code, way back then. Most certainly an interpreted VM; calculating the first 1899 primes took 99 sec with their C, iirc, 105 sec with Kyan Pascal (which is known to use a VM), 24 seconds with UltraForth/VolksForth (indirect threaded code), 3 seconds with hand-crafted assembler. Code from my own cc64 takes 5 seconds with static variables, and 14 seconds with local variables on the stack. Did the C128 Profi C produce code that was speed-wise in the order of magnitude of assembler? In any case it would be very interesting to see the sources of their compilers, if they are willing and allowed to make them available.
  4. And to close the loop on this: It's out: https://github.com/pzembrod/cc64/releases/tag/v0.8.0.1 and
  5. Great work, @desertfish! Really cool to use one's own programming language for such a project. In the meantime I have also done a little research. I asked for likely porting candidates on 6502.org: http://forum.6502.org/viewtopic.php?f=2&t=6475. The Editor Not Included assembler mentioned there looks interesting to me; I'm currently trying to find out if the sources are available. And my VoksForth partner, an old Atarian, pointed me to Bibo Assembler - https://atariwiki.org/wiki/Wiki.jsp?page=BiboAssembler - where the sources are available. Unfortunately the handbook is in German.
  6. Incidentally, I have now also made a tool for easy patching of an X16 ROM: https://github.com/pzembrod/cc64/blob/master/Usage.md#patch-c-charset
  7. Hi Tom, I hadn't read your reply yet when I composed my most recent post. You already said it all. My post is just a repetition with different words.
  8. Trying to reply inline. Spoiler: Most of your reasons I think I either don't buy or don't understand. If we assume that each function gets called once, then the saved jmp opcode byte gets more than offset by the 2 bytes of the additionally needed lda #function_id in the function call. You either have to remember a lot of function numbers or a lot of function addresses. Since each address is equal to $c000 + 3 * function number, I find the difference not really significant. A number would be a little easier to remember, I guess, but in practice you'd want an include file with label defines in either case. This is the only point where I see a certain merit, but only in case you need the single point of entry to be flexible, e.g. if you want to route the entire API through a jmp(), so you can e.g. easily switch between different implementations, flavours, feature sets etc. Or if the library and thus its entry point get loaded to a dynamically determined memory area (easy with pure-relative-addressing 6809 code, harder with non-relocatable 6502 code). But neither of these cases I see applying to an X16 ROM. I don't see why a function parameter should make an API more or less consistent or coherent. Both, consistency and coherence, come, imho, from the functions' and their parameters' semantics, from the mental model behind them, etc, not from which dispatching mechanism is chosen. Same argument can be made for a jump list. No difference, imho. Again, no difference, if you assume that the function code dispatching is to be efficient, i.e. through a vector table. Inserting, adding, removing jmp statements from a jump table is no more nor less easy than doing the same with a vector table and a list of function code definitions. I really don't see a substantial difference here. I can totally accept your reasons as your personal preferences; we all have our styles and tastes. But except for the potential need to route the entire API through a single indirect jmp, I don't see any substantial design advantages in what you argue for. Don't you ever want to pass some values from your registers into the API functions you call? Do all or most of your calls have constant parameters? Or do you then effectively create self-modifying code where you write into the params after the JSR statement? So implied saving and restoring of registers is essential to you, I understand?
  9. Ah! I never thought of that work flow. Thanks for the insight! I just realize that the page boundary bug is something of which I may have been not actively aware enough. Good reminder.
  10. Yes, I'm aware. The reference also mentions A, X, Y for byte-sized parms. Quoting: The 16 bit ABI generally follows the following conventions: arguments word-sized arguments: passed in r0-r5 byte-sized arguments: if three or less, passed in .A, .X, .Y; otherwise in 16 bit registers boolean arguments: .C, .N Incidentally, @Stefan's open-file call at $c003 uses r0 and r1 for the filename pointer and length. I'm sorry but I still don't see the point. The program can start after the growing jump table at the beginning of the ROM just as well. If the API is the jump table, then nobody gets hurt if the non-API program code gets shifted by 3 bytes after a new jump gets added to the jump table. It's not like a stack and a heap growing towards each other in a shared RAM space. The point, as I see it, of a jump table at the end of the ROM is that its position can be established independent of the ROM size, esp. in a case of 6502 machines where the ROM will be at the end of the address space. So, the same jump table works equally well and without change e.g. in 8k KERNALs (VIC20, C64) or 16k KERNALs (C16, C128, X16). Exactly the point why I would not place my own jump table at the end of the ROM. It even goes against extensibility. If I start my own ROM jump table at $FE00, I'd be in trouble as soon as the X16 KERNAL table grows down beyond that point. So, the two fixed-address things I would have grow towards each other would be my own jump table and the KERNAL jump table. My program could live happily in whatever space it finds in between.
  11. @kktos Why the boldface "No, please"? What is so horrible about a jump list? In what way would it be less easily expandable than a function id parameter? I don't see that. And I see a number of downsides of a function parameter in A, or the .db function_x, .dw parms_ptr @BruceMcF Ah, interesting; I realize that my own 65C02 fluidity still needs a good deal of work; I wasn't familiar with JMP (abs, x). Still, this would occupy X, leaving one register less for parameter passing. In general, a function_id parameter goes against one of my design principles, which is not to needlessly join code execution paths, only to divide them apart again based on a parameter that comes from a constant.
  12. One additional feature/option to take into account: An API jump list for the ROM, similar to the Kernal jump list at $ffxx. @Stefan and me discussed this in the context of X16Edit, and so far Stefan implemented one call without parameters at $c000 to start the editor with an empty file, and another call with a file name parameter at $c003 to open an existing file. I find a standard way to establish such an API extremely useful, and I think the beginning of the ROM would be the best place for it, because then, as Stefan wrote earlier, a ROM implementer has the option to also put a redirect copy of the Kernal API into the ROM, which a custom ROM jump list at the end of the ROM would make impossible. I like @BruceMcF's proposal of first a start jump. The API jump list could then follow the signature string and the versions. *= $c000 JMP DOSTART .byte 8,"xforth16", 0,1,0,0 API: JMP FUNCTION1 JMP FUNCTION2 ... This could be combined with the idea of a bra at $c000, defining the length of the signature block; then FUCNTION1 would have to essentially be DOSTART. I'm on the fence whether I would prefer this to the JMP + dedicated length byte, though. I'm also on the fence whether to define a standard address for the API, e.g. $c010. In a way it would be nice, but otoh it would limit the string length, and since the API will be ROM-specific anyway, I guess there is no harm having the jump list's start address being ROM-specific, too.
  13. Actually, it's only {|}~ where there's a problem, \^_ are at their usual ASCII codes for cc64. And even {|}~ get printed correctly under their usual ASCII code. The problem comes from the duplication of $60-$7f at $c0-$df in the PETSCII charset, or rather, the other way around, because shift-A on the C64 keyboard will give you $c1, not $61, and shift-plus (that's where { lives) will give you $db, not $7b, though both print as { (with my patched charset). I could change the mapping in my ascii2petscii and petscii2ascii tools such that {|}~ are left at $7b-$7e (just like [\]^_ are left at $5b-$5f) instead of mapping them to $db-$de, and for me who writes most code on Linux in ASCII, everything would work, and { would look like {, but natively on a C64 no-one could type { anymore. It's a bit of a catch. An ISO cc64 version would certainly be a good thing. For that an ISO X16 VolksForth would be needed, built on an ISO or ASCII target compiler. Playing around with other VolksForth platforms (Z80 or MSDOS or AtariST or generic 6502, all of which are ASCII-based) is one of my plans for the future, anyway, so I'll see what is possible.
  14. Glad to hear! Thank you! Yes, that is correct ... yet. Absolutely! The kernal-io-c64.c and kernal-io-c16.c files might serve as an example or a starting point. But going forward there should be at least a basic subset of the C standard library.
  15. Well, fun was and is the reason for doing cc64 in the first place. And Forth is and continues to be fun. But the original reason for using Forth was that it was the best high level language I could find on the C64 back then - powerful, practical, and producing very compact code. Danke, gleichfalls!
  • Create New...

Important Information

Please review our Terms of Use