author: kx <kx@radix-linux.su> 2024-12-29 12:21:01 +0300
committer: kx <kx@radix-linux.su> 2024-12-29 12:21:01 +0300
commit: 3c780c88a0a0e98f7bb1ceaf7843c4560d2e0ce4
parent: 31f615c1e5a07398bdd68c74b81fbe64c45f169a
Commit Summary:
Diffstat:
1 file changed, 151 insertions, 0 deletions
diff --git a/man/shifts.3mpu b/man/shifts.3mpu
new file mode 100644
index 0000000..00743c9
--- /dev/null
+++ b/man/shifts.3mpu
@@ -0,0 +1,163 @@
+.\" Copyright 2024 Andrew V.Kosteltsev (kx@radix-linux.su)
+.\"
+.\"
+.TH shifts 3 "December 27, 2024" "libmpu" "LibMPU Programmer's Manual"
+.SH NAME
+\fBishl\fP, \fBishr\fP, \fBisal\fP, \fBisar\fP \- one\-bit shifts
+.SH SYNOPSIS
+.nf
+.B #include <libmpu.h>
+.PP
+.BI "void ishl( mpu_int *" c ", mpu_int *" a ", int " nb " );
+.BI "void ishr( mpu_int *" c ", mpu_int *" a ", int " nb " );
+.BI "void isal( mpu_int *" c ", mpu_int *" a ", int " nb " );
+.BI "void isar( mpu_int *" c ", mpu_int *" a ", int " nb " );
+.fi
+.SH DESCRIPTION
+For one\-bit shift operations, the input operand is a variable of size \fBnb\fP bytes located
+at address \fBa\fP, the result is placed in a variable of the same size located at address \fBc\fP.
+The spaces occupied by the input and output variable in memory may overlap, either partially or
+completely, which does not affect the correctness of the result obtained. The content of the
+variable located at address \fBa\fP will remain unchanged after the operation if the space
+occupied by it does not overlap with the space occupied by variable \fBc\fP.
+.PP
+When performing shift operations, the carry flag \fBC\fP always contains the value of the last
+putted forward bit. There are the following types of shift operations:
+.PP
+
+.RS 3
+ SHL \- logical unsigned shift to the left by one bit.
+.RE
+.RS 3
+ SHR \- logical unsigned shift to the right by one bit.
+.RE
+.RS 3
+ SAL \- arithmetic shift to the left by one bit.
+.RE
+.RS 3
+ SAR \- arithmetic shift to the right by one bit.
+.RE
+
+.PP
+The following tables illustrate the execution of the operations \fBishl\fP, \fBishr\fP.
+.nf
+.sp
+ ┌────────────────┬───┬───────────────────┬────────────┐
+ │ SHL(<<): │ C │ operand value │ filling │
+ ├────────────────┼───┼───────────────────┼────────────┤
+ │ before │ │ 10110111 │ 0 │
+ ├────────────────┼───┼───────────────────┼────────────┤
+ │ after │ 1 │ 01101110 │ │
+ └────────────────┴───┴───────────────────┴────────────┘
+
+ ┌────────────────┬────────────┬───────────────────┬───┐
+ │ SHR(>>): │ filling │ operand value │ C │
+ ├────────────────┼────────────┼───────────────────┼───┤
+ │ before │ 0 │ 10110111 │ │
+ ├────────────────┼────────────┼───────────────────┼───┤
+ │ after │ │ 01011011 │ 1 │
+ └────────────────┴────────────┴───────────────────┴───┘
+.fi
+.sp
+The tables show that any logical shift always results in a 0 being pushed into the vacated space.
+The overflow flag \fBO\fP is set if the operand has changed sign as a result of the operation.
+.PP
+The left arithmetic shift operation \fBisal\fP operates in the same way as \fBishl\fP (0 is
+also moved to the empty space on the right). The right arithmetic shift operation works
+differently: the sign bit of the original operand is copied to the empty position on the left.
+The action of the \fBisal\fP and \fBisar\fP operations is shown in the following tables.
+.nf
+.sp
+ ┌────────────────┬───┬───────────────────┬────────────┐
+ │ SAL(<<): │ C │ operand value │ filling │
+ ├────────────────┼───┼───────────────────┼────────────┤
+ │ before │ │ 10110111 │ 0 │
+ ├────────────────┼───┼───────────────────┼────────────┤
+ │ after │ 1 │ 01101110 │ │
+ └────────────────┴───┴───────────────────┴────────────┘
+
+ ┌────────────────┬────────────┬───────────────────┬───┐
+ │ SAR(>>): │ filling │ operand value │ C │
+ ├────────────────┼────────────┼───────────────────┼───┤
+ │ before │ sign(1) │ 10110111 │ │
+ ├────────────────┼────────────┼───────────────────┼───┤
+ │ after │ │ 11011011 │ 1 │
+ └────────────────┴────────────┴───────────────────┴───┘
+.fi
+.sp
+The overflow flag for the \fBisal\fP operation is set in the same way as for the \fBishl\fP
+operation. When performing an \fBisar\fP operation, the operand cannot change its sign. Repeated
+shifting of \fBisar\fP may eventually cause a loss of value, and a positive number will be shifted
+to 0 and a negative number to -1. Therefore, the overflow flag \fBO\fP for the \fBisar\fP operation
+is reset to 0.
+.PP
+When performing \fBisal\fP, \fBisar\fP, \fBishl\fP, \fBishr\fP operations, the parity \fBP\fP,
+sign \fBS\fP and zero \fBZ\fP flags are also set. The carry flag from the lowest tetrad \fBA\fP
+is not defined and is simply reset to 0.
+.PP
+Left shift can be used to double numbers, and right shift can be used to divide by 2. These operations
+are much faster than multiplication and division operations. Dividing odd numbers (such as 5 or 7) in
+half forms smaller values (2 or 3, respectively) and sets the carry flag \fBC\fP to 1. In doing so,
+\fBC\fP actually contains the remainder of the division. This use of shift operations requires control
+of the overflow flag \fBO\fP. For simplicity, consider flag control on 4\-bit signed variables:
+.SS Examples with 4\-bit operands:
+\fBMultiplying by 2\fP:
+.nf
+SAL(0111) = 7; result = 1110 = -2, mistake, there must be 14, CF = 0, OF = 1
+.fi
+.sp
+\fBDividing by 2\fP:
+.nf
+SHR(1000) = -8; result = 0100 = 4, mistake, there must be -4, CF = 0, OF = 1
+.fi
+.sp
+\fBDividing by 2\fP:
+.nf
+SAR(1000) = -8; result = 1100 = -4, exactly, CF = 0, OF = 0
+.fi
+.sp
+\fBDividing by 2\fP:
+.nf
+SAR(0111) = 7; result = 0011 = 3, remainder 1 (see carry flag C), exactly, CF = 1, OF = 0
+.fi
+.sp
+.SH EXAMPLES
+.nf
+.sp
+#include <libmpu.h>
+#include <stdio.h>
+
+int main( void )
+{
+ int rc = 0;
+
+ __mpu_init();
+ __mpu_extra_warnings = 1;
+
+ {
+ mpu_int128_t c, a;
+ int nb = NB_I8;
+ __mpu_char8_t sc[32], sa[32];
+
+ iatoi( a, "0b10110111", nb ); /* evaluate the A variable */
+
+ ishl( c, a, nb );
+ iitoa( sa, a, RADIX_BIN, LOWERCASE, nb ); /* convert A value to ASCII string SA */
+ iitoa( sc, c, RADIX_BIN, LOWERCASE, nb ); /* convert C value to ASCII string SC */
+ printf( "a = %s;\n", sa ); /* c = 0b10110111; */
+ printf( "c = %s;\n", sc ); /* c = 0b01101110; */
+ printf( "carry = %d;\n", __mpu_gtc() ); /* Carry Flag */
+ printf( "overflow = %d;\n", __mpu_gto() ); /* Overflow Flag */
+ }
+
+ __mpu_free_context();
+
+ return( rc );
+}
+.fi
+.SH SEE ALSO
+.BR iadd(3),
+.BR iadc(3),
+.BR isub(3),
+.BR isbb(3).
+