Tutorial 10 (Nov 28/30): File IO (input/output), floating points, A6 sample output
File I/O: Reading to and writing from files.
Both examples are provided by Prof. Manzara. I recommend understanding readlong.asm first, and starting A6 from there. While we didn't talk about writelong.asm very much in class, you should take a look and make sure you understand how the program works.
Exercise: Prof. Manzara suggested writing a program which copies one file to another. Essentially, you are combining parts of readlong.asm and writelong.asm. If you have time this weekend, I suggest you spend some time trying this, or at least figure out how it could be done. (solution posted in Dec 5 tutorial)
Mon Dec 5: We will go through the above exercise, with the remaining time being a work period.
Wed Dec 7: Work period, last tutorial of the year.
Fri Dec 9: A6 is due.
In the past, you have used %d, %ld, and %s in your format strings. You can use %f for floating point numbers. For example, %13.10f will output the number with a minimum width of 13 characters, with a maximum decimal precision (mantissa) of 10 digits. If the decimal precision (10) plus the whole number is less than 13 characters, the remaining space is padded. To print a floating point number, you need to pass in an argument to printf() using the d registers. NOTE: You have to start with d0 and not d1. While the w/x registers share memory, the floating point registers d/s/h/b share their own set of memory. Previously we always had to reserve x0 for the string format, so our arguments started at w/x1. However, the first unused d register is of course d0, since the format string is still stored in x0.
For most arithmetic instructions like add, sub, mul, div, you can just add an f suffix to get the floating point instructions. For example, you can use fadd, fsub, fmul, fdiv. One major difference is that you cannot use immediates with these floating point instructions. That means you have to move a number into a floating point register using fmov, before performing arithmetic instructions with that register/value. For fmov, there is a limitation to the size of the number you can move into a register. The "small enough" constant in A6 exceeds this limit, meaning you have to define it as an external variable. You do this the same way you defined your top index in A5, except we need to use .double instead of .word. A double is 8 bytes, whereas a word is 4 bytes. To initialize the constant, you can use 0r1.0e-10. The 0r means real numbers.
Besides basic math, you can also do cmp, abs, and neg with floating point numbers. These are fcmp, fabs, and fneg respectively.
If you have a floating point number, it needs to be stored in d/s/h/b registers. If you use one of these floating point registers in at least one operand, you must use a floating point instruction.
Floating point instruction examples
Let's say we modified one of those ridiculous "skill-testing questions" to use floats: 4 x 2.5 - 5 x 2.0 = ???
fmov d0, 4.0
fmov d1, 2.5
fmul d0, d0, d1
fmov d2, 5.0
fmov d3, 2.0
fmul d2, d2, d3
fsub d0, d0, d2
Note: You can only fmov a limited set of immediates into a register. The permitted range is approximately -31.0 to 31.0.
If you need to use an immediate outside this range, declare it as an external variable (.data) or constant (.text).
someFloat: .double 0r1.0e5 // declare the variable/constant --- 0r stands for real numbers
adrp x19, someFloat // first dereference the pointer "someFloat" to obtain the 64-bit address (must be stored in x register)
add x19, x19, :lo12:someFloat
ldr d19, [x19] // next, load from the address to obtain the floating point number
fcmp d0, 0
fcmp d0, d1
Note: You can only compare a floating point register with another floating point register, OR zero. Other than zero, no other immediates are allowed.
You may also find fneg and fabs useful for Assignment 6.
fabs dest, src // stores the absolute value of src in dest
fabs d0, d0
fneg dest, src // negates the src, and stores the result in dest
fneg d0, d0
A few students have asked me to post the first few lines of the output. Since you can easily calculate the output with a calculator anyways, this shouldn't be a problem. Make sure you check at least 5 or 6 digits of precision (but print 10 digits for the mantissa). Each term is very small, and a small mistake in your calculations may still look correct at first glance.
For A6, you can download both input.bin and generate.c from D2L. The generate.c file is for your reference only, and shows you how the input.bin file was generated. You can also change the lower/upper limits and the increment value to generate your own input file. Simply compile generate.c with gcc, and run it to create the new input file.
To complete A6, you do not need to use/submit generate.c. You only need to download input.bin and use it to test your A6 program.