diff options
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | basics/Makefile | 2 | ||||
| -rw-r--r-- | basics/float.S | 40 | ||||
| -rw-r--r-- | basics/main.c | 31 |
4 files changed, 68 insertions, 7 deletions
@@ -1,2 +1,4 @@ +Basic stuff at `basics`. Using features from the Linux Kernel in `linux`. + Experiments for `kernel`, `bios` and `init` taken from [@popovicu](https://github.com/popovicu) and his blog. diff --git a/basics/Makefile b/basics/Makefile index 90e88ef..6e36dd6 100644 --- a/basics/Makefile +++ b/basics/Makefile @@ -13,7 +13,7 @@ all: clean $(EXE) .PHONY: $(EXE) $(EXE): - gcc $(CCFLAGS) -o $(EXE) main.c factorial.S string.S + gcc $(CCFLAGS) -o $(EXE) main.c factorial.S string.S float.S .PHONY: clean clean: diff --git a/basics/float.S b/basics/float.S new file mode 100644 index 0000000..f481f3e --- /dev/null +++ b/basics/float.S @@ -0,0 +1,40 @@ +.text +.globl greater_than_ten +.type greater_than_ten, @function + +// bool greater_than_ten(double a, uint64_t b); +greater_than_ten: + // Upon entry a -> fa0; and b -> a0. That is, the ABI increments the + //(f)a<n> register per argument type. + + // Change the rounding to "Rounds Towards Zero" (bits: 0b001). + li t0, 0b001 + fsrm t0 + + // Convert the second parameter to double. + fcvt.d.lu ft0, a0 + + // ret = a + b + fadd.d fa0, fa0, ft0 + + // ret = (ret * b) + b + fmv.d ft1, ft0 + fmadd.d fa0, fa0, ft0, ft1 + + // Now we need to compare the number with 10.0. There are multiple ways to + // load a floating point immediate: + // 1. Loading an integer immediate and then convert it into a double. This + // is discouraged on the RISC-V assembly manual. + // 2. Load a double with `fld` from a memory location on the data section. + // 3. Load a floating point immediate with `fli` (requires the `Zfa` + // extension). + // I don't have the `Zfa` extension on my board, so I'm opting for the + // second way. + fld ft1, .TEN, t0 + fle.d a0, ft1, fa0 + + ret + +.data +.TEN: + .double 10.0 diff --git a/basics/main.c b/basics/main.c index 89d4401..4b5f289 100644 --- a/basics/main.c +++ b/basics/main.c @@ -11,7 +11,7 @@ */ int factorial(uint64_t n); -void test_factorial() +void test_factorial(void) { assert(factorial(0) == 0); assert(factorial(1) == 1); @@ -19,7 +19,7 @@ void test_factorial() assert(factorial(3) == 6); assert(factorial(4) == 24); - printf("factorial:\tOK\n"); + printf("factorial:\t\tOK\n"); } /* @@ -30,7 +30,7 @@ void test_factorial() */ char * reverse_string(char *str); -void test_reverse_string() +void test_reverse_string(void) { assert(reverse_string(NULL) == NULL); assert(reverse_string("") == ""); @@ -41,7 +41,7 @@ void test_reverse_string() char s2[] = "."; assert(strcmp(reverse_string(s2), ".") == 0); - printf("reverse_string:\tOK\n"); + printf("reverse_string:\t\tOK\n"); } /* @@ -51,7 +51,7 @@ void test_reverse_string() */ bool is_palindrome(char *str); -void test_is_palindrome() +void test_is_palindrome(void) { assert(is_palindrome(NULL) == 0); assert(is_palindrome("") == 0); @@ -59,7 +59,25 @@ void test_is_palindrome() assert(is_palindrome("aaa") == 1); assert(is_palindrome("This is a a si sihT") == 1); - printf("is_palindrome:\tOK\n"); + printf("is_palindrome:\t\tOK\n"); +} + +/* + * This function computes the following: ((a + b) * b) + b. Don't try to make + * sense of it, that's the computation I ended up while messing with RISC-V + * floating point instructions. Anyways, with this in mind, it will return if + * the computed value is greater than 10. + * + * Implemented in float.S + */ +bool greater_than_ten(double a, uint64_t b); + +void test_greater_than_ten(void) +{ + assert(!greater_than_ten(2.3, 1)); // 4.3 + assert(greater_than_ten(2.3, 2)); // 10.6 + + printf("greater_than_ten:\tOK\n"); } int main() @@ -67,4 +85,5 @@ int main() test_factorial(); test_reverse_string(); test_is_palindrome(); + test_greater_than_ten(); } |
