From 33613a85afc4b1481367fbe92a17ee59c240250b Mon Sep 17 00:00:00 2001 From: Sven Eisenhauer Date: Fri, 10 Nov 2023 15:11:48 +0100 Subject: add new repo --- .../ARM202U/EXAMPLES/EXPLASM/BYTEDEMO.C | 148 ++++++++++++++ .../ARM202U/EXAMPLES/EXPLASM/DIVC.C | 213 +++++++++++++++++++++ .../ARM202U/EXAMPLES/EXPLASM/RANDOM.S | 42 ++++ .../ARM202U/EXAMPLES/EXPLASM/RANDTEST.C | 20 ++ .../ARM202U/EXAMPLES/EXPLASM/RANTEST.APJ | Bin 0 -> 92 bytes .../ARM202U/EXAMPLES/EXPLASM/UDIV10.S | 23 +++ .../ARM202U/EXAMPLES/EXPLASM/UTOA.APJ | Bin 0 -> 101 bytes .../ARM202U/EXAMPLES/EXPLASM/UTOA1.S | 60 ++++++ .../ARM202U/EXAMPLES/EXPLASM/UTOATEST.C | 22 +++ 9 files changed, 528 insertions(+) create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/BYTEDEMO.C create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/DIVC.C create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANDOM.S create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANDTEST.C create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANTEST.APJ create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UDIV10.S create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA.APJ create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA1.S create mode 100644 Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOATEST.C (limited to 'Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM') diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/BYTEDEMO.C b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/BYTEDEMO.C new file mode 100644 index 0000000..209b4f0 --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/BYTEDEMO.C @@ -0,0 +1,148 @@ +/* Explanation of byte-reversing in ARM assembler + + for PC only (uses cursor control codes) +*/ + +#include + +static void cls() +{ + printf("\033[2J"); +} + +static void up(int n) +{ + while (n > 0) + { printf("\033[1A"); --n; + } +} + +static void pause() +{ + fprintf(stderr, "Please press to proceeed "); + while( fgetc(stdin) != '\n' ); +} + +static void prologue() +{ + printf("\ + AMAZING FACTS ABOUT THE ARM - Reversing the bytes in a word\n\ +\n\ +This function reverses the bytes in a word. The method was discovered in\n\ +1986 following a competition between ARM programmers; it requires just 4\n\ +instructions and 1 work register. A method using only 3 instructions per\n\ +word reversed was also found, but it has some set-up overhead and uses a\n\ +2nd register. Can you re-discover this method?\n\ +\n\ +Later, the C compiler was 'taught' to generate exactly the instructions\n\ +needed, from C source. Check this claim using armcc -S -DREV byterev.c\n\ +and examining the assembly code file produced.\n\ +\n\ +unsigned long reverse(unsigned long v)\n\ +{ unsigned long t;\n\ + t = v ^ ((v << 16) | (v >> 16)); /* EOR r1,r0,r0,ROR #16 */\n\ + t &= ~0xff0000; /* BIC r1,r1,#&ff0000 */\n\ + v = (v << 24) | (v >> 8); /* MOV r0,r0,ROR #8 */\n\ + return v ^ (t >> 8); /* EOR r0,r0,r1,LSR #8 */\n\ +}\n\ +\n\ +To see the method in action, press . Each time you press \n\ +one step of the reversal process will be executed. The values displayed\n\ +are symbolic, starting with the input word D C B A.\n\ +\n"); +} + +static void prelude() +{ + printf("\ + AMAZING FACTS ABOUT THE ARM - Reversing the bytes in a word\n\ +\n\ +unsigned long reverse(unsigned long v)\n\ +{ unsigned long t;\n\ + t = v ^ ((v << 16) | (v >> 16)); /* EOR r1,r0,r0,ROR #16 */\n\ + t &= ~0xff0000; /* BIC r1,r1,#&ff0000 */\n\ + v = (v << 24) | (v >> 8); /* MOV r0,r0,ROR #8 */\n\ + return v ^ (t >> 8); /* EOR r0,r0,r1,LSR #8 */\n\ +}\n\ +\n"); +} + +static void show_state_1() +{ + printf("\ + v / r0 t / r1 original input in v/r0\n\ +\n\ + +---+---+---+---+ +---+---+---+---+\n\ + | D | C | B | A | | x | x | x | x |\n\ + +---+---+---+---+ +---+---+---+---+\n\ +\n\n\n\n\n\n\n"); +} + +static void show_state_2() +{ + printf("\ + v / r0 t / r1 state after executing \n\ +\n\ + +---+---+---+---+ +---+---+---+---+ t = v ^ ((v<<16) | (v>>16));\n\ + | D | C | B | A | |D^B|C^A|B^D|A^C|\n\ + +---+---+---+---+ +---+---+---+---+ EOR r1,r0,r0,ROR #16\n\ +\n\n\n\n\n\n\n"); +} + +static void show_state_3() +{ + printf("\ + +---+---+---+---+ +---+---+---+---+ t &= ~0xff0000; \n\ + | D | C | B | A | |D^B| 0 |B^D|A^C|\n\ + +---+---+---+---+ +---+---+---+---+ BIC r1,r1,#&ff0000 \n\ +\n\n\n\n\n\n\n"); +} + +static void show_state_4() +{ + printf("\ + +---+---+---+---+ +---+---+---+---+ v = (v << 24) | (v >> 8);\n\ + | A | D | C | B | |D^B| 0 |B^D|A^C|\n\ + +---+---+---+---+ +---+---+---+---+ MOV r0,r0,ROR #8 \n\ +\n\n\n\n\n\n\n"); +} + +static void show_state_5() +{ + printf("\ + +---+---+---+---+ +---+---+---+---+ v = v ^ (t >> 8); \n\ +\n\ + +---+-^-+-^-+-^-+---+ +---+---+---+---+ EOR r0,r0,r1,LSR #8\n\ + |D^B| 0 |B^D|A^C|\n\ + +---+---+---+---+\n\ +\n\ + +---+---+---+---+\n\ + | A | B | C | D | (original input was: D C B A)\n\ + +---+---+---+---+\n\ +\n"); +} + +int main() +{ + cls(); + prologue(); + pause(); + cls(); + prelude(); + show_state_1(); + pause(); + up(13); + show_state_2(); + pause(); + up(11); + show_state_3(); + pause(); + up(11); + show_state_4(); + pause(); + up(11); + show_state_5(); + pause(); + fputc('\n', stdout); + return( 0 ); +} diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/DIVC.C b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/DIVC.C new file mode 100644 index 0000000..3a5d85c --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/DIVC.C @@ -0,0 +1,213 @@ +/* Optimal divide-by-contstant code generator + Advanced RISC Machines +*/ + + +#include +#include + +#define BANNER "generated by divc 1.02 (Advanced RISC Machines)" +#define DATE "27 Jan 94" + +#define DIVIDE_BY_2_MINUS_1 0 +#define DIVIDE_BY_2_PLUS_1 1 + + +typedef unsigned int uint; + + +uint log2( uint n ) +{ + uint bit, pow, logn; + + for( bit = 0, pow = 1; bit < 31; bit++, pow <<= 1 ) + { + if( n == pow ) logn = bit; + } + + return( logn ); +} + + +int powerof2( int n ) +{ + return( n == ( n & (-n) ) ); +} + + +void dodiv2m1( uint logd, uint logmsb ) +{ + /* Output instructions to do division by 2^n - 1 */ + printf( "\tMOV a1, a1, lsr #1\n" ); + + while( logd < 32 ) + { + printf( "\tADD a1, a1, a1, lsr #%d\n", logd ); + logd <<= 1; + } + printf( "\tMOV a1, a1, lsr #%d\n", logmsb - 1 ); +} + + +void dodiv2p1( uint logd, uint logmsb ) +{ + /* Output instructions to do division by 2^n + 1 */ + printf( "\tSUB a1, a1, a1, lsr #%d\n", logd ); + + while( logd < 16 ) + { + logd <<= 1; + printf( "\tADD a1, a1, a1, lsr #%d\n", logd ); + } + + printf( "\tMOV a1, a1, lsr #%d\n", logmsb ); +} + + +void loada4( uint type, uint lsb, uint msb ) +{ + /* Constant is too big to be used as an immediate constant, */ + /* so load it into register a4. */ + printf( "\tMOV a4, #0x%x\n", msb ); + + switch( type ) + { + case DIVIDE_BY_2_MINUS_1: + printf( "\tSUB a4, a4, #0x%x\n", lsb ); + break; + + case DIVIDE_BY_2_PLUS_1: + printf( "\tADD a4, a4, #0x%x\n", lsb ); + break; + + default: + fputs( "Internal error", stderr ); + } +} + + +void divideby2( uint type, uint n, uint lsb, uint msb ) +{ + uint loglsb; + uint logmsb; + uint usinga4; + + loglsb = log2( lsb ); + logmsb = log2( msb ); + + printf( "; %s [%s]\n\n", BANNER, DATE ); + printf( "\tAREA |div%d$code|, CODE, READONLY\n\n", n ); + printf( "\tEXPORT udiv%d\n\n", n ); + printf( "udiv%d\n", n ); + printf( "; takes argument in a1\n" ); + printf( "; returns quotient in a1, remainder in a2\n" ); + printf( "; cycles could be saved if only divide or remainder is required\n" ); + + usinga4 = ( n >> loglsb ) > 255; + if( usinga4 ) + { + loada4( type, lsb, msb ); + printf( "\tSUB a2, a1, a4\n" ); + } + else + { + printf( "\tSUB a2, a1, #%d\n", n ); + } + + /* 1/n as a binary number consists of a simple repeating pattern */ + /* The multiply by 1/n is expanded as a sequence of ARM instructions */ + /* (there is a rounding error which must be corrected later) */ + switch( type ) + { + case DIVIDE_BY_2_MINUS_1: + dodiv2m1( logmsb - loglsb, logmsb ); + /* Now do multiply-by-n */ + printf( "\tRSB a3, a1, a1, asl #%d\n", logmsb - loglsb ); + break; + + case DIVIDE_BY_2_PLUS_1: + dodiv2p1( logmsb - loglsb, logmsb ); + /* Now do multiply-by-n */ + printf( "\tADD a3, a1, a1, asl #%d\n", logmsb - loglsb ); + break; + + default: + fputs( "Internal error", stderr ); + } + + /* Subtract from adjusted original to obtain remainder */ + printf( "\tSUBS a2, a2, a3, asl #%d\n", loglsb ); + + /* Apply corrections */ + printf( "\tADDPL a1, a1, #1\n" ); + if( usinga4 ) + { + printf( "\tADDMI a2, a2, a4\n" ); + } + else + { + printf( "\tADDMI a2, a2, #%d\n", n ); + } + + /* Additional test required for divide-by-3, as result could be */ + /* off by 2 lsb due to accumulated rounding errors. */ + if( n == 3 ) + { + printf( "\tCMP a2, #3\n" ); + printf( "\tADDGE a1, a1, #1\n" ); + printf( "\tSUBGE a2, a2, #3\n" ); + } + + printf( "\tMOV pc, lr\n\n" ); + printf( "\tEND\n" ); +} + + +int main( int argc, char *argv[] ) +{ + if( argc != 2 ) + { + printf( "Usage: divc \n" ); + printf( "Generates optimal ARM code for divide-by-constant\n" ); + printf( "where is one of (2^n-2^m) or (2^n+2^m) eg. 10\n" ); + printf( "Advanced RISC Machines [%s]\n", DATE ); + } + else + { + int num; + + num = atoi( argv[ 1 ] ); + if( num <= 1 ) + { + fprintf( stderr, "%d is not sensible\n", num ); + } + else + { + uint lsb = 1; + + /* find least-significant bit */ + while( ( num & lsb ) == 0 ) + { + lsb <<= 1; + } + + if( powerof2( num ) ) + { + fprintf( stderr, "%d is an easy case\n", num ); + } + else if( powerof2( num + lsb ) ) + { + divideby2( DIVIDE_BY_2_MINUS_1, num, lsb, num + lsb ); + } + else if( powerof2( num - lsb ) ) + { + divideby2( DIVIDE_BY_2_PLUS_1, num, lsb, num - lsb ); + } + else + { + fprintf( stderr, "%d is not one of (2^n-2^m) or (2^n+2^m)\n", num ); + } + } + } + return( 0 ); +} diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANDOM.S b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANDOM.S new file mode 100644 index 0000000..67aacdf --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANDOM.S @@ -0,0 +1,42 @@ +; Random number generator +; +; This uses a 33-bit feedback shift register to generate a pseudo-randomly +; ordered sequence of numbers which repeats in a cycle of length 2^33 - 1 +; NOTE: randomseed should not be set to 0, otherwise a zero will be generated +; continuously (not particularly random!). +; +; This is a good application of direct ARM assembler, because the 33-bit +; shift register can be implemented using RRX (which uses reg + carry). +; An ANSI C version would be less efficient as the compiler would not use RRX. + + AREA |Random$$code|, CODE, READONLY + + EXPORT randomnumber + +randomnumber +; on exit: +; a1 = low 32-bits of pseudo-random number +; a2 = high bit (if you want to know it) + LDR ip, |seedpointer| + LDMIA ip, {a1, a2} + TST a2, a2, LSR#1 ; to bit into carry + MOVS a3, a1, RRX ; 33-bit rotate right + ADC a2, a2, a2 ; carry into LSB of a2 + EOR a3, a3, a1, LSL#12 ; (involved!) + EOR a1, a3, a3, LSR#20 ; (similarly involved!) + STMIA ip, {a1, a2} + + MOV pc, lr + +|seedpointer| + DCD seed + + + AREA |Random$$data|, DATA + + EXPORT seed +seed + DCD &55555555 + DCD &55555555 + + END diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANDTEST.C b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANDTEST.C new file mode 100644 index 0000000..092ffb4 --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANDTEST.C @@ -0,0 +1,20 @@ +/* Random number generator demo program + + Calls assembler function 'randomnumber' defined in random.s +*/ + +#include + +/* this function prototype is needed because 'randomnumber' is external */ +extern unsigned int randomnumber( void ); + +int main() +{ + int loop; + + for( loop = 0; loop < 10; loop++ ) + { printf( "randomnumber() returned %08x\n", randomnumber() ); + } + + return( 0 ); +} diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANTEST.APJ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANTEST.APJ new file mode 100644 index 0000000..e8bde34 Binary files /dev/null and b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANTEST.APJ differ diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UDIV10.S b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UDIV10.S new file mode 100644 index 0000000..787bb0b --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UDIV10.S @@ -0,0 +1,23 @@ +; generated by divc 1.01 (Advanced RISC Machines) [01 Jul 92] + + AREA |div10$code|, CODE, READONLY + + EXPORT udiv10 + +udiv10 +; takes argument in a1 +; returns quotient in a1, remainder in a2 +; cycles could be saved if only divide or remainder is required + SUB a2, a1, #10 + SUB a1, a1, a1, lsr #2 + ADD a1, a1, a1, lsr #4 + ADD a1, a1, a1, lsr #8 + ADD a1, a1, a1, lsr #16 + MOV a1, a1, lsr #3 + ADD a3, a1, a1, asl #2 + SUBS a2, a2, a3, asl #1 + ADDPL a1, a1, #1 + ADDMI a2, a2, #10 + MOV pc, lr + + END diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA.APJ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA.APJ new file mode 100644 index 0000000..b4ea8b8 Binary files /dev/null and b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA.APJ differ diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA1.S b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA1.S new file mode 100644 index 0000000..369773a --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA1.S @@ -0,0 +1,60 @@ +; This demonstrates recursion in ARM assembler. +; this version does not perform stack checking. +; +; Converting a number to a string can be expressed using a divide-and- +; conquer algorithm: +; = "" + + AREA |utoa$$code|, CODE, READONLY + + EXPORT dtoa + EXPORT utoa + + IMPORT udiv10 + +dtoa +; converts signed word to string +; a1 = char *buffer +; a2 = signed int number +; on exit: +; a1 = char *end_of_string + + CMP a2, #0 + RSBMI a2, a2, #0; make a2 positive + MOVMI ip, #'-' + STRMIB ip, [ a1 ], #1 ; add minus sign to buffer + +; *** intentional drop-through to utoa *** + +utoa +; recursive routine to convert unsigned word to string +; on entry: +; a1 = char *buffer +; a2 = unsigned int number +; on exit: +; a1 = char *end_of_string ; character after last digit +; all other registers preserved + + STMFD sp!, {v1, v2, lr} ; save 2 variable registers and + ; the return address + + MOV v1, a1 ; keep char *buffer for later + MOV v2, a2 ; and keep the number for later + MOV a1, a2 + BL udiv10 ; on return, the quotient is in a1 + + SUB v2, v2, a1, LSL #3 ; number - 8*quoitient + SUB v2, v2, a1, LSL #1 ; - 2*quotient = remainder + + CMP a1, #0 ; quotient non-zero? + MOVNE a2, a1 ; quotient to a2... + MOV a1, v1 ; buffer pointer unconditionally to a1 + BLNE utoa ; conditional recursive call to utoa + + ADD v2, v2, #'0' ; final digit + STRB v2, [a1], #1 ; store digit at end of buffer + + LDMFD sp!, {v1, v2, pc} ; restore and return + + END + diff --git a/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOATEST.C b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOATEST.C new file mode 100644 index 0000000..5e411b5 --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOATEST.C @@ -0,0 +1,22 @@ +/* test utoa or utoa */ + +#include + +extern char *utoa( char *string, signed int num ); + +int main() +{ + signed int num; + char buffer[ 12 ]; + + puts( "Enter number:" ); + + if( scanf( "%d", &num ) == 1 ) + { + *utoa( buffer, num ) = 0; /* add string terminator */ + puts( "utoa yields:" ); + puts( buffer ); + } + + return( 0 ); +} -- cgit v1.2.3