1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
|
.\" 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
pushed outward 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_int8_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 isub(3),
.BR iadc(3),
.BR isbb(3),
.BR irol(3),
.BR iror(3),
.BR ircl(3),
.BR ircr(3),
.BR ishln(3),
.BR ishrn(3),
.BR isaln(3),
.BR isarn(3),
.BR iroln(3),
.BR irorn(3),
.BR ircln(3),
.BR ircrn(3),
.BR ineg(3),
.BR inot(3),
.BR iand(3),
.BR itest(3),
.BR icmp(3),
.BR ior(3),
.BR ixor(3),
.BR iinc(3),
.BR idec(3),
.BR ixchg(3),
.BR icpy(3),
.BR icvt(3),
.BR imul(3),
.BR ismul(3),
.BR idiv(3),
.BR isdiv(3),
.BR iatoi(3),
.BR iatoui(3),
.BR iitoa(3),
.BR iuitoa(3).
|