So all the other functions are synthesized from combinations of the newlib syscalls?
Sorry that I can't test this as I don't have a dev environment atm but this should work for _Exit


Code:
void _Exit(int code)
{
     asm("mov.l #0x881dfffc,r2\n\t"
         "lds.l @r2+,pr\n\t"
         "rts\n\t"
         "mov r4,r0");
}
Qwerty, yes it takes what you give it and has code to cover what the OS or platform syscalls do not.
Now for abs, another rather easy routine, for now I'll stay away from the float routines.

btw I love asm Very Happy


Code:

int abs(int i)
{
     asm("shlr r4\n\t"
         "rotcl r4\n\t"
         "rts\n\t"
         "mov r4,r0");
}
Here are a couple small routines someone might find useful.

Switch register banks:

Code:
stc sr, r8
mov.l 1f, r9
or r9, r8
ldc r8, sr


1 byte ASCII number -> Hex (r4 and r5 contain the high and low nibbles respectively):


Code:
xor r7,r7
Start:
add r7,r4
add #0xE0,R4
mov #0x3A,r6
cmp/hs r4,r6
bf/s Start
mov #0xFF,r7
shll2 r4
shll2 r4
          /* Loop is unrolled here for speed, but you could easily loop back to the beginning for this after storing r4 to a safe register. */
xor r7,r7
Start2:
add r7,r5
add #0xE0,R5
mov #0x3A,r6
cmp/hs r5,r6
bf/s Start
mov #0xFF,r7
rts
add r5,r4
z80man wrote:
Sorry that I can't test this as I don't have a dev environment atm but this should work for _Exit


Code:
void _Exit(int code)
{
     asm("mov.l #0x881dfffc,r2\n\t"
         "lds.l @r2+,pr\n\t"
         "rts\n\t"
         "mov r4,r0");
}


For some reason the SDK doesn't like that routine. Apparently it gives "invalid opcodes" -- though I tried some simpler stuff and it worked fine. I even split it up into parts in case this version of gcc didn't like the suffixing newline and forced tab:


Code:
        __asm__("mov.l #0x881dfffc,r2");
        __asm__("lds.l @r2+,pr");
        __asm__("rts");
        __asm__("mov r4,r0");


yet it still throws the same error. I looked at the Renseas documentation for SH3 assembly and it seems as if these instructions are written valid.
z80man wrote:
Now for abs, another rather easy routine, for now I'll stay away from the float routines.

btw I love asm Very Happy


Code:

int abs(int i)
{
     asm("shlr r4\n\t"
         "rotcl r4\n\t"
         "rts\n\t"
         "mov r4,r0");
}

This doesn't seem right to me. You're shifting to the right by one bit, and then rotating left with carry by one bit. That doesn't change the value at all. Maybe this would work:

Code:

float abs(float i)
{
     asm("shll r4\n\t"
         "shlr r4\n\t"
         "rts\n\t"
         "mov r4,r0");
}


Edit: And I assume this is a floating point routine? You really shouldn't be passing and returning ints then.
Quote:
This doesn't seem right to me. You're shifting to the right by one bit, and then rotating left with carry by one bit. That doesn't change the value at all. Maybe this would work:

Code:

float abs(float i)
{
     asm("shll r4\n\t"
         "shlr r4\n\t"
         "rts\n\t"
         "mov r4,r0");
}


Edit: And I assume this is a floating point routine? You really shouldn't be passing and returning ints then.

abs is an integer function in C. The floating-point version is fabs, which can simply clear the high bit in a IEEE754 floating-point system (which is what your code seems to do).

By the way, how big are the int and long types on the sh3/sh4? Are they the same size? If so, labs can be defined as a macro that expands to abs:

Code:
#define labs abs

Likewise for other long functions with int counterparts.

Of course, for routines this small, it's probably better to inline the code and let the compiler optimize it:

Code:
static inline int abs(int i) { return i < 0 ? -i : i; }

(That code would be put inside stdlib.h).

While that uses a test and branch conceptually, it's a common idiom, and I believe gcc can optimize it to a few simple instructions (depending on the target architecture). Test it out for sh3 by compiling to assembly code (gcc -O2 -S).

Edit: forgot the "int" between "inline" and "abs". Rolling Eyes
Indeed, I trust GCC to be able to optimize the standard abs() idiom effectively, and I use it several times within Obliterate.
So, here I finally made a new routine that seems *really* random. When I didrectly used it in my map generating routine to take the result of this routine seeded with 0 and mod 6, the tile output showed no patterns whatsoever. However, I attained it by keeping the RTCtimer at bay for a *long*, *random*, time. Anyways, the routine on it's own, which can even seed itself or get seeded by the RTC_GetTicks:


Code:
unsigned short random(int extra_seed) {
   int seed = 0;
   int seed2 = 0;
   for(int i = 0; i < 32; i++ ){
      seed <<= 1;
      seed |= (RTC_GetTicks()%2);
   }
   for(int i = 0; i < 32; i++ ){
      seed2 <<= 1;
      seed2 |= (RTC_GetTicks()%16);
   }
   seed ^= seed2;
    seed = (( 0x41C64E6D*seed ) + 0x3039);
   seed2 = (( 0x1045924A*seed2 ) + 0x5023);
   extra_seed = (extra_seed)?(( 0xF201B35C*extra_seed ) + 0xD018):(extra_seed);
   seed ^= seed2;
   if(extra_seed){ seed ^= extra_seed; }
    return ((seed >> 16) ^ seed) >> 16;
}



It basically gets one bit from the timer at a time for the first seed, and then the second, "darker" seed (higher chance of filled bits), each bit gets 4 oppertunities to be seeded with a 1. It then goes through the standard wacky operations to fill in the bitfield better, xors the available seeds together, and returns them as a short. Very loosly based on simon's routine.

It's random *depending on how it's used*. If you use it every now and then, it will be *surely* random, if you seed it with RTC_GetTicks or another varying number (even with a seed of 0 it will still be random, though). In loops, it's fixed by slowing down operation in tradeoff for randomiscity:


Code:
   for(int i = 0; i < 3600; i++) {
      (*(map+i)).natural_cell = random(random(RTC_GetTicks()))%6;
      OS_InnerWait_ms(random(0)%64);
   }



As you see above, the actual random value is seeded by another random value that is not seeded, which worked really well. For the OS_InnerWait_ms, I have it wait for an unseeded random time, mod 64 (so it won't wait a very long time, and since the RTC timer increments 64 times a second, it should give it long enough to increment in usual cases.

All because of a rand() and srand() linking error Smile fun night spent.
I'd be interested in seeing millions of values being collected, and average, stddev, and other probabilistic measures applied to ensure that it's doing a decent job at generating coherent, unbiased randomness. Looks good from a brief perusal of the code, though.
I tested the bottom three bits of it so far, and it does seem to be doing quite well with these lower bits. It does seem to have some minor flukes, i.e. every now and then it will generate the same number up to 4 times in a row, and it's more likely to output 0's, 2's, and 6's in the lower bits, but they only seem to have a slightly larger occurrence -- per 6000, so far it seems that:

000 - 15%
001 - 14%
010 - 14%
011 - 13%
101 - 14%
110 - 16%
111 - 13%

^ the percents turned out rather even, and the way I collected the data was tedious (literally plugged in the random function for map generation % 8 and counted each tile's occurrence and looked for patterns Razz) Maybe once I have a decent print function for numbers working well I'll test with much higher quantities and have it generate these stats itself (i.e, leave it running for a day with the test code running)
Patterns of up to four in a row are fine; although they're still random, our brains like to pick them out as anomalies. With a random number generator, since every generated number is uncorrelated with the previous, a string like 4 4 4 4 4 4 4 4 4 is just as likely as 1 4 2 4 1 4 2 3 4 2.
hmm, that's true. Never thought about that Razz I guess if it never outputted the same number more than once in a row, it wouldn't truly be "random".

That being said, I did notice one pattern -- 2's and 5's are very likely to be generated right next to each other -- so that if a 2 was generated, it's more likely that the next result would be a 5 than most other numbers -- perhaps just something else my brain picked up on, though that seems a bit different than the "four in a row" pattern, since this is a bit more common and isn't a feature of normal random number generation, from what I researched a few days ago on the subject.
You can easily test bigraphs to see if that is indeed the case, something like:


Code:
unsigned int bigraphs[maxval+1][maxval+1];
for(int i=0;i<maxval;i++) {
  for(int j=0;j<maxval;j++) {
    bigraphs[i][j] = 0;
  }
}
int prevval = 0, val=0;
for(int i=0; i<1<<20; i++) {
  val = random();
  bigraphs[prevval][val]++;
  prevval = val;
}
for(int i=0;i<maxval;i++) {
  for(int j=0;j<maxval;j++) {
    printf("%d, %d: %f%%\n",i,j,100*(bigraphs[i][j]/(1<<20)));
  }
}
Of course, you'd need to use Prizm PrintXY's for the final part.
Interesting, never heard of a test like that (though probably because the first time I looked into real RNG was when I made that last routine), but I'll try it Smile

on a side note, does the Prizm even have a routine like printf, or at least one that can print numbers without a conversion routine? A converter wouldn't be hard to make, but still..
The more I look at it we may just be better off implementing the wanted libc functions right in libfxgc, porting newlib might be difficult solely because there is not a good generic platform for sh3 to work off of like there is for more common platforms.

On a related note, for my next sdk release the crt0.s will be moving into libfxgc since we have finally stablized it thanks to calc84's help. I also think I am ready to start adding C routines such as libc replacement functions and prizm specific functions. The other thing will be possibly working on some real documentation, though the prizm wiki may be the best place for that.

As for your random function, the libc example implementation one from redhat is what I use currently, just seeding it with the rtc seconds counter should be more than adaquate.
This routine will print masked Glyph numbers for you Smile kinda application specific, but others could find use of it.


Code:
void drawprintnum(int x, int y, int num, int width, int height, void*glyph_nums) {
   int digits[10] = {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1};
   int pos_num = (num<0)?(-num):(num);
   int num_digits = 0;
   for(int i = 0; i < 10; i++) {
      if(!pos_num) { break; }
      digits[i] = pos_num%10;
      pos_num = (pos_num - (pos_num%10)) / 10;
      num_digits++;      
   }
   if(num<0) {
      CopySpriteMasked(glyph_nums + (width*height*2*10), x, y, width, height, 0xFFFF);
      x += width+2;
   } else if (num == 0) {
      CopySpriteMasked(glyph_nums, x, y, width, height, 0xFFFF);
      return;
   }
   for(int i = 0; i < num_digits; i++) {
      CopySpriteMasked((digits[i]*(width*height*2))+glyph_nums, x, y, width, height, 0xFFFF);
      x += width+2;
   }
}
A good way to do non-blocking key reading, allowing MENU, and not having annoying color glitches:


Code:
unsigned short key;
int kcol, krow;

[...]
GetKeyWait_OS(&kcol,&krow,KEYWAIT_HALTON_TIMEROFF,1,0,&key);
Bdisp_EnableColor(1);
[...]
Is there a getkey routine that allows multiple keys to be checked for being pressed at the exact same time? Such as, it returns an array of all the keys, and you could do something like this?


Code:
char key[];
...
key = GetKeyASDF();
if(key[KEY_PRGM_RIGHT]&&key[KEY_PRGM_SHIFT]) { ... }


I noticed Kerm's new routine for key reading seems to work with key rows and key columns, and the other one that was non-blocking used some sort of "unsigned char buffer[12]" against which to check for key values, that was condensed into one "key" value. Would I be able to check rows/columns or parts of that small buffer for multiple keys at the same time?
  
Register to Join the Conversation
Have your own thoughts to add to this or any other topic? Want to ask a question, offer a suggestion, share your own programs and projects, upload a file to the file archives, get help with calculator and computer programming, or simply chat with like-minded coders and tech and calculator enthusiasts via the site-wide AJAX SAX widget? Registration for a free Cemetech account only takes a minute.

» Go to Registration page
» Goto page Previous  1, 2, 3, 4, 5, 6 ... 10, 11, 12  Next
» View previous topic :: View next topic  
Page 5 of 12
» All times are UTC - 5 Hours
 
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 vote in polls in this forum

 

Advertisement