diff --git a/README.md b/README.md index 7ea85c3..e04e95b 100644 --- a/README.md +++ b/README.md @@ -324,6 +324,7 @@ contained therein are applicable to all languages. | 6 | [Calling Assembly Language From Python](./python/) | [Link](./python/README.pdf) | | 7 | [Atomic Operations](./more/atomics/README.md) | [Link](./more/atomics/README.pdf) | | 8 | [Jump Tables](./more/jump_tables/README.md) | [Link](./more/jump_tables/README.pdf) | +| 9 | [argv](./more/argv_example/jess1.S) | ASM CODE | | - | [Debugging Lecture](./debugging/Discourses%20and%20Dialogs%20on%20Debugging.pptx) | PPTX | ## Macro Suite diff --git a/README.pdf b/README.pdf index f93c2b1..6bf96b2 100644 Binary files a/README.pdf and b/README.pdf differ diff --git a/more/argv_example/apple-linux-convergence.S b/more/argv_example/apple-linux-convergence.S new file mode 100644 index 0000000..8827423 --- /dev/null +++ b/more/argv_example/apple-linux-convergence.S @@ -0,0 +1,156 @@ +/* Macros to permit the "same" assembly language to build on ARM64 + Linux systems as well as Apple Silicon systems. + + See the fuller documentation at: + https://github.com/pkivolowitz/asm_book/blob/main/macros/README.md + + Perry Kivolowitz + A Gentle Introduction to Assembly Language +*/ + +.macro GLD_PTR xreg, label +#if defined(__APPLE__) + adrp \xreg, _\label@GOTPAGE + ldr \xreg, [\xreg, _\label@GOTPAGEOFF] +#else + ldr \xreg, =\label + ldr \xreg, [\xreg] +#endif +.endm + +.macro GLD_ADDR xreg, label // Get a global address +#if defined(__APPLE__) + adrp \xreg, _\label@GOTPAGE + add \xreg, \xreg, _\label@GOTPAGEOFF +#else + ldr \xreg, =\label +#endif +.endm + +.macro LLD_ADDR xreg, label +#if defined(__APPLE__) + adrp \xreg, \label@PAGE + add \xreg, \xreg, \label@PAGEOFF +#else + ldr \xreg, =\label +#endif +.endm + +.macro LLD_DBL xreg, dreg, label +#if defined(__APPLE__) + adrp \xreg, \label@PAGE + add \xreg, \xreg, \label@PAGEOFF + ldur \dreg, [\xreg] +// fmov \dreg, \xreg +#else + ldr \xreg, =\label + ldur \dreg, [\xreg] +#endif +.endm + +.macro LLD_FLT xreg, sreg, label +#if defined(__APPLE__) + adrp \xreg, \label@PAGE + add \xreg, \xreg, \label@PAGEOFF + ldur \sreg, [\xreg] +#else + ldr \xreg, =\label + ldur \sreg, [\xreg] +#endif +.endm + +.macro GLABEL label +#if defined(__APPLE__) + .global _\label +#else + .global \label +#endif +.endm + +.macro MAIN +#if defined(__APPLE__) +_main: +#else +main: +#endif +.endm + +/* Fetching the address of the externally defined errno is quite + different on Apple and Linux. This macro leaves the address of + errno in x0. +*/ +.macro ERRNO_ADDR +#if defined(__APPLE__) + bl ___error +#else + bl __errno_location +#endif +.endm + +.macro CRT label +#if defined(__APPLE__) + bl _\label +#else + bl \label +#endif +.endm + +.macro START_PROC // after starting label + .cfi_startproc +.endm + +.macro END_PROC // after the return + .cfi_endproc +.endm + +.macro PUSH_P a, b + stp \a, \b, [sp, -16]! +.endm + +.macro PUSH_R a + str \a, [sp, -16]! +.endm + +.macro POP_P a, b + ldp \a, \b, [sp], 16 +.endm + +.macro POP_R a + ldr \a, [sp], 16 +.endm + +/* The smaller of src_a and src_b is put into dest. A cmp instruction + or other instruction that sets the flags must be performed first. + This macro makes it easy to remember which register does what in the + csel. + + Thank you to u/TNorthover for nudge to add the cmp. +*/ + +.macro MIN src_a, src_b, dest + cmp \src_a, \src_b + csel \dest, \src_a, \src_b, LT +.endm + +/* The larger of src_a and src_b is put into dest. A cmp instruction + or other instruction that sets the flags must be performed first. + This macro makes it easy to remember which register does what in the + csel. + + Thank you to u/TNorthover for nudge to add the cmp. +*/ + +.macro MAX src_a, src_b, dest + cmp \src_a, \src_b + csel \dest, \src_a, \src_b, GT +.endm + +.macro AASCIZ label, string + .p2align 2 +\label: .asciz "\string" +.endm + +.macro MOD src_a, src_b, dest, scratch + sdiv \scratch, \src_a, \src_b + msub \dest, \scratch, \src_b, \src_a +.endm diff --git a/more/argv_example/jess1.S b/more/argv_example/jess1.S new file mode 100644 index 0000000..b02d175 --- /dev/null +++ b/more/argv_example/jess1.S @@ -0,0 +1,111 @@ +#include "apple-linux-convergence.S" + + .p2align 2 + .text + GLABEL main + +/* This program will get a string followed by a double followed by an + integer from the command line demonstrating how each of these types + can be retrieved. + + Example: + ./a.out test 29.3 29 +*/ + +MAIN + PUSH_P x29, x30 + mov x29, sp + + // Check argc to see if it is 4. This is not the only way to + // validate command line arguments but it is an easy way. + cmp w0, 4 + bne 99f // take branch if argc isn't "right". + + // Skip past argv[0] + add x1, x1, 8 + + // Fetch argv[1] as a string. + // x1 is a pointer to a pointer to chars (i.e. the string). + // Being a pointer to a pointer, it must be dereferenced to + // make a pointer. + ldr x0, [x1] // dereference + // Now x0 contains a pointer to the command line argument. + // Print the string (as a string). But doing this causes a + // function call which will destroy x1. So, save x1 temporarily. + // This could be avoided if x1 were moved to a backed up x + // register (e.g. x20). + PUSH_R x1 + CRT puts // ptr is in x0 where puts() needs it. + POP_R x1 + + // Advance x1 once again to get to argv[2] which can be done + // in the same instruction as dereferencing it use a + // preincrement. + ldr x0, [x1, 8]! // dereference + + // Now the string version of argv[2] is now pointed to by x0. + // This is exactly where atof would want it. We need atof + // because it turns strings into numbers. BUT, same as before, + // calling a function would destroy x1 so let's do the same + // trick of backing up x1 on the stack and then restoring after + // the function call. + PUSH_R x1 + CRT atof // ptr is in x0 where atof() needs it. + POP_R x1 + // The string value will be converted to a double left in d0. + // d0 is also a scratch register so for our next call to atoi, + // d0 will have to be preserved on the stack - alternatively, + // we could have used a high d register backed up and restored + // at the start and ending of main(). + + // Advance x1 once again to get to argv[3] which can be done + // in the same instruction as dereferencing it use a + // preincrement. + ldr x0, [x1, 8]! // dereference + + // Now the string version of argv[3] is now pointed to by x0. + // This is exactly where atoi would want it. We need atoi + // because it turns strings into numbers. BUT, same as before, + // calling a function would destroy x1 so let's do the same + // trick of backing up x1 on the stack and then restoring after + // the function call. We must also do the same for d0. Actually, + // we won't need argv after this so we will skip backing up x1. + + PUSH_R d0 + CRT atoi // ptr is in x0 where atof() needs it. + POP_R d0 + // d0 now contains the double. + // x0 now contains the integer. + // x0 must be copied to x1 because x0 must be a pointer to fmt + // for printf to work. + mov x1, x0 + LLD_ADDR x0, fmt +#if defined(__APPLE__) + sub sp, sp, 16 + str x1, [sp, 8] + str d0, [sp] + CRT printf + add sp, sp, 16 +#else + bl printf +#endif + +99: POP_P x29, x30 + mov w0, wzr + ret + +/* What did we learn? + * x1 has argv when main begins. + * pointers to the arguments are the contents of argv NOT + the actual values. Therefore, x1, which is a pointer (to a pointer), + must be dereferenced to get to the actual pointer. In the code, + there are three lines with the comment "// dereference". + * all command line arguments are c-strings. If that's not what you + want, they must be converted - see the code for atoi and atof for + examples. +*/ + .data + +fmt: .asciz "double: %f integer: %d\n" + + .end diff --git a/more/jump_tables/README.pdf b/more/jump_tables/README.pdf index 6eb14d7..f7b6974 100644 Binary files a/more/jump_tables/README.pdf and b/more/jump_tables/README.pdf differ diff --git a/projects/SINE/README.md b/projects/SINE/README.md index 887be52..96ef142 100644 --- a/projects/SINE/README.md +++ b/projects/SINE/README.md @@ -17,7 +17,9 @@ sin x = x - x^3/3! + x^5/5! - x^7/7! ... Notice each term flips from addition to subtraction. -Notice each term is based on the odd integers starting at 1. +Notice each term is based on the odd integers starting at 1. While the +"1" case might look different, it is the same as all the others since +1 is just 1 to the first power divided by 1 factorial. ## Command line @@ -29,40 +31,76 @@ arguments are therefore required. be a double. * The number of terms to evaluate. The number of terms must lie between - 1 and 10 inclusive. + 1 and 10 inclusive. Note the value of 10 as an upper bound in new. It + was 8. ## C version To assist your efforts, [here](./c_version.c) is a version of this -project written in C. +project written in C. This has been updated to print nice debugging +output which is not part of the project. -## Errors to stderr - -Error messages must be sent to `stderr`. - -If you are using the convergence macros to allow your program to build -on both Apple Silicon Mac OS and Linux, note the special casing needed -to deal with `stderr`. If this is you, compile the C version on Mac OS -with the `-S` compiler option to see the generated assembly language and -search for `stderr`. +This C version also demonstrates a different way of calculating the +toggle. This version flips the sign of the toggle by multiplying by -1. +The previous version used odd and even values of the term. ## Sample executions ```text -SINE % ./a.out 0 8 -The sine of 0.00 degrees is 0.000000 in radians. -SINE % ./a.out 90 8 -The sine of 90.00 degrees is 1.000000 in radians. -SINE % ./a.out 180 8 -The sine of 180.00 degrees is -0.000001 in radians. -SINE % ./a.out 180 82 +pk_taylor_series > gcc main.S -o a +pk_taylor_series > ./a 0 10 +The sine of 0.00 degrees is 0.00000000. +pk_taylor_series > ./a 30 10 +The sine of 30.00 degrees is 0.50000000. +pk_taylor_series > ./a 45 10 +The sine of 45.00 degrees is 0.70710678. +pk_taylor_series > ./a 90 10 +The sine of 90.00 degrees is 1.00000000. +pk_taylor_series > ./a 180 10 +The sine of 180.00 degrees is -0.00000000. +pk_taylor_series > ./a 360 10 +The sine of 360.00 degrees is -0.00104818. +pk_taylor_series > ./a 360 100 Number of terms is out of range. -SINE % ./a.out 180 -10 +pk_taylor_series > ./a 360 -1 Number of terms is out of range. -SINE % echo $? -1 +pk_taylor_series > ``` +## Floating point instructions I used + +These are the floating point instructions I used in my implementation. + +* fmov + +* scvtf + +* fmul + +* fdiv + +* fadd + +## How I broke up the program + +I have functions named: + +* main + +* HandleOptions + +* Factorial + +* IntegerPower - x to the nth power + +* ComputeSine - The main calculation + +* PrintAnswer + +* ConvertTheta - Wrap D2R + +* D2R - Degrees to radians + ## CSC3510 The following applies to Carthage College CSC3510 students. @@ -74,4 +112,3 @@ Work is to be done solo. ### What to hand in Just the .S file. **Your name must be at the top of the file.** - diff --git a/projects/SINE/README.pdf b/projects/SINE/README.pdf index eba1271..dd10305 100644 Binary files a/projects/SINE/README.pdf and b/projects/SINE/README.pdf differ diff --git a/projects/SINE/c_version.c b/projects/SINE/c_version.c index 9c47c14..c7937b6 100644 --- a/projects/SINE/c_version.c +++ b/projects/SINE/c_version.c @@ -1,13 +1,14 @@ #include #include +#include -double pi = 3.14159265359; +double pi = 3.14159265358979323846; double D2R(double d) { return d * pi / 180.0; } -long Factorial(int n) { +double Factorial(int n) { long retval = 1; if (n > 0) { @@ -15,7 +16,7 @@ long Factorial(int n) { retval = retval * n--; } } - return retval; + return (double) retval; } double IntegerPower(double b, int e) { @@ -48,20 +49,20 @@ int main(int argc, char ** argv) { double r_angle = D2R(angle); + double toggle = 1.0; for (int term = 0, base = 1; term < terms; term++, base += 2) { - double toggle = (term & 1) ? -1.0 : 1.0; - + if (toggle > 0) { + printf("%+03.8e + %+03.8e / %+03.8e [term %2d is %+03.8e]\n", sin, IntegerPower(r_angle, base), + Factorial(base), term + 1, toggle * IntegerPower(r_angle, base) / Factorial(base)); + } else { + printf("%+03.8e - %+03.8e / %+03.8e [term %2d is %+03.8e]\n", sin, IntegerPower(r_angle, base), + Factorial(base), term + 1, toggle * IntegerPower(r_angle, base) / Factorial(base)); + } sin += toggle * IntegerPower(r_angle, base) / Factorial(base); - /* - if (toggle > 0) { - printf("adding %d p/b intermediate: %f\n", base, sin); - } else { - printf("subtracting %d p/b intermediate: %f\n", base, sin); - } - */ + toggle = toggle * -1; } - printf("The sine of %.2f degrees is %f in radians.\n", angle, sin); + printf("The sine of %0.4f degrees is %0.10f.\n", angle, sin); return 0; } \ No newline at end of file diff --git a/section_2/float/asm_rounding.s b/section_2/float/asm_rounding.S similarity index 100% rename from section_2/float/asm_rounding.s rename to section_2/float/asm_rounding.S diff --git a/section_2/float/literals.s b/section_2/float/literals.S similarity index 100% rename from section_2/float/literals.s rename to section_2/float/literals.S