Jump to content

damosan

Members
  • Content Count

    126
  • Joined

  • Last visited

Everything posted by damosan

  1. #include <atari.h> ... direction = OS.stick0;
  2. Huh. They must of added definitions of byte/word in that release...
  3. What version of the compiler are you using? I'm running 2.19.
  4. Yeah - I had aligns in there initially but the linker would complain about the code segment not being aligned. It'd still work of course - I need to modify the linker config to align the data segment to a page. I made some changes to the assembly (using res) but kept the other tables as they were as someone new to 6502 assembly and ca65 may be confused with the repeat/endrep stuff. I'm thinking of new ways to plot pixels where the LDA/ORA/STA sequence will work with absolute addresses instead of lookups. It's going to take a lot of space of course.
  5. Yes... a header named common.h. I forgot to add it to github - it's there now. Sorry about that.
  6. Attached is a link to a graphics mode 8 pixel plotting test harness. It includes all sorts of ways to plot a single pixel on a graphics 8 screen from the slowest (~13 pixels / jiffy) to the fastest I've managed (~332 pixels / jiffy) on an NTSC machine (on a PAL machine the counts are ~17 / ~427 pixels per jiffy). The various methods are all general purpose routines meant to plot a pixel at a given location. There are two "cheat" tests that are optimized for the use case of filling a screen. The project also serves as an example of interfacing CC65 with external assembly code, how to pass variables using the zeropage, and how (in some cases) not to plot pixels. It also includes a routine to plot text on a gr8 screen. This little project was made possible by all the code folks have published over the years as well as the conversations I've had on AtariAge. Next step is to add sprites... https://github.com/damosan314/gr8 gfx.xex
  7. Yeah I've done it with CC65 - once you understand the linker config everything just falls into place.
  8. I would love to see an example of this in action i.e. main program + 1-4 banks. Ideally any data defined within that bank stays there vs. being lumped together with other vars. The bank switcher code would have to reside in main memory outside the window of course and require a stack to remember which bank it came from when making the switch to a new bank.
  9. It's possible to write code that compiles with both compilers depending on what CC65 features you leverage (CC65's atari.h for example). For a time my source code would compile with either CC65 or MOS but I eventually settled on MOS.
  10. If I'm understanding you correctly... d4 = No remainder set d6 = 252 d8 = No remainder set d10 = 250 d12 = 252 d20 = 240 d100 = 200
  11. At first I tried to do this with the C++ compiler and it had issues. So I switched to C. The C compiler is pretty darn good. I started by writing standard C code for everything without applying any of the standard CC65 code optimizations. The code ran pretty quick. Small test apps compile down very small. But once you start writing naïve C apps the binaries get large. "naïve" in this context is standard C e.g. passing structs, using nested structs, structs in general, generic linked lists, etc. As RL2 started to actually take shape the binary was pushing right up against 0xbc00 which is a problem because the static locals area went beyond 0xbc00. So then I started rewriting parts of the game using CC65 style "easy" optimizations such as reducing the amount of structure references across the board, aligning small lookups to page boundaries, etc. In general the standard CC65 optimizations results in smaller code. I compiled the following code snippet in a GR8 test app - with will optimization flags set: void plot_savmsc( word x, word y ) { word address = ( y * 40 ) + ( x / 8 ); byte mask = 0x80; byte current_byte; current_byte = PEEK( SAVMSC + address ); mask = 0x80 / ( x % 8 ); POKE( SAVMSC + address, current_byte | mask ); } word plot_savmsc_test( void ) { word x, y; lbzero( (byte *)SAVMSC, 8192 ); print_at( 0, 23, "Naive plot" ); clear_clock(); for( y = 0; y < 192; y++ ) for( x = 0; x < 320; x++ ) plot_savmsc( x, y ); return getJiffies(); } The above code fills a graphics 8 screen. CC65 ran in 4587 jiffies while MOS did so in 2631. Another test leveraging lookups saw CC65 running in 2663 jiffies while MOS ran in 396 jiffies. I have C code that leverages page zero that brings CC65 down to 664 jiffies while MOS runs in 358. The compiler is pretty good. You don't have complete control over the binary like you do with CC65. At first the game font was aligned to a 1k boundary via a clang attribute. This allows you to create font or player missile regions easily enough but it tends to create gaps in the binary. As you write additional code these gaps get filled. I decided I needed a custom loader for the game so I didn't have to rely on the compiler aligning large memory objects. So I took the ramrom.asm and modified it to act as a font / game loader. I will say the size optimization is pretty good - single use functions are basically inlined to save subroutine pre/post code. I normally compiled with -Oz; when I compiled without this flag the raw binary was very large (over 50k). When I started generating map files to see what the compiler was doing I was shocked to find a three line routine took ~3k of ram...but the compiler was doing the right thing. Dead code removal is 100%. The memory allocator is pretty good. It seems that each malloc() takes 2 bytes to keep track of things. I could be wrong here. Clang has a rather...extensive...syntax on inline assembly. It's *far* easier to write assembly functions and just link them in. Declaring variables VOLATILE is important. My only real complaints are as follows: 1) How the compiler handles locals in a function. It basically creates a memory area named <function_name>_stk (or something like that) which wasted about ~450 bytes. I know software stacks are slow...but I'd like the option to have one. The heap starts at the end of the *_stk definitions. 2) The included supplied printf() is a full implementation so eats a ton of memory (like 4k). If your code references LONGs you will bring in the math libraries for 32+ bit integers. That's a ton of code. Sticking to bytes / words keeps things small. The a_printf() function in the game supports strings, bytes, words, and characters. 3) (Not really a complaint) But the standard library is very small. I had to create fopen()/fclose()/fread()/fwrite() using CIO calls. Not a big deal if you have some C and Atari experience. Atari programmers new to C may wish to stick with CC65 in the beginning. 4) Using extended memory will require some hacking compared to CC65 (once you figure out the linker file format CC65 makes this almost easy).
  12. Then fix it. It works well enough for the standard d4, d6, d8, d10, d12 dice it was meant to support.
  13. Here's what I used in my assembly language roguelike project. It's not as efficient as it should be (see dice2 loop to calculate the modulus) but it works. Usage: ldx #3 ldy #6 jsr dice sta strength ;;; generate player's strength ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; dice - rolls X dice of Y sides storing result in accum. TRND & TSIDES ;; are byte variables defined elsewhere. ;; dice lda #0 sta trnd ; temp result bucket sty tsides ; number of sides on the dice dice1 lda RANDOM ; get random number from hardware sec dice2 sbc tsides ; subtract the number of sides bcs dice2 ; carry set? Subtract again! adc tsides ; now accum = n mod m (0 .. m-1) clc adc trnd ; add accum to trnd sta trnd ; store it back to trnd inc trnd ; increment trnd by one so n mod m range is (1 .. m) dex ; another dice? bne dice1 ; yup, do it again! lda trnd ; store temp random to accum and return rts
  14. The batch file is a hack ... so you will need to edit the file to match your setup. But here are the three ATRs. Once you're in the dungeon press '?' to get help. At some Yes/No prompts you can press 'C' to cheat. RL2.ATR RL3.ATR RL4.ATR
  15. I've been playing with LLVM-MOS for a bit now and have created a collection of "almost done" roguelikes using the toolchain. What's included: basic CIO code to read/write from disk, an assembly autorun.sys that copies the OS to RAM and then loads a binary and executes it, the start of a VBI based sound library, a small printf()/sprintf(), etc. Personally I'd classify the whole thing as a hack job but there are bits that you may find useful for other things. Take the code...make it better...do what you want. Impressions of LLVM-MOS: I like it. It's a modern compiler that generates some tight code. You still pay the penalty for using structures so global arrays are the way to go. You can use pragmas to align variables (such as lookup tables aligned to pages, fonts, P/M graphics) and while the compiler does an OK job of filling the gaps care should be taken. The C++ compiler has some issues so stick with C. damosan314/roguelike: A collection of nearly done simple roguelikes for the Atari 8bit using the MOS-LLVM C compiler (github.com)
  16. This is really cool but how useful is it? Once you have a JVM running on a 48/64k machine how much is left over for byte code? I built a toy VM a few years ago implementing a 16 instruction stack machine. It worked well and I started to implement some of the core in assembly but then the tech ADHD SQUIRREL! happened...
  17. But cc65 doesn't do that thankfully. Unless you want it to... I'm pretty sure the linker pulls in what it needs - looking at the map file shows this. If you want printf() style output you can always build your own using variable arguments. My lw_printf() routine handles strings, bytes, and words and weighs in at around 640 bytes.
  18. I applied a few changes to a previous version in C and then passed it through cc65 (with -Osir) to see the resulting code. It doesn't look too bad. Instead of using X = X + 1 I used ++X (and --X) which allows cc65 to use inc/dec vs. the lda/clc/adc. lda _flicker beq L0002 lda #$04 sec sbc _FLIP sta _FLIP lda _CHAddr clc adc _FLIP jmp L000F L0002: lda _CHAddr clc adc #$08 L000F: sta $02F4 inc _TOGL lda _TOGL cmp #$04 bne L000D lda #$00 sta _TOGL lda _ExAnim0 beq L0011 sta $02C0 dec _ExAnim0 jmp L0012 L0011: sta $D000 L0012: lda _ExAnim1 beq L0014 sta $02C1 dec _ExAnim1 jmp L0015 L0014: sta $D001 L0015: lda _ExAnim2 beq L0017 sta $02C2 dec _ExAnim2 jmp L0018 L0017: sta $D002 L0018: lda _ExAnim3 beq L001A sta $02C3 dec _ExAnim3 rts L001A: sta $D003 L000D: rts
  19. How long did folks use the Alcyon compiler in anger? I suspect folks dumped it the minute better compilers became available - I remember using Haba Hippo-C and Megamax C in 86/87.
  20. If you're only going to do a few bytes at a time... ldx #0 lda $6000,x sta $7000,x inx <repeat n times> ...or do you have to use Y for this? Doesn't matter as the point is you can inline byte copies for a small number of bytes easily. The code will run quite a bit faster as there are no compares, no jumps, etc. You can probably use ZP as well to reduce the byte counts and increase speed further. This is where ca65 comes in handy - you can create a core repeat macro and then create all sorts of byte copies for arbitrary sizes at assembly time. Or make it smarter so that it will try to use inline code but if it cannot then it hops over to memcpy().
×
×
  • Create New...