-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathps1_bit.pro
123 lines (95 loc) · 3.08 KB
/
ps1_bit.pro
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
:- module(ps1_bit, [
split_bits/4
, bytes_le__uint2/2
, bytes_le__uint4/2
, sint_integer/3
, integer_hex/2
, bytesle_uint/2
]).
:- use_module(library(clpfd)).
/** <module> bit manipulation
Predicates:
- Layout
- bytesle_uint/2
- Formatting
- integer_hex/2
Deprecated:
- bytes_le__uint2/2
- bytes_le__uint4/2
To-do:
- Rename to bit.pro.
This was originally written for ps1_decompile.pro, but this isn't PS1 specific.
*/
/** split_bits(?Whole, +Index, ?Left, ?Right)
"Splitting Whole at bit Index produces Left and Right, where Right is the Index least significant bits of Whole."
Every argument is an integer.
Bit 0 is the rightmost bit, the least significant bit.
Groundness requirements:
- Index must be ground.
- At least two of [Whole, Left, Right] must be ground.
Another way to understand the predicate:
- Right is the Index least significant bits of Whole.
- Left is whatever remains.
Example:
```
% split_bits(B4 B3 B2 B1 B0, 2, B4 B3 B2, B1 B0).
split_bits(0b101_11, 2, 0b101, 0b11).
```
*/
split_bits(Whole, Index, Left, Right) :-
integer(Whole), !,
Left #= Whole >> Index,
Right #= Whole /\ ((1 << Index) - 1).
split_bits(Whole, Index, Left, Right) :-
\+ ground(Whole), !,
Whole #= (Left << Index) \/ Right.
split_bits(A,B,C,D) :- throw(error(split_bits(A,B,C,D), _)).
bytes_le__uint2([B0, B1], Half) :-
integer(Half), !,
split_bits(Half, 8, B1, B0).
bytes_le__uint2([B0, B1], Half) :-
\+ ground(Half), !,
Half #= (B1 << 8) \/ B0.
bytes_le__uint4([B0, B1, B2, B3], Word) :-
integer(Word), !,
split_bits(Word, 8, B321, B0),
split_bits(B321, 8, B32, B1),
split_bits(B32, 8, B3, B2).
bytes_le__uint4([B0, B1, B2, B3], Word) :-
\+ ground(Word), !,
Word #= (B3 << 24) \/ (B2 << 16) \/ (B1 << 8) \/ B0.
bytes_le__uint4(A,B) :- throw(error(bytes_le__uint4(A,B), _)).
/*
This assumes that the Prolog implementation uses arbitrary-length integers.
*/
sint_integer(Bits, Sint, Integer) :-
Sign_mask #= 1 << (Bits - 1),
(Sint /\ Sign_mask #= 0 ->
Integer = Sint
; Integer #= - ( ((\ Sint) + 1) /\ ((Sign_mask << 1) - 1))
).
/** integer_hex(?Int, ?Hex)
"Word is Hex hexadecimal."
Int is integer.
Hex is string.
At least one parameter must be bound.
Example:
```
integer_hex(16,"0x10").
integer_hex(-16,"-0x10").
```
*/
integer_hex(Word, Hex) :- integer(Word), Word >= 0, !, format(string(Hex), '0x~16r', [Word]).
integer_hex(Word, Hex) :- integer(Word), Word < 0, !, Abs is -Word, format(string(Hex), '-0x~16r', [Abs]).
integer_hex(Word, Hex) :- string(Hex), !, number_string(Word, Hex).
integer_hex(Word, Hex) :- throw(error(invalid_arguments(Word, Hex), _)).
/** bytesle_uint(?Bytes, ?Word).
"Bytes are the bytes of the unsigned integer Word in little-endian byte order."
Example:
```
bytesle_uint([0x78,0x56,0x34,0x12], 0x12345678).
```
*/
bytesle_uint([], 0).
bytesle_uint([Lsb|Bs], W) :- integer(W), !, Lsb is W /\ 0xff, UpperW is W >> 8, bytesle_uint(Bs, UpperW).
bytesle_uint([Lsb|Bs], W) :- var(W), !, bytesle_uint(Bs, UpperW), W is (UpperW << 8) \/ Lsb.