diff options
| author | Sven Eisenhauer <sven@sven-eisenhauer.net> | 2023-11-10 15:11:48 +0100 |
|---|---|---|
| committer | Sven Eisenhauer <sven@sven-eisenhauer.net> | 2023-11-10 15:11:48 +0100 |
| commit | 33613a85afc4b1481367fbe92a17ee59c240250b (patch) | |
| tree | 670b842326116b376b505ec2263878912fca97e2 /Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM | |
| download | Studium-master.tar.gz Studium-master.tar.bz2 | |
Diffstat (limited to 'Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM')
9 files changed, 528 insertions, 0 deletions
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 <stdio.h>
+
+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 <Return> 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 <Return>. Each time you press <Return>\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 <stdio.h>
+#include <stdlib.h>
+
+#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>\n" );
+ printf( "Generates optimal ARM code for divide-by-constant\n" );
+ printf( "where <n> 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 <stdio.h>
+
+/* 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 Binary files differnew file mode 100644 index 0000000..e8bde34 --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/RANTEST.APJ 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 Binary files differnew file mode 100644 index 0000000..b4ea8b8 --- /dev/null +++ b/Bachelor/Mikroprozessorsysteme2/ARM202U/EXAMPLES/EXPLASM/UTOA.APJ 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:
+; <string> = "<number/10><number%10>"
+
+ 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 <stdio.h>
+
+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 );
+}
|
