rchennau Posted July 30, 2011 Share Posted July 30, 2011 I am stil hacking away... I've searched far and wide for CC65 examples that were very basic. I found some but I decided to write one as I go. Here is the result. #include <atari.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <conio.h> // standard cc65 for 'console' based applications /*************************************************************** * #define SAVMSC is a cc65 MACRO for the Atari 8-BIT platform. * * SAVMSC points to hardware register at memory location 88. * * refer to [url="http://www.atariarchives.org/mapping/memorymap.php"]http://www.atariarchives.org/mapping/memorymap.php[/url] * * * ***************************************************************/ The following define for SAVMSC is to assign a pointer #define SAVMSC *(unsigned int *) 88 // pointer to atari hardware register that holds the screen position address /*************************************************************** * __fastcall__ is a cc65 preprocessor command to place the * * the variable referenced at the top of the memory heap thus * * enabling faster access by the cpu * ***************************************************************/ void __fastcall__ statusLine(int x, int y, int capture); // debug line to display function variables. Should convert to a constructor int __fastcall__ getCalc(int oper, int x, int y, int z); // calculate the operation requested /************************************************************* * This program is built upon exercise 2.19 found in How to * * program C by Dietel / Dietel. It has been addapted * * to work on the Atari 8-Bit platform. * * * * Things to do: * 1. Call to statusLine should be done during a VLI * 2. Convert statusLine to a structure to handle more cases* 3. Use TGI (Having probelms loading driver) * *************************************************************/ void main(void) { int sum, average, product, smallest, largest; // create five operators for math calculations int i1, i2, i3; // create three integers for to be used by the five operators. char c; // character c is need to check for EOF / user exit cursor(1); // turn the atari cursor off gotox(0); // position the cursor on X line 0 printf("Enter three numbers: "); cscanf("%d", &i1); // need to add test for out of range entries statusLine(wherex(),wherey(),i1); // debug function to determine where cursor is and the value of i1 gotoxy(27,0); // Put cursor on Line X 0 and Y 27 as it was moved by statusLine cscanf("%d", &i2); statusLine(wherex(),wherey(),i2); gotoxy(30,0); cscanf("%d", &i3); statusLine(wherex(),wherey(),i3); gotoxy(10,6); // Move cursor to center of screen and display results sum = getCalc(1,i1,i2,i3); average = getCalc(2,i1,i2,i3); product = getCalc(3,i1,i2,i3); smallest = getCalc(4,i1,i2,i3); largest = getCalc(5,i1,i2,i3); printf("The sum = %d\n", sum); gotox(10); printf("The average = %d\n", average); gotox(10); printf("The product = %d\n", product); gotox(10); printf("The smallest = %d\n", smallest); gotox(10); printf("The largest = %d\n", largest); cursor(0); gotox(10); printf("Press Enter to exit"); while (1) { gotoxy(20,11); statusLine(wherex(),wherey(),c=cgetc()); if (c=='\n' || c==EOF) { break; } } return; } int __fastcall__ getCalc(int operand, int x, int y, int z) { switch (operand) { case 1: // calculate the sum operand = x + y + z; return operand; case 2: // calculate the average operand = (x + y + z) / 3; return operand; case 3: // calculate the product operand = x*y*z; return operand; case 4: // calculate the smallest if (x <= y && y <= z) return x; else if (x >= y && y <= z) return y; else (x >= y && x >= z); return z; case 5: // calculate the largest if (x > y && x > z) return x; else if (y > x && y > z) return y; else (z > x && z > y); return z; default: // no calculation return EOF; } } void __fastcall__ statusLine(int x,int y, int capture) { gotoxy(0,20); printf("You entered: %d\n", capture); printf("Position x = %d\n" ,x); printf("Position y = %d ",y); return; } 1 Quote Link to comment Share on other sites More sharing options...
rchennau Posted July 31, 2011 Author Share Posted July 31, 2011 Another good CC65 example may be found here: Google Translator to AtariOnline.pl 1. Araknoid (brick breaker) : Google Translator to AtariOnline.pl [b][font="Courier New"]#include < atari.h > #include < stdio.h > #include < peekpoke.h > #include < joystick.h > #define SCREEN_SIZE 40 #define PADDLE_SIZE 6 #define PADDLE_Y 20 #define COLOR1 0x2C5 #define COLOR2 0x2C6 #define CDTMV3 0x21C #define RANDOM PEEK(0xD20A) // 29 is '=' character in ANTIC character set #define BRICK 29 #define PADDLE 213 #define BALL 84 // Global variables unsigned char *video_ptr; unsigned char total_bricks; unsigned char paddle_pos=0; unsigned char ball_x,ball_y; signed char ball_dx,ball_dy; unsigned char lives=6; // Joystick extern char joy_driver; unsigned char joy; // Helper macros #define set_char(x,y,a) video_ptr[(x)+(y)*SCREEN_SIZE]=(a); #define get_char(x,y) video_ptr[(x)+(y)*SCREEN_SIZE] void set_colors() { POKE(COLOR1,0xFF); // font color POKE(COLOR2,0); // background color } void draw_bricks() { for (total_bricks=0;total_bricks < 4*SCREEN_SIZE;total_bricks++) video_ptr[total_bricks]=BRICK; } void draw_paddle() { register unsigned char s; for (s=0;s < PADDLE_SIZE;++s) set_char(s+paddle_pos,PADDLE_Y,PADDLE); set_char(paddle_pos-1,PADDLE_Y,0); set_char(paddle_pos+PADDLE_SIZE,PADDLE_Y,0); } void win() { for(; puts("Win!"); } void next_life() { unsigned char i; --lives; if (lives==0) { for(; puts("Game over"); } // show available balls for (i=0;i < lives;++i) set_char(i,PADDLE_Y+2,BALL); set_char(i,PADDLE_Y+2,0); // set_ball_position ball_x=paddle_pos+3; ball_y=18; ball_dy=-1; ball_dx=RANDOM%2?1:-1; } void move_ball() { // remove ball set_char(ball_x,ball_y,0); // bounce ball on the top of the screen if (ball_y==0) ball_dy=1; else if (ball_y==PADDLE_Y-1) // ball on the line of the paddle { // hit the paddle? if (ball_x > =paddle_pos && ball_x < paddle_pos+PADDLE_SIZE) ball_dy=-1; else // ball missed the paddle { next_life(); return; } } // bounce the ball on the borders if (ball_x==0) ball_dx=1; else if (ball_x==SCREEN_SIZE-1) ball_dx=-1; // change the ball position ball_x+=ball_dx; ball_y+=ball_dy; // ball hit the brick if (get_char(ball_x,ball_y)==BRICK) { if (--total_bricks==0) win(); ball_dy*=-1; } // draw ball set_char(ball_x,ball_y,BALL); } int main(void) { joy_install(&joy_driver); _graphics(0); set_colors(); // get screen memory pointer video_ptr=(unsigned char*)(PEEKW( PEEKW(560)+4 )); draw_bricks(); paddle_pos=(SCREEN_SIZE-PADDLE_SIZE)/2; next_life(); for(; { // wait a moment and read the joystick state after that POKE(CDTMV3,3); while(PEEK(CDTMV3)); POKE(0x4D,0); // Disable Attract mode joy=joy_read(JOY_1); if (JOY_BTN_LEFT(joy)) { if (paddle_pos > 0) --paddle_pos; } if (JOY_BTN_RIGHT(joy)) { if (paddle_pos < SCREEN_SIZE-PADDLE_SIZE) ++paddle_pos; } draw_paddle(); move_ball(); } return 0; }[/font][/b] Quote Link to comment Share on other sites More sharing options...
ilmenit Posted August 1, 2011 Share Posted August 1, 2011 Here is a topic with many examples of CC65 codes: http://atarionline.pl/forum/comments.php?DiscussionID=406&page=1#Item_0 3 parts of the programming tutorial: http://atarionline.pl/v01/index.php?subaction=showfull&id=1282312984&archive=&start_from=0&ucat=1&ct=nowinki http://atarionline.pl/v01/index.php?subaction=showfull&id=1282742930&archive=&start_from=0&ucat=1&ct=nowinki http://atarionline.pl/v01/index.php?ct=nowinki&id=1282846694&ucat=1&subaction=showfull 2 Quote Link to comment Share on other sites More sharing options...
funkheld Posted January 19, 2012 Share Posted January 19, 2012 he, can you PM in the GRAFIK 7 or GRAFIK 23 with the CC65 ??? thanks Quote Link to comment Share on other sites More sharing options...
Shawn Jefferson Posted January 20, 2012 Share Posted January 20, 2012 (edited) There are no built in functions in cc65 for doing PMG, but you can get to the hardware easily with C. BTW the explanation of fastcall in the code posted above is wrong. fastcall does something different in C code than in assembly code in the cc65 toolchain. Using fastcall in C will save some bytes but not really speed up execution. What it does, used in C code like shown in the code posted above, is move the "jsr pushax" into the function being called, rather than being done in the caller (saving bytes in your program, multiplied by how many times you are calling it.) Still a good thing to do though. Better is to rewrite the code in assembly, and use fastcall there, which will expect the last argument to the function to be passed via the A and X register. That does speed up your programs... Edited January 20, 2012 by Shawn Jefferson Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted January 20, 2012 Share Posted January 20, 2012 Are the sources for the A8 library available anywhere? Quote Link to comment Share on other sites More sharing options...
Irgendwer Posted January 20, 2012 Share Posted January 20, 2012 Are the sources for the A8 library available anywhere? All sources, for all components are available at cc65.org. Quote Link to comment Share on other sites More sharing options...
flashjazzcat Posted January 20, 2012 Share Posted January 20, 2012 Ah - got it - thanks. Don't know how I missed them! Quote Link to comment Share on other sites More sharing options...
funkheld Posted January 20, 2012 Share Posted January 20, 2012 (edited) sorry, I meant grafik7 and pm or pm and grafik7 and text. have here with this xforth. goes the same with the CC65? Edited January 20, 2012 by funkheld Quote Link to comment Share on other sites More sharing options...
Shawn Jefferson Posted January 21, 2012 Share Posted January 21, 2012 There is a command to change graphics modes, like the BASIC command GRAPHICS, but no drawing primitives. There is a cross-platform library callged TGI (Tiny Graphics Interface) that has some limited graphics mode support and graphics primitives like plot, line, etc... You could use other people's work and re-use it. There are some examples of graphics and PM manipulation with CC65 around the forum. Quote Link to comment Share on other sites More sharing options...
rchennau Posted September 3, 2013 Author Share Posted September 3, 2013 I picked up the proverbial coding pen again and am working on a Dungeon crawler. Not much progress but I've finally found something I can sink my teeth in. I've always enjoyed D&D. I've uploaded the code to github and made it public for any one who is starting out with CC65 or C for that matter. I try to heavily comment my code. Mostly so I can remember what it was I was trying to do... code link: https://github.com/rchennau/CharacterGen/tree/master/Dungeon (I know I've reversed the naming logic). Next up is to crate a linked list to store the die rolls and allow the users to scroll back and forwards. I should probably cap it at ten and make it a circular linked list. I've looked at umoria, imoria and angband source for character generation and honestly it is either poorly documented or overly complicated. But maybe that is how things end up after simple beginnings. Quote Link to comment Share on other sites More sharing options...
ilmenit Posted September 3, 2013 Share Posted September 3, 2013 Some comments on your code: - NEVER use structs - it requires a huge 6502 code to handle them properly in C. - NEVER use dynamic memory allocation (malloc etc.) - Atari memory is too small for that. You will also encounter many problems with aligned data (required for most of the GFX related stuff). - remember to use "signed" type or set a proper compiler option. By default types without it are unsigned in CC65. - use unsigned char wherever possible instead of int. int is 16 bit - handling it on 6502 requires a lot of code and CPU time. - it's the best to: typedef unsigned char byte; Quote Link to comment Share on other sites More sharing options...
danwinslow Posted September 3, 2013 Share Posted September 3, 2013 (edited) Being a 'C' programmer from way back, I was very excited to run into the CC65 compiler. After extensive use, though, I agree with what ilmenit said and would add the following ( all my opinion only, of course, your mileage may vary ) : ( Note - this applies only to large programs, especially games - you can knock out quick utils and small programs without worrying about all these restrictions ) 1. Don't code as you would for normal C programs. You will run out of memory. 2. Call the OS rather than using stdio or stdlib. That may sound extreme, but you can usually code your own versions of exactly what you need without pulling in the relatively large runtime library. For example, use CIO calls instead of fopen(), etc. Create your own print routines, again with CIO. 3. Don't be afraid to drop into assembler for small functions, its very well handled by the compilation system. 4. Watch your parameter stack usage..basically you don't want to pass/return anything more than a byte or word or two to/from functions. This will allow you to cut down the huge 2k default parm stack size. Use globals and externs to reduce the need to pass stuff around. 5. Place your own memory blocks, using address specification and/or a custom linker config.. 6. Structs are ok to format data conceptually, as long as you dont pass them around and don't use the -> or . operators to fetch things a lot. You can use unions or address offset #defines to place named items for easy access. I found it best to think of CC65 as a very sophisticated macro assembler rather than as the full fledged C compiler that it is. This is strictly due to limitations of the machine, and not of CC65 itself, which is a very good C compiler. Edited September 3, 2013 by danwinslow 2 Quote Link to comment Share on other sites More sharing options...
rchennau Posted September 6, 2013 Author Share Posted September 6, 2013 ilmenit and danwinslow, Thank you for the feedback. I tried some of the things suggested and indeed was able to drop the size of the xex by a full 1K. Nice for such a simple program at this point. I'll have to research on exactly how to call the OS routines direct vs. using stdlib and stdio. This is actually fun and a challenge. Changes posted to github Quote Link to comment Share on other sites More sharing options...
ilmenit Posted September 6, 2013 Share Posted September 6, 2013 (edited) You are still using structs. Instead of typedef struct characterStats{ int wisdom; int intelligence; ... use char wisdom[CHARACTERS_MAX]; char intelligence[CHARACTERS_MAX]; then you can replace pointers by indexes: void buildCharacter (struct characterStats *thisCharacter); to void buildCharacter (byte index) { wisdom[index] = rollDice(index, 1) + wisdom[index]; ... } 6502 CPU can easily address arrays like that while is terrible at addressing by pointers. You will save at least a few kilobytes in the full program. Also in: void addRaceModifiers (unsigned char *race, struct characterStats *thisCharacter); do not use pointer: unsigned char *race;use simply byte race_index; Do not use magic values like 5, use enums or #DEFINEs : thisCharacter->floor = human[5]; The last mentioned function is especially bad. Place race modifiers in two-dimensional table. You can remove the switch-cases then. char race_modifiers[RACES_MAX][STATS_MAX] = { {2,1,2,0,2,5,14}, // elf {1,-1,1,2,2,6,14}, // dwarf {0,0,0,0,0,6,14}, // human {2,2,0,-2,-2,3,14} // planes }; void addRaceModifiers (byte race_index, byte char_index) { wisdom[char_index] = race_modifiers[race_index][STATS_WISDOM]; floor[char_index] = race_modifiers[race_index][STATS_FLOOR]; max[char_index] = race_modifiers[race_index][STATS_MAX]; }; Edited September 6, 2013 by ilmenit Quote Link to comment Share on other sites More sharing options...
rchennau Posted September 13, 2013 Author Share Posted September 13, 2013 Version with suggested changes. I still need to research how to avoid printf in favor of 'call the OS'. My next step is to record three sets of rolls and let the user scroll through them and accept the one they like. Endless rolling seems like a cheat to me. https://github.com/rchennau/CharacterGen/tree/master/Dungeon Quote Link to comment Share on other sites More sharing options...
Shawn Jefferson Posted September 13, 2013 Share Posted September 13, 2013 (edited) I'd stick with the conio screen output... you won't get screen scrolling, since it prints direct to screen memory. Avoid printf (if you can) I still think writing programs in C is fine... optimize where and when you need to. Time's more important than saving 2k, unless you absolutely need that 2k (then you can optimize). There's lots of tricks you can use to optimize without going to asm as well (a lot mentioned in this thread). Use zeropage variables where you can, globals (puts the variable in BSS or DATA segments and simplifies the generated code to access it), optimize your loops, optimize screen draws, etc... Edited September 13, 2013 by Shawn Jefferson 1 Quote Link to comment Share on other sites More sharing options...
Wrathchild Posted September 13, 2013 Share Posted September 13, 2013 I'd agree, its fine to get things going in C first then later optimise some code into asm source instead, even drawing upon what the orginal C->asm looked like. Quote Link to comment Share on other sites More sharing options...
ilmenit Posted September 14, 2013 Share Posted September 14, 2013 Version with suggested changes. I still need to research how to avoid printf in favor of 'call the OS'. My next step is to record three sets of rolls and let the user scroll through them and accept the one they like. Endless rolling seems like a cheat to me. https://github.com/rchennau/CharacterGen/tree/master/Dungeon Take a look at the sources of my simple game Viper here . It shows how to print a text with a simple conversion to ATASCII. However what I recommend when you use your own font set is to place letters in the set according to ASCII standard. Then you can ASCII strings easier. 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
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.