Compare commits
692 Commits
bladerf_v2
...
master
| Author | SHA1 | Date |
|---|---|---|
|
|
849a3b7329 | |
|
|
b842f4a8ed | |
|
|
6fc48a8cef | |
|
|
2e83305229 | |
|
|
d0e87cc219 | |
|
|
ac7b5759f7 | |
|
|
350664a13a | |
|
|
f24c932cf8 | |
|
|
c35135cabf | |
|
|
86885c2480 | |
|
|
3be128877d | |
|
|
a13356d801 | |
|
|
855f71918e | |
|
|
f5185cbebe | |
|
|
765b295479 | |
|
|
778d85e75f | |
|
|
fb959f0fc7 | |
|
|
fec0da4f0b | |
|
|
52cdd32d0f | |
|
|
4601566886 | |
|
|
23f5dfef2c | |
|
|
42a5c2a978 | |
|
|
65cd5fe441 | |
|
|
f932baa5fa | |
|
|
fa8a066b4c | |
|
|
b645f7d4f2 | |
|
|
bc72177c8b | |
|
|
24c0248fc0 | |
|
|
cdbd6c77a9 | |
|
|
9b2cd0a5ba | |
|
|
059e48b82b | |
|
|
5f7e7cf8e0 | |
|
|
752a7aeac0 | |
|
|
08c7ccbc8e | |
|
|
9788588aba | |
|
|
8b9dd42676 | |
|
|
14e6d5c3fa | |
|
|
e8eeac4654 | |
|
|
abf8fa2b00 | |
|
|
06bc3c34cf | |
|
|
88fec00f17 | |
|
|
ae042eeb27 | |
|
|
f45b2c6475 | |
|
|
2ba2f4da71 | |
|
|
29a6ae5102 | |
|
|
0aac23e049 | |
|
|
ef70374126 | |
|
|
7d552a2ede | |
|
|
8b0e8ce6e3 | |
|
|
e02d0d5ffa | |
|
|
871a7e685f | |
|
|
dd53b36bdf | |
|
|
26924e4efe | |
|
|
6785c56348 | |
|
|
21d1fe0f11 | |
|
|
3367cc5a82 | |
|
|
fe36349083 | |
|
|
e0f794b1a5 | |
|
|
95ab1c0faa | |
|
|
fab8081322 | |
|
|
9d4e2230d2 | |
|
|
825f959e4d | |
|
|
c148fdca84 | |
|
|
9f146fcb71 | |
|
|
cdc818a9f3 | |
|
|
e3a8e00412 | |
|
|
6b8cac3922 | |
|
|
899ee2530c | |
|
|
d6405ddefd | |
|
|
e058929977 | |
|
|
7b1771cdad | |
|
|
017e5d391b | |
|
|
5bd1718bb2 | |
|
|
f3e498a62a | |
|
|
d4b3b03fe0 | |
|
|
ec69b94544 | |
|
|
3069f3d99f | |
|
|
4cf8eb254e | |
|
|
be3c9930f1 | |
|
|
e0f7a33df4 | |
|
|
9e671a14e4 | |
|
|
4e21610c50 | |
|
|
603da245bd | |
|
|
6e5f2595e0 | |
|
|
2480e5169c | |
|
|
1cb4284e6c | |
|
|
ac97423249 | |
|
|
fd8f2d77e1 | |
|
|
b3172181d5 | |
|
|
56625449e8 | |
|
|
b775f2b326 | |
|
|
8d877eeed8 | |
|
|
88741d097b | |
|
|
24c425c968 | |
|
|
acde5b4a91 | |
|
|
f7b6f7aefc | |
|
|
a4cd5bb42d | |
|
|
465d436174 | |
|
|
223283863f | |
|
|
b4acf08738 | |
|
|
265055106b | |
|
|
80acb91dbc | |
|
|
3d013c4251 | |
|
|
86bb40a31c | |
|
|
8dd83d2e7e | |
|
|
c433463392 | |
|
|
455896e86d | |
|
|
037fe4f37f | |
|
|
c97b83d3ed | |
|
|
462dee56f3 | |
|
|
d3c692f630 | |
|
|
f862b530c8 | |
|
|
740d73ac71 | |
|
|
2a62c514f1 | |
|
|
fe91fbc3a4 | |
|
|
bd3ec0cbdc | |
|
|
988489fae1 | |
|
|
63df5a262d | |
|
|
e7f9401722 | |
|
|
f9e252c110 | |
|
|
e7d39c9abb | |
|
|
2c47717360 | |
|
|
047c193da6 | |
|
|
bd43fec71e | |
|
|
cb25eb2cb8 | |
|
|
f36a0c6d38 | |
|
|
9c2531a98d | |
|
|
db53a09dbf | |
|
|
9c67290562 | |
|
|
005e3db2ba | |
|
|
1653ce9ca2 | |
|
|
a75296ae72 | |
|
|
1c7db21349 | |
|
|
a135d2b915 | |
|
|
29d6569ee3 | |
|
|
d90426e1ce | |
|
|
408a3e617a | |
|
|
a59af7385c | |
|
|
5db6efd62d | |
|
|
77ab9f04ba | |
|
|
e8fe48485e | |
|
|
e23cd7e73b | |
|
|
74b1a39aa0 | |
|
|
9f07a81dfa | |
|
|
ff7aafe0bb | |
|
|
c23438a5cf | |
|
|
b84f427732 | |
|
|
3773acf4c0 | |
|
|
e111303b1e | |
|
|
45e13b20ba | |
|
|
22d21cd013 | |
|
|
3324f072cd | |
|
|
5a33b4ee8f | |
|
|
d8d5f2a117 | |
|
|
33bb2d929b | |
|
|
d1f6d02e9a | |
|
|
c4e346698e | |
|
|
4eab12497e | |
|
|
b7205e2e64 | |
|
|
c421c31152 | |
|
|
132702cfa7 | |
|
|
40c24b1c55 | |
|
|
5600d3fc71 | |
|
|
fa80e7c917 | |
|
|
270c629515 | |
|
|
8c892973be | |
|
|
d5184efa6e | |
|
|
c2e1c1f6d5 | |
|
|
2308c1d196 | |
|
|
d8cca659e7 | |
|
|
4ad6c7b4d3 | |
|
|
1b0bcefae6 | |
|
|
1b1f9de119 | |
|
|
0aedcffc5b | |
|
|
2e59e8f1d6 | |
|
|
d1fc00a273 | |
|
|
6a11387861 | |
|
|
11fb727325 | |
|
|
5782ad7468 | |
|
|
fdc1ac731d | |
|
|
2c7b331352 | |
|
|
f1c576b657 | |
|
|
490b5ce36f | |
|
|
ab7aa856bc | |
|
|
5e8be14f2e | |
|
|
2ea75a345d | |
|
|
1eab1fc04b | |
|
|
dbdf18dcc0 | |
|
|
3eb2783cdf | |
|
|
c06c697e26 | |
|
|
bff71dc820 | |
|
|
c7675b3cd1 | |
|
|
b3fcf82473 | |
|
|
e8adeb3414 | |
|
|
8c325e04a0 | |
|
|
3577cb4057 | |
|
|
9950e72d1a | |
|
|
8f9abe57be | |
|
|
930d2534a2 | |
|
|
22e02dbc62 | |
|
|
af4951a494 | |
|
|
ea5a2b8740 | |
|
|
a0dc843842 | |
|
|
16b3d12670 | |
|
|
829fe1b5e2 | |
|
|
47e4df2b7b | |
|
|
1916fc6648 | |
|
|
ad56c1363b | |
|
|
9b85a30c91 | |
|
|
cd6d3a373b | |
|
|
c466a4724f | |
|
|
e2b2ce3f63 | |
|
|
d3459b1697 | |
|
|
0fddde5126 | |
|
|
f4f2f3ddad | |
|
|
c1eeda612e | |
|
|
5c043e8496 | |
|
|
e48006311b | |
|
|
f0055c978d | |
|
|
66f26846b8 | |
|
|
9fb1e5b9e8 | |
|
|
4cde98e063 | |
|
|
c3cd1ec0de | |
|
|
016cb8f9d2 | |
|
|
dc2f47796c | |
|
|
e00935c8d2 | |
|
|
68e95c06cc | |
|
|
4f5f637dc1 | |
|
|
863694761a | |
|
|
3167459bfc | |
|
|
398728439b | |
|
|
be9174a352 | |
|
|
ff190286a6 | |
|
|
14ccaa93bd | |
|
|
774c3cdd55 | |
|
|
24e58762b5 | |
|
|
6714148c45 | |
|
|
6a4a239d0f | |
|
|
418e13e6b6 | |
|
|
303dcc9915 | |
|
|
7356676c5b | |
|
|
9b06099971 | |
|
|
da3e9766de | |
|
|
ec90edcd8d | |
|
|
bc9336e0be | |
|
|
917aa6a0e2 | |
|
|
c89930b4b9 | |
|
|
992f036fc2 | |
|
|
d25103361a | |
|
|
ee552eb058 | |
|
|
1dbb8ab234 | |
|
|
fba10d3262 | |
|
|
798c0a3fa5 | |
|
|
1d3e5c03e9 | |
|
|
ddce32849d | |
|
|
1d04174f37 | |
|
|
e00d12f817 | |
|
|
10b9bc6614 | |
|
|
9237086b38 | |
|
|
da3557fcfe | |
|
|
d353568c59 | |
|
|
a0b0038df7 | |
|
|
af1f4f84a9 | |
|
|
286a6301f8 | |
|
|
74e11bd26f | |
|
|
c3017cc0a4 | |
|
|
799b568dfb | |
|
|
1174841f71 | |
|
|
5a30efb137 | |
|
|
c8d96acbdc | |
|
|
48af886e46 | |
|
|
efb4c1f60f | |
|
|
6dc0741481 | |
|
|
84dd2dfe0e | |
|
|
ce521f715a | |
|
|
ce5cf89e60 | |
|
|
2fa793d0d7 | |
|
|
f1bd1a5829 | |
|
|
653ad6127a | |
|
|
d5d04060de | |
|
|
1761b8ddc1 | |
|
|
e857d042aa | |
|
|
c1f526b76d | |
|
|
74607b31ed | |
|
|
aa2929196d | |
|
|
104575c602 | |
|
|
89a83767f3 | |
|
|
8b21104d66 | |
|
|
f82b7b7a8c | |
|
|
01587a114a | |
|
|
e8b5be519c | |
|
|
8734ec9992 | |
|
|
bf8d6db148 | |
|
|
84b1975e76 | |
|
|
d59e3bb136 | |
|
|
5db1f1e9ba | |
|
|
64abbd02db | |
|
|
84c2d67601 | |
|
|
26e3c23e6a | |
|
|
9520740a12 | |
|
|
b70898cd27 | |
|
|
66ba823493 | |
|
|
6a9700a58c | |
|
|
238bb2bb5d | |
|
|
8b6239fab7 | |
|
|
699576f3de | |
|
|
9b79daadaf | |
|
|
5261b98c95 | |
|
|
49d95744f2 | |
|
|
8d56c0af9d | |
|
|
c890bb6125 | |
|
|
5b964f67b8 | |
|
|
92889d3497 | |
|
|
bb158d929c | |
|
|
95ae1a92be | |
|
|
c32ed2866e | |
|
|
da1aeeeea6 | |
|
|
eb476d2e75 | |
|
|
7267d8aff9 | |
|
|
f314e20342 | |
|
|
53183c0b2a | |
|
|
c89e3b9e9e | |
|
|
f2f19d49fb | |
|
|
0dae3e4b4a | |
|
|
74ef2e92bd | |
|
|
bce7e35e0e | |
|
|
0df937e9c6 | |
|
|
ae12414eed | |
|
|
d3658b9fe6 | |
|
|
ba8f3e6af0 | |
|
|
651d6a4e0d | |
|
|
0793c64ee8 | |
|
|
79c9877232 | |
|
|
8879bcac86 | |
|
|
0ff1275bf9 | |
|
|
f1507d8f2e | |
|
|
258e3f9d65 | |
|
|
8ba24e8c3b | |
|
|
eb1d42e47a | |
|
|
2f9c3fe0e1 | |
|
|
52338202d1 | |
|
|
b6f007a104 | |
|
|
d6b8065c3b | |
|
|
4241a9f1a0 | |
|
|
aa8f3b3c27 | |
|
|
2efbf20177 | |
|
|
a273f72246 | |
|
|
bfc45dc81d | |
|
|
888e7de16d | |
|
|
f13b96dc6b | |
|
|
8bb95e9956 | |
|
|
08a326eb7c | |
|
|
c71c39b0d7 | |
|
|
263e03f7c2 | |
|
|
9406fa7a2e | |
|
|
070bc9f23c | |
|
|
e5a87e91b7 | |
|
|
dfbe32559e | |
|
|
439f615552 | |
|
|
c3541bcbea | |
|
|
940c8e47ea | |
|
|
81e6f680ee | |
|
|
1223f7f29a | |
|
|
d471249f17 | |
|
|
886b0d3f81 | |
|
|
404ac5dced | |
|
|
0f0696c97b | |
|
|
4a21198081 | |
|
|
f45e657583 | |
|
|
497776c642 | |
|
|
0878bd2ddc | |
|
|
1a0ba50c4a | |
|
|
201cb2f466 | |
|
|
105ec2098c | |
|
|
aa59af32aa | |
|
|
21743b03b7 | |
|
|
f7123c41e5 | |
|
|
ae29613d85 | |
|
|
a224f6f783 | |
|
|
fb110802d6 | |
|
|
59170cbacb | |
|
|
4ab1938f97 | |
|
|
c853db67d0 | |
|
|
f868e4c010 | |
|
|
ea9f81c605 | |
|
|
19327926f1 | |
|
|
b2e9153653 | |
|
|
a8737f7916 | |
|
|
8ffa43b65c | |
|
|
54409b4836 | |
|
|
dfc588335a | |
|
|
54f2c54d8f | |
|
|
9500a2f2f7 | |
|
|
429e34db21 | |
|
|
ce89cd08d9 | |
|
|
dda442c121 | |
|
|
3c76eeb51c | |
|
|
620cb3a720 | |
|
|
a11576710d | |
|
|
f1fef5b8fc | |
|
|
36ae24838f | |
|
|
f67a31823b | |
|
|
aa2b205481 | |
|
|
af786e6e85 | |
|
|
ffff5d6646 | |
|
|
089684e20f | |
|
|
25b3a34fff | |
|
|
ae4a89b707 | |
|
|
dabb6fc135 | |
|
|
0ba4ba3fd7 | |
|
|
0a0fb46b5d | |
|
|
1d29f5e059 | |
|
|
18d47fd5ff | |
|
|
4edb2e8e35 | |
|
|
a1a7d42e90 | |
|
|
e2761fc21d | |
|
|
6a0df00e2d | |
|
|
d0094d5abd | |
|
|
35299c47ba | |
|
|
0d2bd6ae34 | |
|
|
1ecc925ed5 | |
|
|
d9a78636a6 | |
|
|
9cef820dfc | |
|
|
f1cb09d0e3 | |
|
|
207ca0c401 | |
|
|
76ab0a7ebe | |
|
|
b01f42097d | |
|
|
5cc04d4ca8 | |
|
|
de6d671ba4 | |
|
|
f4537bd49a | |
|
|
ef125bd5f0 | |
|
|
e444d2eb5c | |
|
|
a0bd957274 | |
|
|
fa65517ada | |
|
|
64236c55d8 | |
|
|
40614778bc | |
|
|
17f1054dff | |
|
|
7c57d8095b | |
|
|
e30b3e87f5 | |
|
|
68ca0dc800 | |
|
|
01b07ec50a | |
|
|
16f1d450ae | |
|
|
930e158208 | |
|
|
61f483c3e7 | |
|
|
39aeb7a48c | |
|
|
5eb0bd10ea | |
|
|
f968fea390 | |
|
|
d5741bf8c8 | |
|
|
c9bea6a21c | |
|
|
27f41c178f | |
|
|
b8fb5e5fe5 | |
|
|
0306c7edfd | |
|
|
564f033087 | |
|
|
d33b1160f2 | |
|
|
1b5b0dfa03 | |
|
|
74d7ead41b | |
|
|
d575cc0d00 | |
|
|
b84fffc443 | |
|
|
f573b843c3 | |
|
|
da41d820f6 | |
|
|
e419719731 | |
|
|
19f26968c7 | |
|
|
34bfe10317 | |
|
|
f13f8dfce8 | |
|
|
4d683ac50c | |
|
|
857c56ca7b | |
|
|
0f23e514c6 | |
|
|
a24718feca | |
|
|
37e49906d1 | |
|
|
d54c452683 | |
|
|
82c5ff6724 | |
|
|
b281ceee7b | |
|
|
d6bafd64a2 | |
|
|
f497d7481f | |
|
|
a2480a2769 | |
|
|
8a6261d7c2 | |
|
|
91e9635563 | |
|
|
883399cee3 | |
|
|
0f2215c2ce | |
|
|
91f3c3ce67 | |
|
|
a654c60d65 | |
|
|
18c0758a67 | |
|
|
77c8f9aafa | |
|
|
f46640a5c2 | |
|
|
56aa2f7d1e | |
|
|
45886edc40 | |
|
|
14c458db8c | |
|
|
9136766b9c | |
|
|
719e004c7a | |
|
|
d66a05b019 | |
|
|
0946d5165d | |
|
|
9dfc3e7aa6 | |
|
|
47e43778a6 | |
|
|
28e7ccca8e | |
|
|
10cfc13c3a | |
|
|
bd50f5d689 | |
|
|
324491b0e6 | |
|
|
6abcebd0e4 | |
|
|
f04a71640a | |
|
|
671aac5f50 | |
|
|
c05aea65a4 | |
|
|
9c124b3f2b | |
|
|
983829bff6 | |
|
|
bd14c822e3 | |
|
|
9063761dd1 | |
|
|
c8501cb41c | |
|
|
3c02e8419d | |
|
|
b327848d75 | |
|
|
cdba7566fd | |
|
|
2a7a1e16f6 | |
|
|
d0cfbdf3cf | |
|
|
8829b65ab2 | |
|
|
f4692a3784 | |
|
|
e2c8d361f8 | |
|
|
7d17d8e1ff | |
|
|
ed23dbd6db | |
|
|
e31bee1909 | |
|
|
8eeb29ec32 | |
|
|
8985b5ab86 | |
|
|
bf05a94f3e | |
|
|
4fbb336fa3 | |
|
|
43fedd9c6d | |
|
|
e0bb6e11e7 | |
|
|
7d61b2aaab | |
|
|
7bb2cfe01f | |
|
|
65f44d99bf | |
|
|
963cb1aefb | |
|
|
71f2c99e96 | |
|
|
540e5f8e95 | |
|
|
3ec6ec1a9d | |
|
|
974e962a55 | |
|
|
ea7a2c1c09 | |
|
|
12151ed8f5 | |
|
|
6af6ff7c2b | |
|
|
01a4477c92 | |
|
|
0983766a6c | |
|
|
3298eb77b4 | |
|
|
3e4012e958 | |
|
|
20a16d50bd | |
|
|
41fa394278 | |
|
|
6c055c8c23 | |
|
|
2b00c05465 | |
|
|
1caabc5ad8 | |
|
|
b82922e81c | |
|
|
d3448b0efb | |
|
|
dfdee153ef | |
|
|
655d311a37 | |
|
|
fffd3c9913 | |
|
|
39b008472f | |
|
|
6e7c32bde0 | |
|
|
f81044cc01 | |
|
|
9101d5017d | |
|
|
60c762c843 | |
|
|
3340e6315c | |
|
|
fcbf32dc49 | |
|
|
f4fa94f842 | |
|
|
c9997a783f | |
|
|
c9e729a48a | |
|
|
084acd2951 | |
|
|
9efd6b3470 | |
|
|
7749316540 | |
|
|
d5eccc30a4 | |
|
|
0b9f7e4cef | |
|
|
d267d2257a | |
|
|
213d769bf9 | |
|
|
d8f568e0ce | |
|
|
0608e31965 | |
|
|
a8fe04f856 | |
|
|
5a9350a6a1 | |
|
|
94824fbb98 | |
|
|
04b940d45b | |
|
|
f323745ead | |
|
|
abfb88b124 | |
|
|
5cdf9157db | |
|
|
f1036702ce | |
|
|
a256833e17 | |
|
|
7059c0f64a | |
|
|
aa78020410 | |
|
|
286d8e7a10 | |
|
|
d6c0612767 | |
|
|
1d5db2fd76 | |
|
|
44e8913c2d | |
|
|
daebc372a9 | |
|
|
0c3671429b | |
|
|
2ce2af1685 | |
|
|
571ea7ac41 | |
|
|
63d1b4b553 | |
|
|
a947163dee | |
|
|
ea1e9c336b | |
|
|
079061df3c | |
|
|
161d2d8ded | |
|
|
6986b3847f | |
|
|
232a64e5fd | |
|
|
d62f4c2ff5 | |
|
|
a125155074 | |
|
|
a38acc3dff | |
|
|
ee7d879130 | |
|
|
20c3c4b597 | |
|
|
3e207b5379 | |
|
|
220bbf5057 | |
|
|
51e3e1d677 | |
|
|
14bbf09230 | |
|
|
74c9cb564c | |
|
|
567600889f | |
|
|
43b0f5a75a | |
|
|
18b455fbf0 | |
|
|
196ef89aca | |
|
|
417aee9dc5 | |
|
|
a3cdd47d80 | |
|
|
634d806686 | |
|
|
4baae970ae | |
|
|
c6d7f1ec6f | |
|
|
2f53b57278 | |
|
|
f45a7d61a5 | |
|
|
8a52108d77 | |
|
|
382554a250 | |
|
|
e3c8c91852 | |
|
|
17c8265ce8 | |
|
|
c7855c5ab6 | |
|
|
1ec32903ba | |
|
|
05e9601903 | |
|
|
27b0e9c40f | |
|
|
2142d2edf5 | |
|
|
98d64483d6 | |
|
|
2e0aba4f1f | |
|
|
80eca0ff9a | |
|
|
d225b9bc3f | |
|
|
0d7177fe9a | |
|
|
bd96af9827 | |
|
|
f1192e9414 | |
|
|
fbb87b909f | |
|
|
02b9e635b5 | |
|
|
c404e33198 | |
|
|
5ba613dd44 | |
|
|
06cdc5071b | |
|
|
0aa1822262 | |
|
|
9486c14842 | |
|
|
0c5472043e | |
|
|
d790600a86 | |
|
|
84383e2209 | |
|
|
17c3a3fb6b | |
|
|
f6dfe2616f | |
|
|
87689cf6eb | |
|
|
cfcb329a2f | |
|
|
9621cadbd3 | |
|
|
f23bdb21f6 | |
|
|
3987cd59bc | |
|
|
630136a1eb | |
|
|
effca83150 | |
|
|
3a819a5aeb | |
|
|
e0e09ed3a4 | |
|
|
fddb2298ee | |
|
|
09f6bed7c0 | |
|
|
0722edc2bc | |
|
|
d40e69ee42 | |
|
|
2e6b4eb4b6 | |
|
|
b929821fe8 | |
|
|
484765a119 | |
|
|
5d781785aa | |
|
|
bc2415bc5d | |
|
|
cc92afd4f0 | |
|
|
0511d6fd3a | |
|
|
0e1e5df326 | |
|
|
06ab0502fe | |
|
|
773668f510 | |
|
|
973182c75e | |
|
|
908d794238 | |
|
|
c34b1c38fb | |
|
|
fbf8af2236 | |
|
|
ee23816428 | |
|
|
9d3f3bdf84 | |
|
|
bee850061e | |
|
|
6b699bffc3 | |
|
|
6d4300848f | |
|
|
d332f477b8 | |
|
|
d6898dbc49 | |
|
|
a7be17a5d7 | |
|
|
4cbb1ab437 | |
|
|
e4a94aa574 | |
|
|
bbfdd45cc3 | |
|
|
8b9f984a54 | |
|
|
71b9b659d0 | |
|
|
ac9249b293 | |
|
|
e2fcc58bf2 | |
|
|
8228050ca4 | |
|
|
924bcaa044 | |
|
|
c2c43b9f6b | |
|
|
e5fcd4035f | |
|
|
cf6fcdce6a | |
|
|
cc75121d37 | |
|
|
6c86d4f276 | |
|
|
b0dc4f8a4f |
|
|
@ -1 +1,4 @@
|
||||||
*.xz binary
|
*.xz binary
|
||||||
|
dsp/generated/* merge=binary linguist-generated
|
||||||
|
cpu_features/** linguist-vendored
|
||||||
|
starch/** linguist-vendored
|
||||||
|
|
|
||||||
|
|
@ -11,3 +11,9 @@ untrackedDeveloperSettings.js
|
||||||
view1090
|
view1090
|
||||||
faup1090
|
faup1090
|
||||||
package-wheezy
|
package-wheezy
|
||||||
|
oneoff/convert_benchmark
|
||||||
|
oneoff/uc8_capture_stats
|
||||||
|
oneoff/dsp_error_measurement
|
||||||
|
oneoff/decode_comm_b
|
||||||
|
starch-benchmark
|
||||||
|
wisdom.local
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ matrix:
|
||||||
before_install:
|
before_install:
|
||||||
- if [ `uname` = "Linux" ]; then
|
- if [ `uname` = "Linux" ]; then
|
||||||
sudo apt-get update -qq;
|
sudo apt-get update -qq;
|
||||||
sudo apt-get install -y build-essential debhelper librtlsdr-dev libusb-1.0-0-dev pkg-config;
|
sudo apt-get install -y build-essential debhelper librtlsdr-dev libusb-1.0-0-dev pkg-config fakeroot libbladerf-dev dh-systemd;
|
||||||
elif [ `uname` = "Darwin" ]; then
|
elif [ `uname` = "Darwin" ]; then
|
||||||
brew update;
|
brew update;
|
||||||
brew install -v librtlsdr;
|
brew install -v librtlsdr;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
node(label: 'raspberrypi') {
|
||||||
|
properties([
|
||||||
|
pipelineTriggers([
|
||||||
|
upstream(threshold: 'SUCCESS',
|
||||||
|
upstreamProjects: "bladeRF/${env.BRANCH_NAME}")
|
||||||
|
]),
|
||||||
|
disableConcurrentBuilds(),
|
||||||
|
durabilityHint(hint: 'PERFORMANCE_OPTIMIZED')
|
||||||
|
])
|
||||||
|
|
||||||
|
def dists = ["bullseye", "buster", "stretch"]
|
||||||
|
def srcdir = "${WORKSPACE}/src"
|
||||||
|
|
||||||
|
stage('Checkout') {
|
||||||
|
sh "rm -fr ${srcdir}"
|
||||||
|
sh "mkdir ${srcdir}"
|
||||||
|
dir(srcdir) {
|
||||||
|
checkout scm
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < dists.size(); ++i) {
|
||||||
|
def dist = dists[i]
|
||||||
|
def pkgdir = "package-${dist}"
|
||||||
|
def results = "results-${dist}"
|
||||||
|
|
||||||
|
stage("Prepare source for ${dist}") {
|
||||||
|
sh "rm -fr ${pkgdir}"
|
||||||
|
sh "${srcdir}/prepare-build.sh ${dist} ${pkgdir}"
|
||||||
|
}
|
||||||
|
|
||||||
|
stage("Build for ${dist}") {
|
||||||
|
sh "rm -fr ${results}"
|
||||||
|
sh "mkdir -p ${results}"
|
||||||
|
dir(pkgdir) {
|
||||||
|
sh "DIST=${dist} BRANCH=${env.BRANCH_NAME} pdebuild --use-pdebuild-internal --debbuildopts -b --buildresult ${WORKSPACE}/${results} -- --override-config"
|
||||||
|
}
|
||||||
|
archiveArtifacts artifacts: "${results}/*.deb", fingerprint: true
|
||||||
|
}
|
||||||
|
|
||||||
|
stage("Test install on ${dist}") {
|
||||||
|
sh "BRANCH=${env.BRANCH_NAME} /build/pi-builder/scripts/validate-packages.sh ${dist} ${results}/dump1090-fa_*.deb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
stage('Deploy to internal repository') {
|
||||||
|
for (int i = 0; i < dists.size(); ++i) {
|
||||||
|
def dist = dists[i]
|
||||||
|
def results = "results-${dist}"
|
||||||
|
sh "/build/pi-builder/scripts/deploy.sh -distribution ${dist} -branch ${env.BRANCH_NAME} ${results}/*.deb"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
251
Makefile
251
Makefile
|
|
@ -1,73 +1,250 @@
|
||||||
PROGNAME=dump1090
|
PROGNAME=dump1090
|
||||||
|
|
||||||
|
DUMP1090_VERSION ?= unknown
|
||||||
|
|
||||||
|
CFLAGS ?= -O3 -g
|
||||||
|
DUMP1090_CFLAGS := -std=c11 -fno-common -Wall -Wmissing-declarations -Werror -W
|
||||||
|
DUMP1090_CPPFLAGS := -I. -D_POSIX_C_SOURCE=200112L -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\"
|
||||||
|
|
||||||
|
LIBS = -lpthread -lm
|
||||||
|
SDR_OBJ = cpu.o sdr.o fifo.o sdr_ifile.o dsp/helpers/tables.o
|
||||||
|
|
||||||
|
# Try to autodetect available libraries via pkg-config if no explicit setting was used
|
||||||
|
PKGCONFIG=$(shell pkg-config --version >/dev/null 2>&1 && echo "yes" || echo "no")
|
||||||
|
ifeq ($(PKGCONFIG), yes)
|
||||||
|
ifndef RTLSDR
|
||||||
|
ifdef RTLSDR_PREFIX
|
||||||
|
RTLSDR := yes
|
||||||
|
else
|
||||||
|
RTLSDR := $(shell pkg-config --exists librtlsdr && echo "yes" || echo "no")
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef BLADERF
|
||||||
|
BLADERF := $(shell pkg-config --exists libbladeRF && echo "yes" || echo "no")
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef HACKRF
|
||||||
|
HACKRF := $(shell pkg-config --exists libhackrf && echo "yes" || echo "no")
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifndef LIMESDR
|
||||||
|
LIMESDR := $(shell pkg-config --exists LimeSuite && echo "yes" || echo "no")
|
||||||
|
endif
|
||||||
|
else
|
||||||
|
# pkg-config not available. Only use explicitly enabled libraries.
|
||||||
|
RTLSDR ?= no
|
||||||
|
BLADERF ?= no
|
||||||
|
HACKRF ?= no
|
||||||
|
LIMESDR ?= no
|
||||||
|
endif
|
||||||
|
|
||||||
|
HOST_UNAME := $(shell uname)
|
||||||
|
HOST_ARCH := $(shell uname -m)
|
||||||
|
|
||||||
|
UNAME ?= $(HOST_UNAME)
|
||||||
|
ARCH ?= $(HOST_ARCH)
|
||||||
|
|
||||||
|
ifeq ($(UNAME), Linux)
|
||||||
|
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||||
|
LIBS += -lrt
|
||||||
|
LIBS_USB += -lusb-1.0
|
||||||
|
LIBS_CURSES := -lncurses
|
||||||
|
CPUFEATURES ?= yes
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME), Darwin)
|
||||||
|
ifneq ($(shell sw_vers -productVersion | egrep '^10\.([0-9]|1[01])\.'),) # Mac OS X ver <= 10.11
|
||||||
|
DUMP1090_CPPFLAGS += -DMISSING_GETTIME
|
||||||
|
COMPAT += compat/clock_gettime/clock_gettime.o
|
||||||
|
endif
|
||||||
|
DUMP1090_CPPFLAGS += -DMISSING_NANOSLEEP
|
||||||
|
COMPAT += compat/clock_nanosleep/clock_nanosleep.o
|
||||||
|
LIBS_USB += -lusb-1.0
|
||||||
|
LIBS_CURSES := -lncurses
|
||||||
|
# cpufeatures reportedly does not work (yet) on darwin arm64
|
||||||
|
ifneq ($(ARCH),arm64)
|
||||||
|
CPUFEATURES ?= yes
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME), OpenBSD)
|
||||||
|
DUMP1090_CPPFLAGS += -DMISSING_NANOSLEEP
|
||||||
|
COMPAT += compat/clock_nanosleep/clock_nanosleep.o
|
||||||
|
LIBS_USB += -lusb-1.0
|
||||||
|
LIBS_CURSES := -lncurses
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME), FreeBSD)
|
||||||
|
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||||
|
LIBS += -lrt
|
||||||
|
LIBS_USB += -lusb
|
||||||
|
LIBS_CURSES := -lncurses
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(UNAME), NetBSD)
|
||||||
|
DUMP1090_CPPFLAGS += -D_DEFAULT_SOURCE
|
||||||
|
LIBS += -lrt
|
||||||
|
LIBS_USB += -lusb-1.0
|
||||||
|
LIBS_CURSES := -lcurses
|
||||||
|
endif
|
||||||
|
|
||||||
|
CPUFEATURES ?= no
|
||||||
|
|
||||||
|
ifeq ($(CPUFEATURES),yes)
|
||||||
|
include Makefile.cpufeatures
|
||||||
|
DUMP1090_CPPFLAGS += -DENABLE_CPUFEATURES -Icpu_features/include
|
||||||
|
endif
|
||||||
|
|
||||||
RTLSDR ?= yes
|
RTLSDR ?= yes
|
||||||
BLADERF ?= yes
|
BLADERF ?= yes
|
||||||
|
|
||||||
CC=gcc
|
|
||||||
CPPFLAGS += -DMODES_DUMP1090_VERSION=\"$(DUMP1090_VERSION)\" -DMODES_DUMP1090_VARIANT=\"dump1090-fa\"
|
|
||||||
|
|
||||||
ifneq ($(HTMLPATH),"")
|
|
||||||
CPPFLAGS += -DHTMLPATH=\"$(HTMLPATH)\"
|
|
||||||
endif
|
|
||||||
|
|
||||||
DIALECT = -std=c11
|
|
||||||
CFLAGS += $(DIALECT) -O2 -g -Wall -Werror -W -D_DEFAULT_SOURCE
|
|
||||||
LIBS = -lpthread -lm -lrt
|
|
||||||
|
|
||||||
ifeq ($(RTLSDR), yes)
|
ifeq ($(RTLSDR), yes)
|
||||||
SDR_OBJ += sdr_rtlsdr.o
|
SDR_OBJ += sdr_rtlsdr.o
|
||||||
CPPFLAGS += -DENABLE_RTLSDR
|
DUMP1090_CPPFLAGS += -DENABLE_RTLSDR
|
||||||
|
|
||||||
ifdef RTLSDR_PREFIX
|
ifdef RTLSDR_PREFIX
|
||||||
CPPFLAGS += -I$(RTLSDR_PREFIX)/include
|
DUMP1090_CPPFLAGS += -I$(RTLSDR_PREFIX)/include
|
||||||
LDFLAGS += -L$(RTLSDR_PREFIX)/lib
|
ifeq ($(STATIC), yes)
|
||||||
|
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -Wl,-Bstatic -lrtlsdr -Wl,-Bdynamic $(LIBS_USB)
|
||||||
|
else
|
||||||
|
LIBS_SDR += -L$(RTLSDR_PREFIX)/lib -lrtlsdr $(LIBS_USB)
|
||||||
|
endif
|
||||||
else
|
else
|
||||||
CFLAGS += $(shell pkg-config --cflags librtlsdr)
|
# some packaged .pc files are massively broken, try to handle it
|
||||||
LDFLAGS += $(shell pkg-config --libs-only-L librtlsdr)
|
|
||||||
endif
|
|
||||||
|
|
||||||
ifeq ($(STATIC), yes)
|
# FreeBSD's librtlsdr.pc includes -std=gnu89 in cflags
|
||||||
LIBS_SDR += -Wl,-Bstatic -lrtlsdr -Wl,-Bdynamic -lusb-1.0
|
# some linux librtlsdr packages return a bare -I/ with no path in --cflags
|
||||||
else
|
RTLSDR_CFLAGS := $(shell pkg-config --cflags librtlsdr)
|
||||||
LIBS_SDR += -lrtlsdr -lusb-1.0
|
RTLSDR_CFLAGS := $(filter-out -std=%,$(RTLSDR_CFLAGS))
|
||||||
|
RTLSDR_CFLAGS := $(filter-out -I/,$(RTLSDR_CFLAGS))
|
||||||
|
DUMP1090_CFLAGS += $(RTLSDR_CFLAGS)
|
||||||
|
|
||||||
|
# some linux librtlsdr packages return a bare -L with no path in --libs
|
||||||
|
# which horribly confuses things because it eats the next option on the command line
|
||||||
|
RTLSDR_LFLAGS := $(shell pkg-config --libs-only-L librtlsdr)
|
||||||
|
ifeq ($(RTLSDR_LFLAGS),-L)
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs-only-l --libs-only-other librtlsdr)
|
||||||
|
else
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs librtlsdr)
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(BLADERF), yes)
|
ifeq ($(BLADERF), yes)
|
||||||
SDR_OBJ += sdr_bladerf.o
|
SDR_OBJ += sdr_bladerf.o
|
||||||
CPPFLAGS += -DENABLE_BLADERF
|
DUMP1090_CPPFLAGS += -DENABLE_BLADERF
|
||||||
CFLAGS += $(shell pkg-config --cflags libbladeRF)
|
DUMP1090_CFLAGS += $(shell pkg-config --cflags libbladeRF)
|
||||||
LIBS_SDR += $(shell pkg-config --libs libbladeRF)
|
LIBS_SDR += $(shell pkg-config --libs libbladeRF)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
all: dump1090 view1090
|
ifeq ($(HACKRF), yes)
|
||||||
|
SDR_OBJ += sdr_hackrf.o
|
||||||
|
DUMP1090_CPPFLAGS += -DENABLE_HACKRF
|
||||||
|
DUMP1090_CFLAGS += $(shell pkg-config --cflags libhackrf)
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs libhackrf)
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(LIMESDR), yes)
|
||||||
|
SDR_OBJ += sdr_limesdr.o
|
||||||
|
DUMP1090_CPPFLAGS += -DENABLE_LIMESDR
|
||||||
|
DUMP1090_CFLAGS += $(shell pkg-config --cflags LimeSuite)
|
||||||
|
LIBS_SDR += $(shell pkg-config --libs LimeSuite)
|
||||||
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
##
|
||||||
|
## starch (runtime DSP code selection) mix, architecture-specific
|
||||||
|
##
|
||||||
|
|
||||||
|
ifneq ($(CPUFEATURES),yes)
|
||||||
|
# need to be able to detect CPU features at runtime to enable any non-standard compiler flags
|
||||||
|
STARCH_MIX := generic
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_GENERIC
|
||||||
|
else
|
||||||
|
ifeq ($(ARCH),x86_64)
|
||||||
|
# AVX, AVX2
|
||||||
|
STARCH_MIX := x86
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_X86
|
||||||
|
else ifeq ($(findstring aarch,$(ARCH)),aarch)
|
||||||
|
STARCH_MIX := aarch64
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_AARCH64
|
||||||
|
else ifeq ($(findstring arm64,$(ARCH)),arm64)
|
||||||
|
# Apple calls this arm64, not aarch64
|
||||||
|
STARCH_MIX := aarch64
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_AARCH64
|
||||||
|
else ifeq ($(findstring arm,$(ARCH)),arm)
|
||||||
|
# ARMv7 NEON
|
||||||
|
STARCH_MIX := arm
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_ARM
|
||||||
|
else
|
||||||
|
STARCH_MIX := generic
|
||||||
|
DUMP1090_CPPFLAGS += -DSTARCH_MIX_GENERIC
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
all: showconfig dump1090 view1090 starch-benchmark
|
||||||
|
|
||||||
|
ALL_CCFLAGS := $(CPPFLAGS) $(DUMP1090_CPPFLAGS) $(CFLAGS) $(DUMP1090_CFLAGS)
|
||||||
|
|
||||||
|
STARCH_COMPILE := $(CC) $(ALL_CCFLAGS) -c
|
||||||
|
include dsp/generated/makefile.$(STARCH_MIX)
|
||||||
|
|
||||||
|
showconfig:
|
||||||
|
@echo "Building with:" >&2
|
||||||
|
@echo " Version string: $(DUMP1090_VERSION)" >&2
|
||||||
|
@echo " Architecture: $(ARCH)" >&2
|
||||||
|
@echo " DSP mix: $(STARCH_MIX)" >&2
|
||||||
|
@echo " RTLSDR support: $(RTLSDR)" >&2
|
||||||
|
@echo " BladeRF support: $(BLADERF)" >&2
|
||||||
|
@echo " HackRF support: $(HACKRF)" >&2
|
||||||
|
@echo " LimeSDR support: $(LIMESDR)" >&2
|
||||||
|
|
||||||
%.o: %.c *.h
|
%.o: %.c *.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
|
$(CC) $(ALL_CCFLAGS) -c $< -o $@
|
||||||
|
|
||||||
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o convert.o sdr_ifile.o sdr.o $(SDR_OBJ) $(COMPAT)
|
dump1090: dump1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o demod_2400.o stats.o cpr.o icao_filter.o track.o util.o convert.o ais_charset.o adaptive.o $(SDR_OBJ) $(COMPAT) $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||||
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_SDR) -lncurses
|
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_SDR) $(LIBS_CURSES)
|
||||||
|
|
||||||
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o $(COMPAT)
|
view1090: view1090.o anet.o interactive.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o sdr_stub.o $(COMPAT)
|
||||||
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) -lncurses
|
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS) $(LIBS_CURSES)
|
||||||
|
|
||||||
faup1090: faup1090.o anet.o mode_ac.o mode_s.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o $(COMPAT)
|
faup1090: faup1090.o anet.o mode_ac.o mode_s.o comm_b.o net_io.o crc.o stats.o cpr.o icao_filter.o track.o util.o ais_charset.o sdr_stub.o $(COMPAT)
|
||||||
|
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
|
starch-benchmark: cpu.o dsp/helpers/tables.o $(CPUFEATURES_OBJS) $(STARCH_OBJS) $(STARCH_BENCHMARK_OBJ)
|
||||||
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
|
$(CC) -g -o $@ $^ $(LDFLAGS) $(LIBS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.o compat/clock_gettime/*.o compat/clock_nanosleep/*.o dump1090 view1090 faup1090 cprtests crctests convert_benchmark
|
rm -f *.o oneoff/*.o compat/clock_gettime/*.o compat/clock_nanosleep/*.o cpu_features/src/*.o dsp/generated/*.o dsp/helpers/*.o $(CPUFEATURES_OBJS) dump1090 view1090 faup1090 cprtests crctests oneoff/convert_benchmark oneoff/decode_comm_b oneoff/dsp_error_measurement oneoff/uc8_capture_stats starch-benchmark
|
||||||
|
|
||||||
test: cprtests
|
test: cprtests
|
||||||
./cprtests
|
./cprtests
|
||||||
|
|
||||||
cprtests: cpr.o cprtests.o
|
cprtests: cpr.o cprtests.o
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||||
|
|
||||||
crctests: crc.c crc.h
|
crctests: crc.c crc.h
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -DCRCDEBUG -o $@ $<
|
$(CC) $(ALL_CCFLAGS) -g -DCRCDEBUG -o $@ $<
|
||||||
|
|
||||||
benchmarks: convert_benchmark
|
benchmarks: oneoff/convert_benchmark
|
||||||
./convert_benchmark
|
oneoff/convert_benchmark
|
||||||
|
|
||||||
convert_benchmark: convert_benchmark.o convert.o util.o
|
oneoff/convert_benchmark: oneoff/convert_benchmark.o convert.o util.o dsp/helpers/tables.o cpu.o $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||||
$(CC) $(CPPFLAGS) $(CFLAGS) -g -o $@ $^ -lm
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm -lpthread
|
||||||
|
|
||||||
|
oneoff/decode_comm_b: oneoff/decode_comm_b.o comm_b.o ais_charset.o
|
||||||
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||||
|
|
||||||
|
oneoff/dsp_error_measurement: oneoff/dsp_error_measurement.o dsp/helpers/tables.o cpu.o $(CPUFEATURES_OBJS) $(STARCH_OBJS)
|
||||||
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||||
|
|
||||||
|
oneoff/uc8_capture_stats: oneoff/uc8_capture_stats.o
|
||||||
|
$(CC) $(ALL_CCFLAGS) -g -o $@ $^ -lm
|
||||||
|
|
||||||
|
starchgen:
|
||||||
|
dsp/starchgen.py .
|
||||||
|
|
||||||
|
.PHONY: wisdom.local
|
||||||
|
wisdom.local: starch-benchmark
|
||||||
|
./starch-benchmark -i 5 -o wisdom.local mean_power_u16 mean_power_u16_aligned magnitude_uc8 magnitude_uc8_aligned
|
||||||
|
./starch-benchmark -i 5 -r wisdom.local -o wisdom.local
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,38 @@
|
||||||
|
# -*- makefile -*-
|
||||||
|
|
||||||
|
# cmake integration is a little tricky, so let's do this by hand for now
|
||||||
|
|
||||||
|
CPUFEATURES_UNAME ?= $(UNAME)
|
||||||
|
CPUFEATURES_ARCH ?= $(ARCH)
|
||||||
|
CPUFEATURES_CFLAGS ?= $(CFLAGS)
|
||||||
|
|
||||||
|
CPUFEATURES_OBJS := cpu_features/src/filesystem.o cpu_features/src/stack_line_reader.o cpu_features/src/string_view.o
|
||||||
|
CPUFEATURES_EXTRA_CFLAGS := -std=c99
|
||||||
|
CPUFEATURES_EXTRA_CPPFLAGS := -DSTACK_LINE_READER_BUFFER_SIZE=1024 -DNDEBUG -Icpu_features/include
|
||||||
|
|
||||||
|
ifeq ($(CPUFEATURES_UNAME),Linux)
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/hwcaps.o
|
||||||
|
CPUFEATURES_EXTRA_CPPFLAGS += -DHAVE_STRONG_GETAUXVAL
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CPUFEATURES_UNAME),Darwin)
|
||||||
|
CPUFEATURES_EXTRA_CPPFLAGS += -DHAVE_SYSCTLBYNAME
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CPUFEATURES_ARCH),x86_64)
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_x86.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(filter i%86,$(CPUFEATURES_ARCH)))
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_x86.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring arm,$(CPUFEATURES_ARCH)))
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_arm.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq (,$(findstring aarch64,$(CPUFEATURES_ARCH)))
|
||||||
|
CPUFEATURES_OBJS += cpu_features/src/cpuinfo_aarch64.o
|
||||||
|
endif
|
||||||
|
|
||||||
|
$(CPUFEATURES_OBJS): override ALL_CCFLAGS := $(CPUFEATURES_CPPFLAGS) $(CPUFEATURES_EXTRA_CPPFLAGS) $(CPUFEATURES_CFLAGS) $(CPUFEATURES_EXTRA_CFLAGS)
|
||||||
|
|
@ -7,15 +7,15 @@ about dump1090's operation to collectd for later graphing.
|
||||||
|
|
||||||
## Reading the json files
|
## Reading the json files
|
||||||
|
|
||||||
There are two ways to obtain the json files:
|
dump1090-fa writes json files periodically to the location specified by the `--write-json` command line option.
|
||||||
|
These json files can then be exposed via a separate standalone webserver e.g. lighttpd.
|
||||||
|
|
||||||
* By HTTP from dump1090's internal webserver, which defaults to running on port 8080. The json is served from the data/ path, e.g. http://somehost:8080/data/aircraft.json
|
The files are written periodically; for aircraft, typically once a second, for stats, once a minute.
|
||||||
* As a file in the directory specified by --write-json on dump1090's command line. These can be exposed via a
|
The interval between file updates can be controlled by the `--write-json-every` and `--json-stats-every` options.
|
||||||
separate webserver.
|
As these files are frequently updated, it's a good idea to put them in RAM rather than on disk. Package installs
|
||||||
|
default to putting the file under `/run`, which is in RAM.
|
||||||
|
|
||||||
The HTTP versions are always up to date.
|
New versions of each file are written to a temporary file, then atomically renamed to the right path, so you should never see partial copies.
|
||||||
The file versions are written periodically; for aircraft, typically once a second, for stats, once a minute.
|
|
||||||
The file versions are updated to a temporary file, then atomically renamed to the right path, so you should never see partial copies.
|
|
||||||
|
|
||||||
Each file contains a single JSON object. The file formats are:
|
Each file contains a single JSON object. The file formats are:
|
||||||
|
|
||||||
|
|
@ -38,19 +38,59 @@ This file contains dump1090's list of recently seen aircraft. The keys are:
|
||||||
* messages: the total number of Mode S messages processed since dump1090 started.
|
* messages: the total number of Mode S messages processed since dump1090 started.
|
||||||
* aircraft: an array of JSON objects, one per known aircraft. Each aircraft has the following keys. Keys will be omitted if data is not available.
|
* aircraft: an array of JSON objects, one per known aircraft. Each aircraft has the following keys. Keys will be omitted if data is not available.
|
||||||
* hex: the 24-bit ICAO identifier of the aircraft, as 6 hex digits. The identifier may start with '~', this means that the address is a non-ICAO address (e.g. from TIS-B).
|
* hex: the 24-bit ICAO identifier of the aircraft, as 6 hex digits. The identifier may start with '~', this means that the address is a non-ICAO address (e.g. from TIS-B).
|
||||||
* squawk: the 4-digit squawk (octal representation)
|
* type: type of underlying message, one of:
|
||||||
* flight: the flight name / callsign
|
* adsb_icao: messages from a Mode S or ADS-B transponder, using a 24-bit ICAO address
|
||||||
* lat, lon: the aircraft position in decimal degrees
|
* adsb_icao_nt: messages from an ADS-B equipped "non-transponder" emitter e.g. a ground vehicle, using a 24-bit ICAO address
|
||||||
* nucp: the NUCp (navigational uncertainty category) reported for the position
|
* adsr_icao: rebroadcast of ADS-B messages originally sent via another data link e.g. UAT, using a 24-bit ICAO address
|
||||||
* seen_pos: how long ago (in seconds before "now") the position was last updated
|
* tisb_icao: traffic information about a non-ADS-B target identified by a 24-bit ICAO address, e.g. a Mode S target tracked by secondary radar
|
||||||
* altitude: the aircraft altitude in feet, or "ground" if it is reporting it is on the ground
|
* adsb_other: messages from an ADS-B transponder using a non-ICAO address, e.g. anonymized address
|
||||||
* vert_rate: vertical rate in feet/minute
|
* adsr_other: rebroadcast of ADS-B messages originally sent via another data link e.g. UAT, using a non-ICAO address
|
||||||
|
* tisb_other: traffic information about a non-ADS-B target using a non-ICAO address
|
||||||
|
* tisb_trackfile: traffic information about a non-ADS-B target using a track/file identifier, typically from primary or Mode A/C radar
|
||||||
|
* flight: callsign, the flight name or aircraft registration as 8 chars (2.2.8.2.6)
|
||||||
|
* alt_baro: the aircraft barometric altitude in feet
|
||||||
|
* alt_geom: geometric (GNSS / INS) altitude in feet referenced to the WGS84 ellipsoid
|
||||||
|
* gs: ground speed in knots
|
||||||
|
* ias: indicated air speed in knots
|
||||||
|
* tas: true air speed in knots
|
||||||
|
* mach: Mach number
|
||||||
* track: true track over ground in degrees (0-359)
|
* track: true track over ground in degrees (0-359)
|
||||||
* speed: reported speed in kt. This is usually speed over ground, but might be IAS - you can't tell the difference here, sorry!
|
* track_rate: Rate of change of track, degrees/second
|
||||||
|
* roll: Roll, degrees, negative is left roll
|
||||||
|
* mag_heading: Heading, degrees clockwise from magnetic north
|
||||||
|
* true_heading: Heading, degrees clockwise from true north
|
||||||
|
* baro_rate: Rate of change of barometric altitude, feet/minute
|
||||||
|
* geom_rate: Rate of change of geometric (GNSS / INS) altitude, feet/minute
|
||||||
|
* squawk: Mode A code (Squawk), encoded as 4 octal digits
|
||||||
|
* emergency: ADS-B emergency/priority status, a superset of the 7x00 squawks (2.2.3.2.7.8.1.1)
|
||||||
|
* category: emitter category to identify particular aircraft or vehicle classes (values A0 - D7) (2.2.3.2.5.2)
|
||||||
|
* nav_qnh: altimeter setting (QFE or QNH/QNE), hPa
|
||||||
|
* nav_altitude_mcp: selected altitude from the Mode Control Panel / Flight Control Unit (MCP/FCU) or equivalent equipment
|
||||||
|
* nav_altitude_fms: selected altitude from the Flight Manaagement System (FMS) (2.2.3.2.7.1.3.3)
|
||||||
|
* nav_heading: selected heading (True or Magnetic is not defined in DO-260B, mostly Magnetic as that is the de facto standard) (2.2.3.2.7.1.3.7)
|
||||||
|
* nav_modes: set of engaged automation modes: 'autopilot', 'vnav', 'althold', 'approach', 'lnav', 'tcas'
|
||||||
|
* lat, lon: the aircraft position in decimal degrees
|
||||||
|
* nic: Navigation Integrity Category (2.2.3.2.7.2.6)
|
||||||
|
* rc: Radius of Containment, meters; a measure of position integrity derived from NIC & supplementary bits. (2.2.3.2.7.2.6, Table 2-69)
|
||||||
|
* seen_pos: how long ago (in seconds before "now") the position was last updated
|
||||||
|
* version: ADS-B Version Number 0, 1, 2 (3-7 are reserved) (2.2.3.2.7.5)
|
||||||
|
* nic_baro: Navigation Integrity Category for Barometric Altitude (2.2.5.1.35)
|
||||||
|
* nac_p: Navigation Accuracy for Position (2.2.5.1.35)
|
||||||
|
* nac_v: Navigation Accuracy for Velocity (2.2.5.1.19)
|
||||||
|
* sil: Source Integity Level (2.2.5.1.40)
|
||||||
|
* sil_type: interpretation of SIL: unknown, perhour, persample
|
||||||
|
* gva: Geometric Vertical Accuracy (2.2.3.2.7.2.8)
|
||||||
|
* sda: System Design Assurance (2.2.3.2.7.2.4.6)
|
||||||
|
* modea: true if we seem to be also receiving Mode A responses from this aircraft
|
||||||
|
* modec: true if we seem to be also receiving Mode C responses from this aircraft
|
||||||
|
* mlat: list of fields derived from MLAT data
|
||||||
|
* tisb: list of fields derived from TIS-B data
|
||||||
* messages: total number of Mode S messages received from this aircraft
|
* messages: total number of Mode S messages received from this aircraft
|
||||||
* seen: how long ago (in seconds before "now") a message was last received from this aircraft
|
* seen: how long ago (in seconds before "now") a message was last received from this aircraft
|
||||||
* rssi: recent average RSSI (signal power), in dbFS; this will always be negative.
|
* rssi: recent average RSSI (signal power), in dbFS; this will always be negative.
|
||||||
|
|
||||||
|
Section references (2.2.xyz) refer to DO-260B.
|
||||||
|
|
||||||
## history_0.json, history_1.json, ..., history_119.json
|
## history_0.json, history_1.json, ..., history_119.json
|
||||||
|
|
||||||
These files are historical copies of aircraft.json at (by default) 30 second intervals. They follow exactly the
|
These files are historical copies of aircraft.json at (by default) 30 second intervals. They follow exactly the
|
||||||
|
|
@ -124,3 +164,4 @@ Each period has the following subkeys:
|
||||||
* all: total tracks created
|
* all: total tracks created
|
||||||
* single_message: tracks consisting of only a single message. These are usually due to message decoding errors that produce a bad aircraft address.
|
* single_message: tracks consisting of only a single message. These are usually due to message decoding errors that produce a bad aircraft address.
|
||||||
* messages: total number of messages accepted by dump1090 from any source
|
* messages: total number of messages accepted by dump1090 from any source
|
||||||
|
* messages_by_df: an array of integers where entry N (0..31) is the total number of messages accepted with downlink format (DF) = N.
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,191 @@
|
||||||
|
# Adaptive gain configuration
|
||||||
|
|
||||||
|
dump1090-fa can optionally tune the receiver gain automatically to try to
|
||||||
|
pick a gain value for the particular hardware and RF environment without
|
||||||
|
manual tuning. This README covers some of the background for why this is
|
||||||
|
useful, and how to configure dump1090 to enable this feature.
|
||||||
|
|
||||||
|
## Background
|
||||||
|
|
||||||
|
In general, more receiver gain means better reception. Most ADS-B transmitters
|
||||||
|
within line of sight transmit with enough power that their messages can
|
||||||
|
potentially be decoded, but if the receiver gain setting is too low then very
|
||||||
|
weak signals may still be too weak to be decoded even after amplification.
|
||||||
|
Adding extra receiver gain helps in this case.
|
||||||
|
|
||||||
|
However, there are two problems with just adding more gain to a wideband SDR.
|
||||||
|
First, _everything_ is amplified, not only the signals of interest. Noise and
|
||||||
|
RF interference is also amplified. At high gain settings or in noisy RF
|
||||||
|
environments, this can interfere with receiving the ADS-B signals themselves.
|
||||||
|
|
||||||
|
Second, there is a wide range of possible ADS-B signal strengths. There can be
|
||||||
|
a 60dB or more difference between the weakest signals (a distant aircraft at
|
||||||
|
the limit of receiver range) and the strongest signals (a nearby aircraft on
|
||||||
|
the ramp 100m from the receiver). Increasing the receiver gain to handle the
|
||||||
|
weakest signals can mean that the strongest signals overload the receiver.
|
||||||
|
A rtlsdr receiver only has about 30-35dB of dynamic range available at a
|
||||||
|
particular gain setting, so there is no single gain setting that can
|
||||||
|
simultaneously handle both the weakest and strongest signals.
|
||||||
|
|
||||||
|
Adaptive gain tries to deal with these cases by changing the receiver gain
|
||||||
|
on the fly to handle the signal and noise levels that are currently being seen
|
||||||
|
without human intervention. It is not perfect and it's not a substitute for
|
||||||
|
hand-tuning of gain settings, but it aims at picking a reasonable setting for
|
||||||
|
cases where individual hand-tuning isn't possible.
|
||||||
|
|
||||||
|
## Where to configure adaptive gain options
|
||||||
|
|
||||||
|
How to configure adaptive gain varies depending on how you have installed
|
||||||
|
dump1090.
|
||||||
|
|
||||||
|
If you are using a PiAware sdcard image, adaptive gain can be configured by
|
||||||
|
editing `/boot/piaware-config.txt` or by using the `piaware-config` command.
|
||||||
|
|
||||||
|
If you are using the Debian package, adaptive gain can be configured by editing
|
||||||
|
`/etc/default/dump1090-fa`.
|
||||||
|
|
||||||
|
If running dump1090 directly, adaptive gain options are set directly by
|
||||||
|
command-line options.
|
||||||
|
|
||||||
|
## Default settings
|
||||||
|
|
||||||
|
For new PiAware or Debian package installations, adaptive dynamic range mode
|
||||||
|
is enabled by default and adaptive burst mode is disabled by default.
|
||||||
|
|
||||||
|
For _upgrades_ of PiAware or the Debian package from versions older than 6.0,
|
||||||
|
both adaptive gain modes are disabled by default.
|
||||||
|
|
||||||
|
These defaults can be overridden as described below.
|
||||||
|
|
||||||
|
## Adaptive gain in dynamic range mode
|
||||||
|
|
||||||
|
The dynamic range adaptive gain mode attempts to set the receiver gain to
|
||||||
|
maintain a given dynamic range - that is, it tries to set the gain so that
|
||||||
|
general noise is at or below a given level. This takes into account different
|
||||||
|
or changing RF environments and different receiver hardware (antenna,
|
||||||
|
preamplifiers, etc) that affects the overall gain of the system, and usually
|
||||||
|
will pick a reasonable gain setting without intervention.
|
||||||
|
|
||||||
|
To enable this mode:
|
||||||
|
|
||||||
|
* Set `adaptive-dynamic-range yes` in piaware-config; or
|
||||||
|
* Set `ADAPTIVE_DYNAMIC_RANGE=yes` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-range` option on the command line.
|
||||||
|
|
||||||
|
The default settings for dynamic range will use a dynamic range target chosen
|
||||||
|
based on SDR type (e.g. 30dB for rtlsdr receivers). This is usually a good
|
||||||
|
default. To override this target:
|
||||||
|
|
||||||
|
* Set `adaptive-dynamic-range-target` in piaware-config; or
|
||||||
|
* Set `ADAPTIVE_DYNAMIC_RANGE_TARGET` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-range-target` option on the command line.
|
||||||
|
|
||||||
|
## Adaptive gain in "burst" / loud signal mode
|
||||||
|
|
||||||
|
The "burst" adaptive gain mode listens for loud bursts of signal that were
|
||||||
|
_not_ successfully decoded as ADS-B messages, but which have approximately
|
||||||
|
the right timing to be possible messages that were lost due to receiver
|
||||||
|
overloading. When enough overly-loud signals are heard in a short period of
|
||||||
|
time, dump1090 will _reduce_ the receiver gain to try to allow them to be
|
||||||
|
received.
|
||||||
|
|
||||||
|
This is a more situational setting. It may allow reception of loud nearby
|
||||||
|
aircraft (e.g. if you are close to an airport). The tradeoff is that when
|
||||||
|
there are nearby aircraft, overall receiver range may be reduced. Whether
|
||||||
|
this is a good tradeoff depends on the aircraft you're interested in.
|
||||||
|
By default, adaptive gain burst mode is disabled.
|
||||||
|
|
||||||
|
To enable burst mode:
|
||||||
|
|
||||||
|
* Set `adaptive-burst yes` in piaware-config; or
|
||||||
|
* Set `ADAPTIVE_BURST=yes` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-burst` option on the command line.
|
||||||
|
|
||||||
|
This mode is more experimental than the dynamic range mode and tweaking of
|
||||||
|
the advanced burst options may be needed depending on your local installation.
|
||||||
|
In particular, `--adaptive-burst-loud-rate` and `adaptive-burst-quiet-rate`
|
||||||
|
may need adjusting. Feedback on what works for you and what doesn't would
|
||||||
|
be appreciated!
|
||||||
|
|
||||||
|
Burst mode and dynamic range mode can be enabled at the same time.
|
||||||
|
|
||||||
|
## Limiting the gain range
|
||||||
|
|
||||||
|
If you know in advance approximately what the gain setting should be, so
|
||||||
|
you want to allow adaptive gain to change the gain only within a certain range,
|
||||||
|
you can set minimum and maximum gain settings in dB. Adaptive gain will only
|
||||||
|
adjust the gain within this range. To set this:
|
||||||
|
|
||||||
|
* Set `adaptive-min-gain` and `adaptive-max-gain` in piaware-config; or
|
||||||
|
* Set `ADAPTIVE_MIN_GAIN` and `ADAPTIVE_MAX_GAIN` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-min-gain` and `--adaptive-max-gain` options on the command line.
|
||||||
|
|
||||||
|
If you know approximately where the gain should be, then a good starting point would be
|
||||||
|
to set the max and min adaptive gain to +/- 10dB around your gain setting.
|
||||||
|
|
||||||
|
## Reducing the CPU cost of adaptive gain
|
||||||
|
|
||||||
|
The measurements needed to adjust gain have a CPU cost, and on slower
|
||||||
|
devices it may be useful to reduce the amount of work that adaptive gain does.
|
||||||
|
This can be done by adjusting the adaptive gain duty cycle. This is a
|
||||||
|
percentage that controls what fraction of incoming data adaptive gain inspects.
|
||||||
|
100% means that every sample is inspected. Lower values reduce CPU use, with
|
||||||
|
a tradeoff that adaptive gain has a less accurate picture of the RF
|
||||||
|
environment. The default duty cycle is 50% on "fast" CPUs and 10% on "slow"
|
||||||
|
CPUs (where currently "slow" means "armv6 architecture", for example the
|
||||||
|
Pi Zero or Pi 1). To reduce the duty cycle further:
|
||||||
|
|
||||||
|
* Set `slow-cpu yes` in piaware-config; or
|
||||||
|
* Set `SLOW_CPU=yes` in `/etc/default/dump1090-fa`; or
|
||||||
|
* Pass the `--adaptive-duty-cycle` option on the command line
|
||||||
|
|
||||||
|
## Advanced options
|
||||||
|
|
||||||
|
There are a number of advanced options that are only supported as
|
||||||
|
command-line options or via the EXTRA_OPTIONS setting in
|
||||||
|
`/etc/default/dump1090-fa`. They tweak settings that require some knowledge of
|
||||||
|
dump1090 internals to make sense of, so YMMV.
|
||||||
|
|
||||||
|
For a complete list of options, run `dump1090-fa --help` and look at the
|
||||||
|
adaptive gain section.
|
||||||
|
|
||||||
|
## Device support
|
||||||
|
|
||||||
|
Currently, adaptive gain is only supported on rtlsdr devices. Support for other
|
||||||
|
SDRs is planned for the future.
|
||||||
|
|
||||||
|
If you're a developer and want to add support for your SDR, you'll need
|
||||||
|
to implement the gain control API used in `sdr.[ch]`. See `sdr_rtlsdr.c`
|
||||||
|
(`rtlsdrGetGain`, `rtlsdrSetGain`, etc) for examples.
|
||||||
|
|
||||||
|
## Comparison with wiedehopf's auto-gain scripts
|
||||||
|
|
||||||
|
There is an [auto-gain script](https://github.com/wiedehopf/adsb-scripts/wiki/Automatic-gain-optimization-for-readsb-and-dump1090-fa)
|
||||||
|
written by [wiedehopf](https://github.com/wiedehopf) that aims to solve similar
|
||||||
|
problems. The implementation approaches are quite different, and which one works best
|
||||||
|
for you will depend on the problem you're trying to solve.
|
||||||
|
|
||||||
|
The major differences between adaptive gain and the auto-gain script are:
|
||||||
|
|
||||||
|
* Adaptive gain works on short-term data (seconds or minutes) and can react to
|
||||||
|
changes in a similar timeframe. It tries to set an appropriate gain for the
|
||||||
|
_current_ environment without much regard for longer-term trends. The auto-gain
|
||||||
|
script looks at data over longer timeframes (1+ days) and reacts more slowly,
|
||||||
|
but takes into account data across that whole period.
|
||||||
|
|
||||||
|
* Adaptive gain in dynamic range mode looks at an estimate of the noise floor
|
||||||
|
to decide whether to increase gain. Adaptive gain in burst mode looks at the
|
||||||
|
signal strength of samples that were _not_ successfully decoded to decide when
|
||||||
|
to reduce gain. The auto-gain scripts look at the signal strength of _successfully_
|
||||||
|
decoded messages to decide when to increase or decrease gain. These are each measuring
|
||||||
|
something different, and which is most effective will depend on the exact RF
|
||||||
|
environment.
|
||||||
|
|
||||||
|
* Adaptive gain burst mode and the auto-gain script superfically measure similar things,
|
||||||
|
but the difference in measurement timeframe mean they react quite differently. Burst mode
|
||||||
|
tries to react to transient loud signals i.e. temporarily nearby aircraft. The auto-gain
|
||||||
|
script uses the loud-messages fraction as an estimate for messages lost to excessive
|
||||||
|
gain over the long term, not only the transient case.
|
||||||
|
|
||||||
|
* Adaptive gain has a few less moving parts (i.e. no external scripts, no config changes over
|
||||||
|
time) as it's built directly into dump1090 itself.
|
||||||
128
README.md
128
README.md
|
|
@ -1,38 +1,122 @@
|
||||||
# dump1090-fa Debian/Raspbian packages
|
# dump1090-fa Debian/Raspbian packages
|
||||||
|
|
||||||
This is a fork of [dump1090-mutability](https://github.com/mutability/dump1090)
|
dump1090-fa is a ADS-B, Mode S, and Mode 3A/3C demodulator and decoder that
|
||||||
customized for use within [FlightAware](http://flightaware.com)'s
|
will receive and decode aircraft transponder messages received via
|
||||||
[PiAware](http://flightaware.com/adsb/piaware) software.
|
a directly connected software defined radio, or from data provided over a
|
||||||
|
network connection.
|
||||||
|
|
||||||
It is designed to build as a Debian package.
|
It is the successor to
|
||||||
|
[dump1090-mutability](https://github.com/mutability/dump1090) and is
|
||||||
|
maintained by [FlightAware](http://flightaware.com/).
|
||||||
|
|
||||||
## Building under jessie
|
It can provide a display of locally received aircraft data in a terminal or
|
||||||
|
via a browser map. Together with [PiAware](http://flightaware.com/adsb/piaware)
|
||||||
|
it can be used to contribute crowd-sourced flight tracking data to FlightAware.
|
||||||
|
|
||||||
### Dependencies - bladeRF
|
It is designed to build as a Debian package, but should also be buildable on
|
||||||
|
many other Linux or Unix-like systems.
|
||||||
|
|
||||||
You will need a build of libbladeRF. You can build packages from source:
|
## Building under bullseye, buster, or stretch
|
||||||
|
|
||||||
$ git clone https://github.com/Nuand/bladeRF.git
|
```bash
|
||||||
$ cd bladeRF
|
$ sudo apt-get install build-essential fakeroot debhelper librtlsdr-dev pkg-config libncurses5-dev libbladerf-dev libhackrf-dev liblimesuite-dev
|
||||||
$ dpkg-buildpackage -b
|
$ ./prepare-build.sh bullseye # or buster, or stretch
|
||||||
|
$ cd package-bullseye # or buster, or stretch
|
||||||
|
$ dpkg-buildpackage -b --no-sign
|
||||||
|
```
|
||||||
|
|
||||||
Or Nuand has some build/install instructions including an Ubuntu PPA
|
## Building with limited dependencies
|
||||||
at https://github.com/Nuand/bladeRF/wiki/Getting-Started:-Linux
|
|
||||||
|
|
||||||
Or FlightAware provides armhf packages as part of the piaware repository;
|
(Supported for bullseye and buster builds only)
|
||||||
see https://flightaware.com/adsb/piaware/install
|
|
||||||
|
|
||||||
### Dependencies - rtlsdr
|
The package supports some build profiles to allow building without all
|
||||||
|
required SDR libraries being present. This will produce a package with
|
||||||
|
limited SDR support only.
|
||||||
|
|
||||||
This is packaged with jessie. "sudo apt-get install librtlsdr-dev"
|
Pass `--build-profiles` to `dpkg-buildpackage` with a comma-separated list of
|
||||||
|
profiles. The list of profiles should include `custom` and zero or more of
|
||||||
|
`rtlsdr`, `bladerf`, `hackrf`, `limesdr` depending on what you want:
|
||||||
|
|
||||||
### Actually building it
|
```bash
|
||||||
|
$ dpkg-buildpackage -b --no-sign --build-profiles=custom,rtlsdr # builds with rtlsdr support only
|
||||||
|
$ dpkg-buildpackage -b --no-sign --build-profiles=custom,rtlsdr,bladerf # builds with rtlsdr and bladeRF support
|
||||||
|
$ dpkg-buildpackage -b --no-sign --build-profiles=custom # builds with _no_ SDR support (network support only)
|
||||||
|
```
|
||||||
|
|
||||||
Nothing special, just build it ("dpkg-buildpackage -b")
|
## Building manually
|
||||||
|
|
||||||
## Building under wheezy
|
You can probably just run "make" after installing the required dependencies.
|
||||||
|
Binaries are built in the source directory; you will need to arrange to
|
||||||
|
install them (and a method for starting them) yourself.
|
||||||
|
|
||||||
First run "prepare-wheezy-tree.sh". This will create a package tre in
|
``make BLADERF=no`` will disable bladeRF support and remove the dependency on
|
||||||
package-wheezy/. Build in there ("dpkg-buildpackage -b")
|
libbladeRF.
|
||||||
|
|
||||||
The wheezy build does not include bladeRF support.
|
``make RTLSDR=no`` will disable rtl-sdr support and remove the dependency on
|
||||||
|
librtlsdr.
|
||||||
|
|
||||||
|
``make HACKRF=no`` will disable HackRF support and remove the dependency on
|
||||||
|
libhackrf.
|
||||||
|
|
||||||
|
``make LIMESDR=no`` will disable LimeSDR support and remove the dependency on
|
||||||
|
libLimeSuite.
|
||||||
|
|
||||||
|
## Building on OSX
|
||||||
|
|
||||||
|
Minimal testing on Mojave 10.14.6, YMMV.
|
||||||
|
|
||||||
|
```
|
||||||
|
$ brew install librtlsdr
|
||||||
|
$ brew install libbladerf
|
||||||
|
$ brew install hackrf
|
||||||
|
$ brew install pkg-config
|
||||||
|
$ make
|
||||||
|
```
|
||||||
|
|
||||||
|
## Building on FreeBSD
|
||||||
|
|
||||||
|
Minimal testing on 12.1-RELEASE, YMMV.
|
||||||
|
|
||||||
|
```
|
||||||
|
# pkg install gmake
|
||||||
|
# pkg install pkgconf
|
||||||
|
# pkg install rtl-sdr
|
||||||
|
# pkg install bladerf
|
||||||
|
# pkg install hackrf
|
||||||
|
$ gmake
|
||||||
|
```
|
||||||
|
|
||||||
|
## Generating wisdom files
|
||||||
|
|
||||||
|
dump1090-fa uses [starch](https://github.com/flightaware/starch) to build
|
||||||
|
multiple versions of the DSP code and choose the fastest supported by the
|
||||||
|
hardware at runtime. The implementations chosen can been seen by running
|
||||||
|
`dump1090-fa --version`.
|
||||||
|
|
||||||
|
The implementations used are controlled by "wisdom files", a list of
|
||||||
|
implementations to use in order of priority. For each DSP function, the first
|
||||||
|
implementation listed that's supported by the current hardware is used.
|
||||||
|
By default dump1090-fa provides compiled-in wisdom for [x86](wisdom.x86),
|
||||||
|
[ARM 32-bit](wisdom.arm), and [ARM 64-bit](wisdom.aarch64). If the defaults
|
||||||
|
are not suitable for your hardware or if you're building on a different
|
||||||
|
architecture, you may want to generate your own external wisdom file.
|
||||||
|
|
||||||
|
Ideally, to get stable results, you want to do this on an idle system
|
||||||
|
with CPU frequency scaling disabled. Running the benchmarks will take
|
||||||
|
some time (10s of minutes).
|
||||||
|
|
||||||
|
### Package installs
|
||||||
|
|
||||||
|
Run `/usr/share/dump1090-fa/generate-wisdom`. Wait.
|
||||||
|
|
||||||
|
Follow the instructions to copy the resulting wisdom file to `/etc/dump1090-fa/wisdom.local`.
|
||||||
|
|
||||||
|
Restart dump1090.
|
||||||
|
|
||||||
|
### Manual installs
|
||||||
|
|
||||||
|
Run `make wisdom.local`. Wait.
|
||||||
|
|
||||||
|
Copy the resulting `wisdom.local` file somewhere appropriate.
|
||||||
|
|
||||||
|
Update the dump1090-fa command-line options to include `--wisdom /path/to/wisdom.local`
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,645 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// adaptive.c: adaptive gain control
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 FlightAware, LLC
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "dump1090.h"
|
||||||
|
#include "adaptive.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// gain limits
|
||||||
|
//
|
||||||
|
static int adaptive_gain_min;
|
||||||
|
static int adaptive_gain_max;
|
||||||
|
|
||||||
|
// gain steps relative to current gain
|
||||||
|
static float adaptive_gain_up_db;
|
||||||
|
static float adaptive_gain_down_db;
|
||||||
|
|
||||||
|
//
|
||||||
|
// block handling
|
||||||
|
//
|
||||||
|
// 1 block = approx 1 second of samples. Control updates are done at the end of each block only.
|
||||||
|
// Each block is made up of an integer number of subblocks (currently 20)
|
||||||
|
//
|
||||||
|
// 1 subblock = approx 50ms of samples. Duty cycle decisions are made at the subblock level;
|
||||||
|
// either the whole subblock is processed, or the whole subblock is skipped.
|
||||||
|
// Each subblock is made up of an integer number of windows (currently 1250)
|
||||||
|
//
|
||||||
|
// 1 window = approx 40us of samples. Burst measurements are made by counting samples within each window.
|
||||||
|
//
|
||||||
|
// All three levels are aligned, i.e. every block boundary is also a subblock boundary;
|
||||||
|
// every subblock boundary is also a window boundary.
|
||||||
|
|
||||||
|
|
||||||
|
static const unsigned adaptive_subblocks_per_block = 20; // subblocks per block
|
||||||
|
static unsigned adaptive_subblocks_remaining; // subblocks remaining in the current block
|
||||||
|
|
||||||
|
// Duty cycle is expressed as N/D
|
||||||
|
// where N = adaptive_subblbock_dutycycle_N = adaptive_subblocks_per_block * Modes.adaptive_duty_cycle
|
||||||
|
// and D = adaptive_subblocks_dutycycle_D = adaptive_subblocks_per_block
|
||||||
|
//
|
||||||
|
// i.e. within each block, there are exactly N active subblocks out of D total subblocks
|
||||||
|
//
|
||||||
|
// The active subblocks are distributed evenly across the block by increasing a counter by N on each
|
||||||
|
// subblock, modulo D, and marking the subblock as active each time the counter rolls over.
|
||||||
|
|
||||||
|
static unsigned adaptive_subblock_dutycycle_N; // subblock duty cycle numerator N
|
||||||
|
|
||||||
|
// stretch gcc doesn't like this as a separate const
|
||||||
|
#define adaptive_subblock_dutycycle_D adaptive_subblocks_per_block
|
||||||
|
|
||||||
|
static unsigned adaptive_subblock_dutycycle_counter; // subblock duty cycle counter (modulo D)
|
||||||
|
static bool adaptive_subblock_active; // is the current subblock active i.e. samples should be processed, not skipped?
|
||||||
|
|
||||||
|
static unsigned adaptive_samples_per_subblock; // samples per subblock
|
||||||
|
static unsigned adaptive_subblock_samples_remaining; // samples remaining in the current subblock
|
||||||
|
|
||||||
|
static unsigned adaptive_samples_per_window; // samples per window
|
||||||
|
|
||||||
|
void adaptive_init();
|
||||||
|
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||||
|
static void adaptive_update_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||||
|
static void adaptive_end_of_block();
|
||||||
|
static void adaptive_control_update();
|
||||||
|
|
||||||
|
//
|
||||||
|
// burst handling
|
||||||
|
//
|
||||||
|
|
||||||
|
static unsigned adaptive_burst_window_remaining; // samples remaining in the current burst window
|
||||||
|
static unsigned adaptive_burst_window_counter; // loud samples seen in current burst window
|
||||||
|
static unsigned adaptive_burst_runlength; // consecutive loud burst windows seen
|
||||||
|
static unsigned adaptive_burst_block_loud_undecoded; // loud undecoded bursts seen in this block so far
|
||||||
|
static unsigned adaptive_burst_block_loud_decoded; // loud decoded messages seen in this block so far
|
||||||
|
static double adaptive_burst_loud_undecoded_smoothed; // smoothed rate of loud misdecodes per block
|
||||||
|
static double adaptive_burst_loud_decoded_smoothed; // smoothed rate of loud successful decodes per block
|
||||||
|
static unsigned adaptive_burst_change_timer; // countdown inhibiting control after changing gain
|
||||||
|
static double adaptive_burst_loud_threshold; // current signal level threshold for a "loud decode"
|
||||||
|
static unsigned adaptive_burst_loud_blocks = 0; // consecutive blocks with loud rate
|
||||||
|
static unsigned adaptive_burst_quiet_blocks = 0; // consecutive blocks with quiet rate
|
||||||
|
|
||||||
|
static void adaptive_burst_update(uint16_t *buf, unsigned length);
|
||||||
|
static void adaptive_burst_skip(unsigned length);
|
||||||
|
static unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n);
|
||||||
|
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows);
|
||||||
|
static void adaptive_burst_end_of_window(unsigned counter);
|
||||||
|
static void adaptive_burst_end_of_block();
|
||||||
|
|
||||||
|
//
|
||||||
|
// noise floor measurement (adaptive dynamic range)
|
||||||
|
//
|
||||||
|
|
||||||
|
static unsigned *adaptive_range_radix; // radix-sort buckets for current block
|
||||||
|
static unsigned adaptive_range_radix_counter; // sum of all radix-sort buckets (= number of samples sorted)
|
||||||
|
static double adaptive_range_smoothed; // smoothed noise floor estimate, dBFS
|
||||||
|
static enum { RANGE_SCAN_IDLE, RANGE_SCAN_UP, RANGE_SCAN_DOWN, RANGE_RESCAN_UP, RANGE_RESCAN_DOWN } adaptive_range_state = RANGE_SCAN_UP;
|
||||||
|
static unsigned adaptive_range_change_timer; // countdown inhibiting control after changing gain
|
||||||
|
static unsigned adaptive_range_rescan_timer; // countdown to next upwards gain reprobe
|
||||||
|
static int adaptive_range_gain_limit; // probed maximum gain step with acceptable dynamic range
|
||||||
|
|
||||||
|
static void adaptive_range_update(uint16_t *buf, unsigned length);
|
||||||
|
static void adaptive_range_end_of_block();
|
||||||
|
|
||||||
|
// Try to change the SDR gain to 'step' and tell the user about it,
|
||||||
|
// with 'why' as the reason to show. Return true if the gain actually changed.
|
||||||
|
static bool adaptive_set_gain(int step, const char *why)
|
||||||
|
{
|
||||||
|
if (step < adaptive_gain_min)
|
||||||
|
step = adaptive_gain_min;
|
||||||
|
if (step > adaptive_gain_max)
|
||||||
|
step = adaptive_gain_max;
|
||||||
|
|
||||||
|
int current_gain = sdrGetGain();
|
||||||
|
if (current_gain == step)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
fprintf(stderr, "adaptive: changing gain from %.1fdB (step %d) to %.1fdB (step %d) because: %s\n",
|
||||||
|
sdrGetGainDb(current_gain), current_gain, sdrGetGainDb(step), step, why);
|
||||||
|
|
||||||
|
int new_gain = sdrSetGain(step);
|
||||||
|
bool changed = (current_gain != new_gain);
|
||||||
|
if (changed)
|
||||||
|
++Modes.stats_current.adaptive_gain_changes;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update internal state to reflect a gain change
|
||||||
|
// (usually after adaptive_set_gain returns true, but also called during init)
|
||||||
|
static void adaptive_gain_changed()
|
||||||
|
{
|
||||||
|
int new_gain = sdrGetGain();
|
||||||
|
adaptive_gain_up_db = sdrGetGainDb(new_gain + 1) - sdrGetGainDb(new_gain);
|
||||||
|
adaptive_gain_down_db = sdrGetGainDb(new_gain) - sdrGetGainDb(new_gain - 1);
|
||||||
|
|
||||||
|
double loud_threshold_dbfs = 0 - adaptive_gain_up_db - 3.0;
|
||||||
|
adaptive_burst_loud_threshold = pow(10, loud_threshold_dbfs / 10.0);
|
||||||
|
|
||||||
|
adaptive_range_change_timer = Modes.adaptive_range_change_delay;
|
||||||
|
adaptive_burst_change_timer = Modes.adaptive_burst_change_delay;
|
||||||
|
adaptive_burst_loud_blocks = 0;
|
||||||
|
adaptive_burst_quiet_blocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// External init entry point
|
||||||
|
void adaptive_init()
|
||||||
|
{
|
||||||
|
int maxgain = sdrGetMaxGain();
|
||||||
|
|
||||||
|
// If the SDR doesn't support gain control, disable ourselves
|
||||||
|
if (maxgain < 0) {
|
||||||
|
if (Modes.adaptive_burst_control || Modes.adaptive_range_control) {
|
||||||
|
fprintf(stderr, "warning: adaptive gain control requested, but SDR gain control not available, ignored.\n");
|
||||||
|
}
|
||||||
|
Modes.adaptive_burst_control = false;
|
||||||
|
Modes.adaptive_range_control = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If we're disabled, do nothing
|
||||||
|
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Set up window, subblock, and block sizes
|
||||||
|
// Look for 40us bursts
|
||||||
|
adaptive_samples_per_window = Modes.sample_rate / 25000;
|
||||||
|
|
||||||
|
// Use ~50ms subblocks; ensure it's an exact multiple of window size
|
||||||
|
adaptive_samples_per_subblock = adaptive_samples_per_window * 1250;
|
||||||
|
|
||||||
|
adaptive_subblocks_remaining = adaptive_subblocks_per_block;
|
||||||
|
adaptive_subblock_samples_remaining = adaptive_samples_per_subblock;
|
||||||
|
adaptive_subblock_active = false;
|
||||||
|
|
||||||
|
float N = roundf(adaptive_subblock_dutycycle_D * Modes.adaptive_duty_cycle);
|
||||||
|
if (N <= 0)
|
||||||
|
N = 1;
|
||||||
|
if (N > adaptive_subblock_dutycycle_D)
|
||||||
|
N = adaptive_subblock_dutycycle_D;
|
||||||
|
fprintf(stderr, "adaptive: using %.0f%% duty cycle\n", 100.0 * N / adaptive_subblock_dutycycle_D);
|
||||||
|
adaptive_subblock_dutycycle_N = (unsigned)N;
|
||||||
|
|
||||||
|
adaptive_burst_window_remaining = adaptive_samples_per_window;
|
||||||
|
adaptive_burst_window_counter = 0;
|
||||||
|
|
||||||
|
adaptive_range_radix = calloc(sizeof(unsigned), 65536);
|
||||||
|
adaptive_range_state = RANGE_RESCAN_UP;
|
||||||
|
|
||||||
|
// select and enforce gain limits
|
||||||
|
for (adaptive_gain_min = 0; adaptive_gain_min < maxgain; ++adaptive_gain_min) {
|
||||||
|
if (sdrGetGainDb(adaptive_gain_min) >= Modes.adaptive_min_gain_db)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (adaptive_gain_max = maxgain; adaptive_gain_max > adaptive_gain_min; --adaptive_gain_max) {
|
||||||
|
if (sdrGetGainDb(adaptive_gain_max) <= Modes.adaptive_max_gain_db)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "adaptive: enabled adaptive gain control with gain limits %.1fdB (step %d) .. %.1fdB (step %d)\n",
|
||||||
|
sdrGetGainDb(adaptive_gain_min), adaptive_gain_min, sdrGetGainDb(adaptive_gain_max), adaptive_gain_max);
|
||||||
|
if (Modes.adaptive_range_control)
|
||||||
|
fprintf(stderr, "adaptive: enabled dynamic range control, target dynamic range %.1fdB\n", Modes.adaptive_range_target);
|
||||||
|
if (Modes.adaptive_burst_control)
|
||||||
|
fprintf(stderr, "adaptive: enabled burst control\n");
|
||||||
|
adaptive_set_gain(sdrGetGain(), "constraining gain to adaptive gain limits");
|
||||||
|
adaptive_gain_changed();
|
||||||
|
|
||||||
|
adaptive_range_gain_limit = sdrGetGain();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed some samples into the adaptive system. Any number of samples might be passed in.
|
||||||
|
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded)
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_burst_control && !Modes.adaptive_range_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// process complete subblocks
|
||||||
|
while (length >= adaptive_subblock_samples_remaining) {
|
||||||
|
if (adaptive_subblock_active)
|
||||||
|
adaptive_update_subblock(buf, adaptive_subblock_samples_remaining, decoded);
|
||||||
|
|
||||||
|
buf += adaptive_subblock_samples_remaining;
|
||||||
|
length -= adaptive_subblock_samples_remaining;
|
||||||
|
adaptive_subblock_samples_remaining = adaptive_samples_per_subblock;
|
||||||
|
|
||||||
|
adaptive_subblock_dutycycle_counter += adaptive_subblock_dutycycle_N;
|
||||||
|
if (adaptive_subblock_dutycycle_counter >= adaptive_subblock_dutycycle_D) {
|
||||||
|
adaptive_subblock_dutycycle_counter -= adaptive_subblock_dutycycle_D;
|
||||||
|
adaptive_subblock_active = true;
|
||||||
|
} else {
|
||||||
|
adaptive_subblock_active = false;
|
||||||
|
// fake a quiet window to reset any existing run
|
||||||
|
adaptive_burst_end_of_window(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!--adaptive_subblocks_remaining) {
|
||||||
|
// Block completed, do a control update
|
||||||
|
adaptive_subblocks_remaining = adaptive_subblocks_per_block;
|
||||||
|
adaptive_end_of_block();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// process final samples that don't complete a subblock
|
||||||
|
if (length > 0) {
|
||||||
|
if (adaptive_subblock_active)
|
||||||
|
adaptive_update_subblock(buf, length, decoded);
|
||||||
|
adaptive_subblock_samples_remaining -= length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Feed some samples into the adaptive system. The samples are guaranteed to not cross a subblock boundary.
|
||||||
|
// The samples should be processsed (i.e. duty cycle is in the active part)
|
||||||
|
static void adaptive_update_subblock(uint16_t *buf, unsigned length, struct modesMessage *decoded)
|
||||||
|
{
|
||||||
|
if (decoded) {
|
||||||
|
if (/* decoded->msgbits == 112 && */ decoded->signalLevel >= adaptive_burst_loud_threshold)
|
||||||
|
++adaptive_burst_block_loud_decoded;
|
||||||
|
adaptive_burst_skip(length);
|
||||||
|
} else {
|
||||||
|
adaptive_burst_update(buf, length);
|
||||||
|
adaptive_range_update(buf, length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: ignore the next 'length' samples (they are a successfully decoded message)
|
||||||
|
static void adaptive_burst_skip(unsigned length)
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_burst_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// first window
|
||||||
|
if (length < adaptive_burst_window_remaining) {
|
||||||
|
// partial fill
|
||||||
|
adaptive_burst_window_remaining -= length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip remainder of first window, dispatch it
|
||||||
|
adaptive_burst_end_of_window(adaptive_burst_window_counter);
|
||||||
|
length -= adaptive_burst_window_remaining;
|
||||||
|
|
||||||
|
// skip remaining windows, dispatch them
|
||||||
|
unsigned windows = length / adaptive_samples_per_window;
|
||||||
|
unsigned samples = windows * adaptive_samples_per_window;
|
||||||
|
while (windows--)
|
||||||
|
adaptive_burst_end_of_window(0);
|
||||||
|
|
||||||
|
length -= samples;
|
||||||
|
|
||||||
|
// final partial window
|
||||||
|
adaptive_burst_window_counter = 0;
|
||||||
|
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: process 'length' samples from 'buf', look for loud bursts;
|
||||||
|
// the samples might cross burst window boundaries;
|
||||||
|
// the samples will not cross a block boundary.
|
||||||
|
static void adaptive_burst_update(uint16_t *buf, unsigned length)
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_burst_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// first window
|
||||||
|
if (length < adaptive_burst_window_remaining) {
|
||||||
|
// partial fill
|
||||||
|
adaptive_burst_window_counter += adaptive_burst_count_samples(buf, length);
|
||||||
|
adaptive_burst_window_remaining -= length;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// complete fill of first partial window
|
||||||
|
unsigned n = adaptive_burst_window_remaining;
|
||||||
|
unsigned counter = adaptive_burst_window_counter + adaptive_burst_count_samples(buf, n);
|
||||||
|
adaptive_burst_end_of_window(counter);
|
||||||
|
buf += n;
|
||||||
|
length -= n;
|
||||||
|
|
||||||
|
// remaining windows
|
||||||
|
unsigned windows = length / adaptive_samples_per_window;
|
||||||
|
unsigned samples = windows * adaptive_samples_per_window;
|
||||||
|
adaptive_burst_scan_windows(buf, windows);
|
||||||
|
buf += samples;
|
||||||
|
length -= samples;
|
||||||
|
|
||||||
|
// final partial window
|
||||||
|
adaptive_burst_window_counter = adaptive_burst_count_samples(buf, length);
|
||||||
|
adaptive_burst_window_remaining = adaptive_samples_per_window - length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: process 'windows' complete burst windows starting at 'buf';
|
||||||
|
// 'buf' is aligned to the start of a burst window
|
||||||
|
static void adaptive_burst_scan_windows(uint16_t *buf, unsigned windows)
|
||||||
|
{
|
||||||
|
while (windows--) {
|
||||||
|
unsigned counter = adaptive_burst_count_samples(buf, adaptive_samples_per_window);
|
||||||
|
buf += adaptive_samples_per_window;
|
||||||
|
adaptive_burst_end_of_window(counter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: process 'n' samples from 'buf', look for loud samples;
|
||||||
|
// the samples are guaranteed not to cross window boundaries;
|
||||||
|
// return the number of loud samples seen
|
||||||
|
static inline unsigned adaptive_burst_count_samples(uint16_t *buf, unsigned n)
|
||||||
|
{
|
||||||
|
unsigned counter;
|
||||||
|
starch_count_above_u16(buf, n, 46395 /* -3dBFS */, &counter);
|
||||||
|
return counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: we reached the end of a burst window with 'counter'
|
||||||
|
// loud samples seen, handle that window.
|
||||||
|
static void adaptive_burst_end_of_window(unsigned counter)
|
||||||
|
{
|
||||||
|
if (counter > adaptive_samples_per_window / 4) {
|
||||||
|
// This window is loud, extend any existing run of loud windows
|
||||||
|
++adaptive_burst_runlength;
|
||||||
|
} else {
|
||||||
|
// Quiet window. If we saw a run of loud windows >= 80us long, count
|
||||||
|
// that as a candidate for an over-amplified message that was
|
||||||
|
// not decoded.
|
||||||
|
if (adaptive_burst_runlength >= 2 && adaptive_burst_runlength <= 5)
|
||||||
|
++adaptive_burst_block_loud_undecoded;
|
||||||
|
adaptive_burst_runlength = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Noise measurement: process 'length' samples from 'buf'.
|
||||||
|
// The samples will not cross a block boundary.
|
||||||
|
static void adaptive_range_update(uint16_t *buf, unsigned length)
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_range_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
adaptive_range_radix_counter += length;
|
||||||
|
while (length--) {
|
||||||
|
// do a very simple radix sort of sample magnitudes
|
||||||
|
// so we can later find the Nth percentile value
|
||||||
|
++adaptive_range_radix[buf[0]];
|
||||||
|
++buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Noise measurement: we reached the end of a block, update
|
||||||
|
// our noise estimate
|
||||||
|
static void adaptive_range_end_of_block()
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_range_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned n = 0, i = 0;
|
||||||
|
|
||||||
|
// measure Nth percentile magnitude
|
||||||
|
unsigned count_n = adaptive_range_radix_counter * Modes.adaptive_range_percentile / 100;
|
||||||
|
while (i < 65536 && n <= count_n)
|
||||||
|
n += adaptive_range_radix[i++];
|
||||||
|
uint16_t percentile_n = i - 1;
|
||||||
|
|
||||||
|
// maintain an EMA of the Nth percentile
|
||||||
|
adaptive_range_smoothed = adaptive_range_smoothed * (1 - Modes.adaptive_range_alpha) + percentile_n * Modes.adaptive_range_alpha;
|
||||||
|
// .. report to stats in dBFS
|
||||||
|
if (adaptive_range_smoothed > 0) {
|
||||||
|
Modes.stats_current.adaptive_noise_dbfs = 20 * log10(adaptive_range_smoothed / 65536.0);
|
||||||
|
} else {
|
||||||
|
Modes.stats_current.adaptive_noise_dbfs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// reset radix sort for the next block
|
||||||
|
memset(adaptive_range_radix, 0, 65536 * sizeof(unsigned));
|
||||||
|
adaptive_range_radix_counter = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Burst measurement: we reached the end of a block, update our burst rate estimate
|
||||||
|
static void adaptive_burst_end_of_block()
|
||||||
|
{
|
||||||
|
if (!Modes.adaptive_burst_control)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// scale rates based on the actual duty cycle fraction
|
||||||
|
// (e.g. if we are only inspecting 2/5 of samples, then scale the rate by 5/2)
|
||||||
|
double scale = (double)adaptive_subblock_dutycycle_D / adaptive_subblock_dutycycle_N;
|
||||||
|
|
||||||
|
// maintain an EMA of the number of undecoded loud bursts seen per block
|
||||||
|
Modes.stats_current.adaptive_loud_undecoded += adaptive_burst_block_loud_undecoded;
|
||||||
|
adaptive_burst_loud_undecoded_smoothed = adaptive_burst_loud_undecoded_smoothed * (1 - Modes.adaptive_burst_alpha) + scale * adaptive_burst_block_loud_undecoded * Modes.adaptive_burst_alpha;
|
||||||
|
adaptive_burst_block_loud_undecoded = 0;
|
||||||
|
|
||||||
|
// maintain an EMA of the number of decoded, but loud, messages seen per block
|
||||||
|
Modes.stats_current.adaptive_loud_decoded += adaptive_burst_block_loud_decoded;
|
||||||
|
adaptive_burst_loud_decoded_smoothed = adaptive_burst_loud_decoded_smoothed * (1 - Modes.adaptive_burst_alpha) + scale * adaptive_burst_block_loud_decoded * Modes.adaptive_burst_alpha;
|
||||||
|
adaptive_burst_block_loud_decoded = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void flush_stats(uint64_t now);
|
||||||
|
|
||||||
|
static void adaptive_increase_gain(const char *why)
|
||||||
|
{
|
||||||
|
if (adaptive_set_gain(sdrGetGain() + 1, why))
|
||||||
|
adaptive_gain_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adaptive_decrease_gain(const char *why)
|
||||||
|
{
|
||||||
|
if (adaptive_set_gain(sdrGetGain() - 1, why))
|
||||||
|
adaptive_gain_changed();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adaptive gain: we reached a block boundary. Update measurements and act on them.
|
||||||
|
static void adaptive_end_of_block()
|
||||||
|
{
|
||||||
|
adaptive_range_end_of_block();
|
||||||
|
adaptive_burst_end_of_block();
|
||||||
|
|
||||||
|
adaptive_control_update();
|
||||||
|
|
||||||
|
Modes.stats_current.adaptive_valid = true;
|
||||||
|
unsigned current = Modes.stats_current.adaptive_gain = sdrGetGain();
|
||||||
|
Modes.stats_current.adaptive_range_gain_limit = adaptive_range_gain_limit;
|
||||||
|
++Modes.stats_current.adaptive_gain_seconds[current < STATS_GAIN_COUNT ? current : STATS_GAIN_COUNT-1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static void adaptive_control_update()
|
||||||
|
{
|
||||||
|
// votes for what to do with the gain
|
||||||
|
// "gain_not_up" overlaps somewhat with "gain_down", but they are not identical;
|
||||||
|
// burst control may want to prevent gain from increasing, but not necessarily
|
||||||
|
// decrease gain.
|
||||||
|
|
||||||
|
bool gain_up = false;
|
||||||
|
const char *gain_up_reason = NULL;
|
||||||
|
bool gain_down = false;
|
||||||
|
const char *gain_down_reason = NULL;
|
||||||
|
bool gain_not_up = false;
|
||||||
|
|
||||||
|
int current_gain = sdrGetGain();
|
||||||
|
|
||||||
|
if (adaptive_burst_change_timer)
|
||||||
|
--adaptive_burst_change_timer;
|
||||||
|
if (adaptive_range_change_timer > 0)
|
||||||
|
--adaptive_range_change_timer;
|
||||||
|
if (adaptive_range_rescan_timer > 0)
|
||||||
|
--adaptive_range_rescan_timer;
|
||||||
|
|
||||||
|
if (Modes.adaptive_burst_control && !adaptive_burst_change_timer) {
|
||||||
|
if (adaptive_burst_loud_undecoded_smoothed > Modes.adaptive_burst_loud_rate) {
|
||||||
|
adaptive_burst_quiet_blocks = 0;
|
||||||
|
++adaptive_burst_loud_blocks;
|
||||||
|
} else if (adaptive_burst_loud_decoded_smoothed < Modes.adaptive_burst_quiet_rate) {
|
||||||
|
adaptive_burst_loud_blocks = 0;
|
||||||
|
++adaptive_burst_quiet_blocks;
|
||||||
|
} else {
|
||||||
|
adaptive_burst_loud_blocks = 0;
|
||||||
|
adaptive_burst_quiet_blocks = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adaptive_burst_loud_blocks >= Modes.adaptive_burst_loud_runlength) {
|
||||||
|
// we need to reduce gain (further)
|
||||||
|
gain_down = gain_not_up = true;
|
||||||
|
gain_down_reason = "high rate of loud undecoded messages";
|
||||||
|
|
||||||
|
// if we're currently doing a downward scan, reducing gain further may confuse it;
|
||||||
|
// stop that scan and restart it once we are no longer in a reduced-gain state
|
||||||
|
if (adaptive_range_state == RANGE_SCAN_DOWN || adaptive_range_state == RANGE_RESCAN_DOWN) {
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = 0;
|
||||||
|
}
|
||||||
|
} else if (adaptive_burst_quiet_blocks < Modes.adaptive_burst_quiet_runlength) {
|
||||||
|
// we're OK at the current gain, but should not increase it
|
||||||
|
gain_not_up = true;
|
||||||
|
} else if (current_gain < adaptive_range_gain_limit) {
|
||||||
|
// we're OK at the current gain, and can increase gain to the previously discovered
|
||||||
|
// dynamic range limit
|
||||||
|
gain_up = true;
|
||||||
|
gain_up_reason = "low loud message rate and gain below dynamic range limit";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Modes.adaptive_range_control && !adaptive_range_change_timer) {
|
||||||
|
float available_range = -20 * log10(adaptive_range_smoothed / 65536.0);
|
||||||
|
// allow the gain limit to increase if this gain setting is acceptable
|
||||||
|
// (decreasing the limit is done separately depending on the current state as we make slightly different decisions in IDLE
|
||||||
|
// to provide hysteresis)
|
||||||
|
if (available_range >= Modes.adaptive_range_target && current_gain > adaptive_range_gain_limit) {
|
||||||
|
adaptive_range_gain_limit = current_gain;
|
||||||
|
}
|
||||||
|
switch (adaptive_range_state) {
|
||||||
|
case RANGE_SCAN_UP:
|
||||||
|
case RANGE_RESCAN_UP:
|
||||||
|
if (available_range < Modes.adaptive_range_target) {
|
||||||
|
// Current gain fails to meet our target. Switch to downward scanning.
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), switching to downward scan\n", available_range, Modes.adaptive_range_target);
|
||||||
|
gain_down = gain_not_up = true;
|
||||||
|
gain_down_reason = "probing dynamic range gain lower bound";
|
||||||
|
adaptive_range_state = (adaptive_range_state == RANGE_RESCAN_UP ? RANGE_RESCAN_DOWN : RANGE_SCAN_DOWN);
|
||||||
|
if (adaptive_range_gain_limit >= current_gain) {
|
||||||
|
adaptive_range_gain_limit = current_gain - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdrGetGain() >= adaptive_gain_max) {
|
||||||
|
// We have reached our upper gain limit
|
||||||
|
fprintf(stderr, "adaptive: reached upper gain limit, halting dynamic range scan here\n");
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gain step is OK and we have more to try, try the next gain step up.
|
||||||
|
// (But if burst detection has inhibited increasing gain, don't do anything yet, just try again next block)
|
||||||
|
if (!gain_not_up) {
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), continuing upward scan\n", available_range, Modes.adaptive_range_target);
|
||||||
|
gain_up = true;
|
||||||
|
gain_up_reason = "probing dynamic range gain upper bound";
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RANGE_SCAN_DOWN:
|
||||||
|
case RANGE_RESCAN_DOWN:
|
||||||
|
if (available_range >= Modes.adaptive_range_target) {
|
||||||
|
// Current gain meets our target; we are done with the scan.
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) >= required dynamic range (%.1fdB), stopping downwards scan here\n", available_range, Modes.adaptive_range_target);
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = (adaptive_range_state == RANGE_SCAN_DOWN ? Modes.adaptive_range_scan_delay : Modes.adaptive_range_rescan_delay);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (adaptive_range_gain_limit >= current_gain) {
|
||||||
|
adaptive_range_gain_limit = current_gain - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sdrGetGain() <= adaptive_gain_min) {
|
||||||
|
fprintf(stderr, "adaptive: reached lower gain limit, halting dynamic range scan here\n");
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This gain step is too loud and we have more to try, try the next gain step down
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) < required dynamic range (%.1fdB), continuing downwards scan\n", available_range, Modes.adaptive_range_target);
|
||||||
|
gain_down = gain_not_up = true;
|
||||||
|
gain_down_reason = "probing dynamic range gain lower bound";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RANGE_SCAN_IDLE:
|
||||||
|
// Look for increased noise that could be compensated for by decreasing gain.
|
||||||
|
// Do this even if we're waiting to rescan or if burst control is also active
|
||||||
|
if (available_range + adaptive_gain_down_db / 2 < Modes.adaptive_range_target && sdrGetGain() > adaptive_gain_min) {
|
||||||
|
fprintf(stderr, "adaptive: available dynamic range (%.1fdB) + half gain step down (%.1fdB) < required dynamic range (%.1fdB), starting downward scan\n",
|
||||||
|
available_range, Modes.adaptive_range_target, adaptive_gain_down_db);
|
||||||
|
if (adaptive_range_gain_limit >= current_gain) {
|
||||||
|
adaptive_range_gain_limit = current_gain - 1;
|
||||||
|
}
|
||||||
|
adaptive_range_state = RANGE_SCAN_DOWN;
|
||||||
|
gain_down = gain_not_up = true;
|
||||||
|
gain_down_reason = "dynamic range fell below target value";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Infrequently consider increasing gain to handle the case where we've selected a too-low gain where the noise floor is dominated by noise unrelated to the gain setting.
|
||||||
|
// But don't do this while burst control is preventing gain increases.
|
||||||
|
if (!adaptive_range_rescan_timer && !gain_not_up) {
|
||||||
|
if (available_range >= Modes.adaptive_range_target && sdrGetGain() < adaptive_gain_max) {
|
||||||
|
fprintf(stderr, "adaptive: start periodic scan for acceptable dynamic range at increased gain\n");
|
||||||
|
gain_up = true;
|
||||||
|
gain_up_reason = "periodic re-probing of dynamic range gain upper bound";
|
||||||
|
adaptive_range_state = RANGE_RESCAN_UP;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing to do for a while.
|
||||||
|
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "adaptive: in a weird state (%d), trying to fix it\n", adaptive_range_state);
|
||||||
|
adaptive_range_state = RANGE_SCAN_IDLE;
|
||||||
|
adaptive_range_rescan_timer = Modes.adaptive_range_rescan_delay;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now actually perform any gain changes
|
||||||
|
|
||||||
|
if (gain_down)
|
||||||
|
adaptive_decrease_gain(gain_down_reason);
|
||||||
|
else if (gain_up && !gain_not_up)
|
||||||
|
adaptive_increase_gain(gain_up_reason);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,30 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// adaptive.h: adaptive gain control prototypes
|
||||||
|
//
|
||||||
|
// Copyright (c) 2021 FlightAware, LLC
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef ADAPTIVE_H
|
||||||
|
#define ADAPTIVE_H
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
struct modesMessage;
|
||||||
|
|
||||||
|
void adaptive_init();
|
||||||
|
void adaptive_update(uint16_t *buf, unsigned length, struct modesMessage *decoded);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
#include "ais_charset.h"
|
||||||
|
|
||||||
|
char ais_charset[64] = "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_ !\"#$%&'()*+,-./0123456789:;<=>?";
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef AIS_CHARSET_H
|
||||||
|
#define AIS_CHARSET_H
|
||||||
|
|
||||||
|
extern char ais_charset[64];
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,985 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// comm_b.c: Comm-B message decoding
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017 FlightAware, LLC
|
||||||
|
// Copyright (c) 2017 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#include "dump1090.h"
|
||||||
|
#include "ais_charset.h"
|
||||||
|
|
||||||
|
typedef int (*CommBDecoderFn)(struct modesMessage *,bool);
|
||||||
|
|
||||||
|
static int decodeEmptyResponse(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS10(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS17(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS20(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS30(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS40(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS44(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS50(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS60(struct modesMessage *mm, bool store);
|
||||||
|
static int decodeBDS05(struct modesMessage *mm, bool store);
|
||||||
|
|
||||||
|
static CommBDecoderFn comm_b_decoders[] = {
|
||||||
|
&decodeEmptyResponse,
|
||||||
|
&decodeBDS10,
|
||||||
|
&decodeBDS20,
|
||||||
|
&decodeBDS30,
|
||||||
|
&decodeBDS17,
|
||||||
|
&decodeBDS40,
|
||||||
|
&decodeBDS50,
|
||||||
|
&decodeBDS60,
|
||||||
|
&decodeBDS44,
|
||||||
|
&decodeBDS05
|
||||||
|
};
|
||||||
|
|
||||||
|
void decodeCommB(struct modesMessage *mm)
|
||||||
|
{
|
||||||
|
// If DR or UM are set, this message is _probably_ noise
|
||||||
|
// as nothing really seems to use the multisite broadcast stuff?
|
||||||
|
// Also skip anything that had errors corrected
|
||||||
|
if (mm->DR != 0 || mm->UM != 0 || mm->correctedbits > 0) {
|
||||||
|
mm->commb_format = COMMB_NOT_DECODED;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a bit hairy as we don't know what the requested register was
|
||||||
|
int bestScore = 0;
|
||||||
|
CommBDecoderFn bestDecoder = NULL;
|
||||||
|
int ambiguous = 0;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < (sizeof(comm_b_decoders) / sizeof(comm_b_decoders[0])); ++i) {
|
||||||
|
int score = comm_b_decoders[i](mm, false);
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestDecoder = comm_b_decoders[i];
|
||||||
|
ambiguous = 0;
|
||||||
|
} else if (score == bestScore) {
|
||||||
|
ambiguous = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestDecoder) {
|
||||||
|
if (ambiguous) {
|
||||||
|
mm->commb_format = COMMB_AMBIGUOUS;
|
||||||
|
} else {
|
||||||
|
// decode it
|
||||||
|
bestDecoder(mm, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mm->commb_format = COMMB_UNKNOWN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int decodeEmptyResponse(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
// 00000000000000 is a common response. Ignore it.
|
||||||
|
//
|
||||||
|
// Also, it's common to see responses that look like this:
|
||||||
|
// 40000000000000
|
||||||
|
// 50000000000000
|
||||||
|
// 60000000000000
|
||||||
|
// typically in grouped bursts (one of each message) from
|
||||||
|
// the same aircraft.
|
||||||
|
//
|
||||||
|
// I speculate that these are response to interrogations for
|
||||||
|
// BDS 4,0 5,0 and 6,0 respectively where the transponder
|
||||||
|
// doesn't support the register or has no data loaded for it.
|
||||||
|
// Treat them like empty responses.
|
||||||
|
|
||||||
|
switch (mm->MB[0]) {
|
||||||
|
case 0x00:
|
||||||
|
case 0x40:
|
||||||
|
case 0x50:
|
||||||
|
case 0x60:
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned i = 1; i < 7; ++i) {
|
||||||
|
if (mm->MB[i] != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_EMPTY_RESPONSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS1,0 Datalink capabilities
|
||||||
|
static int decodeBDS10(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
// BDS identifier
|
||||||
|
if (msg[0] != 0x10) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reserved bits
|
||||||
|
if (getbits(msg, 10, 14) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks plausible.
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_DATALINK_CAPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS1,7 Common usage GICB capability report
|
||||||
|
static int decodeBDS17(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
// reserved bits
|
||||||
|
if (getbits(msg, 25, 56) != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
if (getbit(msg, 7)) {
|
||||||
|
score += 1; // 2,0 aircraft identification
|
||||||
|
} else {
|
||||||
|
// BDS2,0 is on almost everything
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// unlikely bits
|
||||||
|
if (getbit(msg, 10)) { // 4,1 next waypoint identifier
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 11)) { // 4,2 next waypoint position
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 12)) { // 4,3 next waypoint information
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 13)) { // 4,4 meterological routine report
|
||||||
|
score -= 1;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 14)) { // 4,4 meterological hazard report
|
||||||
|
score -= 1;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 20)) { // 5,4 waypoint 1
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 21)) { // 5,5 waypoint 2
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
if (getbit(msg, 22)) { // 5,6 waypoint 3
|
||||||
|
score -= 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getbit(msg, 1) && getbit(msg, 2) && getbit(msg, 3) && getbit(msg, 4) && getbit(msg, 5)) {
|
||||||
|
// looks like ES capable
|
||||||
|
score += 5;
|
||||||
|
if (getbit(msg, 6)) {
|
||||||
|
// ES EDI
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
} else if (!getbit(msg, 1) && !getbit(msg, 2) && !getbit(msg, 3) && !getbit(msg, 4) && !getbit(msg, 5) && !getbit(msg, 6)) {
|
||||||
|
// not ES capable
|
||||||
|
score += 1;
|
||||||
|
} else if (!getbit(msg, 1) && !getbit(msg, 2) && getbit(msg, 3) && getbit(msg, 4) && getbit(msg, 5)) {
|
||||||
|
// ES with no position data
|
||||||
|
score += 3;
|
||||||
|
} else {
|
||||||
|
// other combinations, unlikely
|
||||||
|
score -= 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getbit(msg, 16) && getbit(msg, 24)) {
|
||||||
|
// track/turn, heading/speed
|
||||||
|
score += 2;
|
||||||
|
if (getbit(msg, 9)) {
|
||||||
|
// vertical intent
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
} else if (!getbit(msg, 16) && !getbit(msg, 24) && !getbit(msg, 9)) {
|
||||||
|
// neither
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
// unlikely
|
||||||
|
score -= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_GICB_CAPS;
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS2,0 Aircraft identification
|
||||||
|
static int decodeBDS20(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
char callsign[9];
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
// BDS identifier
|
||||||
|
if (msg[0] != 0x20) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
callsign[0] = ais_charset[getbits(msg, 9, 14)];
|
||||||
|
callsign[1] = ais_charset[getbits(msg, 15, 20)];
|
||||||
|
callsign[2] = ais_charset[getbits(msg, 21, 26)];
|
||||||
|
callsign[3] = ais_charset[getbits(msg, 27, 32)];
|
||||||
|
callsign[4] = ais_charset[getbits(msg, 33, 38)];
|
||||||
|
callsign[5] = ais_charset[getbits(msg, 39, 44)];
|
||||||
|
callsign[6] = ais_charset[getbits(msg, 45, 50)];
|
||||||
|
callsign[7] = ais_charset[getbits(msg, 51, 56)];
|
||||||
|
callsign[8] = 0;
|
||||||
|
|
||||||
|
// score based on number of valid characters
|
||||||
|
int score = 8;
|
||||||
|
int valid = 1;
|
||||||
|
for (unsigned i = 0; i < 8; ++i) {
|
||||||
|
if ((callsign[i] >= 'A' && callsign[i] <= 'Z') || (callsign[i] >= '0' && callsign[i] <= '9') || callsign[i] == ' ') {
|
||||||
|
score += 6;
|
||||||
|
} else if (callsign[i] == '@') {
|
||||||
|
// Padding (sometimes we get @@@@@@@@, i.e. BDS2,0 with all zeros - we do want to accept this as a BDS2,0 but not actually use the callsign)
|
||||||
|
valid = 0;
|
||||||
|
} else {
|
||||||
|
// Invalid
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_AIRCRAFT_IDENT;
|
||||||
|
if (valid) {
|
||||||
|
memcpy(mm->callsign, callsign, sizeof(mm->callsign));
|
||||||
|
mm->callsign_valid = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS3,0 ACAS RA
|
||||||
|
static int decodeBDS30(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
// BDS identifier
|
||||||
|
if (msg[0] != 0x30) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_ACAS_RA;
|
||||||
|
}
|
||||||
|
|
||||||
|
// just accept it.
|
||||||
|
return 56;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS4,0 Selected vertical intention
|
||||||
|
static int decodeBDS40(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned mcp_valid = getbit(msg, 1);
|
||||||
|
unsigned mcp_raw = getbits(msg, 2, 13);
|
||||||
|
unsigned fms_valid = getbit(msg, 14);
|
||||||
|
unsigned fms_raw = getbits(msg, 15, 26);
|
||||||
|
unsigned baro_valid = getbit(msg, 27);
|
||||||
|
unsigned baro_raw = getbits(msg, 28, 39);
|
||||||
|
unsigned reserved_1 = getbits(msg, 40, 47);
|
||||||
|
unsigned mode_valid = getbit(msg, 48);
|
||||||
|
unsigned mode_raw = getbits(msg, 49, 51);
|
||||||
|
unsigned reserved_2 = getbits(msg, 52, 53);
|
||||||
|
unsigned source_valid = getbit(msg, 54);
|
||||||
|
unsigned source_raw = getbits(msg, 55, 56);
|
||||||
|
|
||||||
|
if (!mcp_valid && !fms_valid && !baro_valid && !mode_valid && !source_valid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
unsigned mcp_alt = 0;
|
||||||
|
if (mcp_valid && mcp_raw != 0) {
|
||||||
|
mcp_alt = mcp_raw * 16;
|
||||||
|
if (mcp_alt >= 1000 && mcp_alt <= 50000) {
|
||||||
|
score += 13;
|
||||||
|
} else {
|
||||||
|
// unlikely altitude
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!mcp_valid && mcp_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned fms_alt = 0;
|
||||||
|
if (fms_valid && fms_raw != 0) {
|
||||||
|
fms_alt = fms_raw * 16;
|
||||||
|
if (fms_alt >= 1000 && fms_alt <= 50000) {
|
||||||
|
score += 13;
|
||||||
|
} else {
|
||||||
|
// unlikely altitude
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!fms_valid && fms_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float baro_setting = 0;
|
||||||
|
if (baro_valid && baro_raw != 0) {
|
||||||
|
baro_setting = 800 + baro_raw * 0.1;
|
||||||
|
if (baro_setting >= 900 && baro_setting <= 1100) {
|
||||||
|
score += 13;
|
||||||
|
} else {
|
||||||
|
// unlikely pressure setting
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!baro_valid && baro_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reserved_1 != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode_valid) {
|
||||||
|
score += 4;
|
||||||
|
} else if (!mode_valid && mode_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (reserved_2 != 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source_valid) {
|
||||||
|
score += 3;
|
||||||
|
} else if (!source_valid && source_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// small penalty for inconsistent data
|
||||||
|
if (mcp_valid && fms_valid && mcp_alt != fms_alt) {
|
||||||
|
score -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mcp_valid) {
|
||||||
|
unsigned remainder = mcp_alt % 500;
|
||||||
|
if (!(remainder < 16 || remainder > 484)) {
|
||||||
|
// mcp altitude is not a multiple of 500
|
||||||
|
score -= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fms_valid) {
|
||||||
|
unsigned remainder = fms_alt % 500;
|
||||||
|
if (!(remainder < 16 || remainder > 484)) {
|
||||||
|
// fms altitude is not a multiple of 500
|
||||||
|
score -= 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_VERTICAL_INTENT;
|
||||||
|
|
||||||
|
if (mcp_valid) {
|
||||||
|
mm->nav.mcp_altitude_valid = 1;
|
||||||
|
mm->nav.mcp_altitude = mcp_alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fms_valid) {
|
||||||
|
mm->nav.fms_altitude_valid = 1;
|
||||||
|
mm->nav.fms_altitude = fms_alt;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baro_valid) {
|
||||||
|
mm->nav.qnh_valid = 1;
|
||||||
|
mm->nav.qnh = baro_setting;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mode_valid) {
|
||||||
|
mm->nav.modes_valid = 1;
|
||||||
|
mm->nav.modes =
|
||||||
|
((mode_raw & 4) ? NAV_MODE_VNAV : 0) |
|
||||||
|
((mode_raw & 2) ? NAV_MODE_ALT_HOLD : 0) |
|
||||||
|
((mode_raw & 1) ? NAV_MODE_APPROACH : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source_valid) {
|
||||||
|
switch (source_raw) {
|
||||||
|
case 0:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_UNKNOWN;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_AIRCRAFT;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_MCP;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_FMS;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
mm->nav.altitude_source = NAV_ALT_INVALID;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
mm->nav.altitude_source = NAV_ALT_INVALID;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS5,0 Track and turn report
|
||||||
|
static int decodeBDS50(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned roll_valid = getbit(msg, 1);
|
||||||
|
unsigned roll_sign = getbit(msg, 2);
|
||||||
|
unsigned roll_raw = getbits(msg, 3, 11);
|
||||||
|
|
||||||
|
unsigned track_valid = getbit(msg, 12);
|
||||||
|
unsigned track_sign = getbit(msg, 13);
|
||||||
|
unsigned track_raw = getbits(msg, 14, 23);
|
||||||
|
|
||||||
|
unsigned gs_valid = getbit(msg, 24);
|
||||||
|
unsigned gs_raw = getbits(msg, 25, 34);
|
||||||
|
|
||||||
|
unsigned track_rate_valid = getbit(msg, 35);
|
||||||
|
unsigned track_rate_sign = getbit(msg, 36);
|
||||||
|
unsigned track_rate_raw = getbits(msg, 37, 45);
|
||||||
|
|
||||||
|
unsigned tas_valid = getbit(msg, 46);
|
||||||
|
unsigned tas_raw = getbits(msg, 47, 56);
|
||||||
|
|
||||||
|
if (!roll_valid || !track_valid || !gs_valid || !tas_valid) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
float roll = 0;
|
||||||
|
if (roll_valid) {
|
||||||
|
roll = roll_raw * 45.0 / 256.0;
|
||||||
|
if (roll_sign) {
|
||||||
|
roll -= 90.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (roll >= -40 && roll < 40) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!roll_valid && roll_raw == 0 && !roll_sign) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float track = 0;
|
||||||
|
if (track_valid) {
|
||||||
|
score += 12;
|
||||||
|
track = track_raw * 90.0 / 512.0;
|
||||||
|
if (track_sign) {
|
||||||
|
track += 180.0;
|
||||||
|
}
|
||||||
|
} else if (!track_valid && track_raw == 0 && !track_sign) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned gs = 0;
|
||||||
|
if (gs_valid && gs_raw != 0) {
|
||||||
|
gs = gs_raw * 2;
|
||||||
|
|
||||||
|
if (gs >= 50 && gs <= 700) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!gs_valid && gs_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float track_rate = 0;
|
||||||
|
if (track_rate_valid) {
|
||||||
|
track_rate = track_rate_raw * 8.0 / 256.0;
|
||||||
|
if (track_rate_sign) {
|
||||||
|
track_rate -= 16;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track_rate >= -10.0 && track_rate <= 10.0) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!track_rate_valid && track_rate_raw == 0 && !track_rate_sign) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned tas = 0;
|
||||||
|
if (tas_valid && tas_raw != 0) {
|
||||||
|
tas = tas_raw * 2;
|
||||||
|
|
||||||
|
if (tas >= 50 && tas <= 700) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!tas_valid && tas_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// small penalty for inconsistent data
|
||||||
|
if (gs_valid && tas_valid) {
|
||||||
|
int delta = abs((int)gs_valid - (int)tas_valid);
|
||||||
|
if (delta > 150) {
|
||||||
|
score -= 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// compute the theoretical turn rate and compare to track angle rate
|
||||||
|
if (roll_valid && tas_valid && tas > 0 && track_rate_valid) {
|
||||||
|
double turn_rate = 68625 * tan(roll * M_PI / 180.0) / (tas * 20 * M_PI);
|
||||||
|
double delta = fabs(turn_rate - track_rate);
|
||||||
|
if (delta > 2.0) {
|
||||||
|
score -= 6;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_TRACK_TURN;
|
||||||
|
|
||||||
|
if (roll_valid) {
|
||||||
|
mm->roll_valid = 1;
|
||||||
|
mm->roll = roll;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track_valid) {
|
||||||
|
mm->heading_valid = 1;
|
||||||
|
mm->heading = track;
|
||||||
|
mm->heading_type = HEADING_GROUND_TRACK;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gs_valid) {
|
||||||
|
mm->gs_valid = 1;
|
||||||
|
mm->gs.v0 = mm->gs.v2 = mm->gs.selected = gs;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (track_rate_valid) {
|
||||||
|
mm->track_rate_valid = 1;
|
||||||
|
mm->track_rate = track_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tas_valid) {
|
||||||
|
mm->tas_valid = 1;
|
||||||
|
mm->tas = tas;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS6,0 Heading and speed report
|
||||||
|
static int decodeBDS60(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned heading_valid = getbit(msg, 1);
|
||||||
|
unsigned heading_sign = getbit(msg, 2);
|
||||||
|
unsigned heading_raw = getbits(msg, 3, 12);
|
||||||
|
|
||||||
|
unsigned ias_valid = getbit(msg, 13);
|
||||||
|
unsigned ias_raw = getbits(msg, 14, 23);
|
||||||
|
|
||||||
|
unsigned mach_valid = getbit(msg, 24);
|
||||||
|
unsigned mach_raw = getbits(msg, 25, 34);
|
||||||
|
|
||||||
|
unsigned baro_rate_valid = getbit(msg, 35);
|
||||||
|
unsigned baro_rate_sign = getbit(msg, 36);
|
||||||
|
unsigned baro_rate_raw = getbits(msg, 37, 45);
|
||||||
|
|
||||||
|
unsigned inertial_rate_valid = getbit(msg, 46);
|
||||||
|
unsigned inertial_rate_sign = getbit(msg, 47);
|
||||||
|
unsigned inertial_rate_raw = getbits(msg, 48, 56);
|
||||||
|
|
||||||
|
if (!heading_valid || !ias_valid || !mach_valid || (!baro_rate_valid && !inertial_rate_valid)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
float heading = 0;
|
||||||
|
if (heading_valid) {
|
||||||
|
heading = heading_raw * 90.0 / 512.0;
|
||||||
|
if (heading_sign) {
|
||||||
|
heading += 180.0;
|
||||||
|
}
|
||||||
|
score += 12;
|
||||||
|
} else if (!heading_valid && heading_raw == 0 && !heading_sign) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned ias = 0;
|
||||||
|
if (ias_valid && ias_raw != 0) {
|
||||||
|
ias = ias_raw;
|
||||||
|
if (ias >= 50 && ias <= 700) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!ias_valid && ias_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
float mach = 0;
|
||||||
|
if (mach_valid && mach_raw != 0) {
|
||||||
|
mach = mach_raw * 2.048 / 512;
|
||||||
|
if (mach >= 0.1 && mach <= 0.9) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!mach_valid && mach_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int baro_rate = 0;
|
||||||
|
if (baro_rate_valid) {
|
||||||
|
baro_rate = baro_rate_raw * 32;
|
||||||
|
if (baro_rate_sign) {
|
||||||
|
baro_rate -= 16384;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baro_rate >= -6000 && baro_rate <= 6000) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!baro_rate_valid && baro_rate_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int inertial_rate = 0;
|
||||||
|
if (inertial_rate_valid) {
|
||||||
|
inertial_rate = inertial_rate_raw * 32;
|
||||||
|
if (inertial_rate_sign) {
|
||||||
|
inertial_rate -= 16384;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inertial_rate >= -6000 && inertial_rate <= 6000) {
|
||||||
|
score += 11;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else if (!inertial_rate_valid && inertial_rate_raw == 0) {
|
||||||
|
score += 1;
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// small penalty for inconsistent data
|
||||||
|
|
||||||
|
// Should check IAS vs Mach at given altitude, but the maths is a little involved
|
||||||
|
|
||||||
|
if (baro_rate_valid && inertial_rate_valid) {
|
||||||
|
int delta = abs(baro_rate - inertial_rate);
|
||||||
|
if (delta > 2000) {
|
||||||
|
score -= 12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_HEADING_SPEED;
|
||||||
|
|
||||||
|
if (heading_valid) {
|
||||||
|
mm->heading_valid = 1;
|
||||||
|
mm->heading = heading;
|
||||||
|
mm->heading_type = HEADING_MAGNETIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ias_valid) {
|
||||||
|
mm->ias_valid = 1;
|
||||||
|
mm->ias = ias;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mach_valid) {
|
||||||
|
mm->mach_valid = 1;
|
||||||
|
mm->mach = mach;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baro_rate_valid) {
|
||||||
|
mm->baro_rate_valid = 1;
|
||||||
|
mm->baro_rate = baro_rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inertial_rate_valid) {
|
||||||
|
// INS-derived data is treated as a "geometric rate" / "geometric altitude"
|
||||||
|
// elsewhere, so do the same here.
|
||||||
|
mm->geom_rate_valid = 1;
|
||||||
|
mm->geom_rate = inertial_rate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS4,4 Meterological routine air report
|
||||||
|
static int decodeBDS44(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned source = getbits(msg, 1, 4);
|
||||||
|
|
||||||
|
unsigned wind_valid = getbit(msg, 5);
|
||||||
|
unsigned windspeed_raw = getbits(msg, 6, 14);
|
||||||
|
unsigned winddir_raw = getbits(msg, 15, 23);
|
||||||
|
|
||||||
|
// ICAO 9871 is inconsistent, it claims:
|
||||||
|
// bit 24 sign
|
||||||
|
// bits 25..34 static air temperature, MSB = 64C, LSB=0.25C, range -128C..+128C
|
||||||
|
//
|
||||||
|
// .. but this does not actually work, there is one too many bits in the bitfield
|
||||||
|
// for the claimed values.
|
||||||
|
//
|
||||||
|
// Based on observed data, the most plausible actual layout is:
|
||||||
|
//
|
||||||
|
// bit 24 status
|
||||||
|
// bit 25 sign
|
||||||
|
// bits 26..34 static air temperature, MSB=64C, LSB=0.25C, range -128C..+128C
|
||||||
|
|
||||||
|
unsigned sat_valid = getbit(msg, 24);
|
||||||
|
unsigned sat_sign = getbit(msg, 25);
|
||||||
|
unsigned sat_raw = getbits(msg, 26, 34);
|
||||||
|
|
||||||
|
unsigned asp_valid = getbit(msg, 35);
|
||||||
|
unsigned asp_raw = getbits(msg, 36, 46);
|
||||||
|
|
||||||
|
unsigned turbulence_valid = getbit(msg, 47);
|
||||||
|
unsigned turbulence_raw = getbits(msg, 48, 49);
|
||||||
|
|
||||||
|
unsigned humidity_valid = getbit(msg, 50);
|
||||||
|
unsigned humidity_raw = getbits(msg, 51, 56);
|
||||||
|
|
||||||
|
if (source == MRAR_SOURCE_INVALID || source >= MRAR_SOURCE_RESERVED)
|
||||||
|
return 0; // invalid or reserved source
|
||||||
|
|
||||||
|
if (!wind_valid || !sat_valid)
|
||||||
|
return 0; // all valid messages seen in the wild have at least temp + wind
|
||||||
|
|
||||||
|
if (!asp_valid && asp_raw != 0)
|
||||||
|
return 0; // ASP not valid, but non-zero values in the ASP field
|
||||||
|
|
||||||
|
if (!turbulence_valid && turbulence_raw != 0)
|
||||||
|
return 0; // turbulence not valid, but non-zero values in the turbulence field
|
||||||
|
|
||||||
|
if (!humidity_valid && humidity_raw != 0)
|
||||||
|
return 0; // humidity not valid, but non-zero values in the humidity field
|
||||||
|
|
||||||
|
int score = 0;
|
||||||
|
|
||||||
|
float wind_speed = 0;
|
||||||
|
float wind_dir = 0;
|
||||||
|
if (wind_valid) {
|
||||||
|
wind_dir = winddir_raw * (180.0 / 256.0);
|
||||||
|
wind_speed = windspeed_raw;
|
||||||
|
|
||||||
|
if (windspeed_raw == 0) // possible but uncommon
|
||||||
|
score += 2;
|
||||||
|
else if (wind_speed <= 250)
|
||||||
|
score += 19;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float sat = 0;
|
||||||
|
if (sat_valid) {
|
||||||
|
sat = sat_raw * 0.25;
|
||||||
|
if (sat_sign)
|
||||||
|
sat -= 128;
|
||||||
|
if (sat == 0) // possible but uncommon
|
||||||
|
score += 2;
|
||||||
|
else if (sat >= -80 && sat <= 60)
|
||||||
|
score += 11;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float asp = 0;
|
||||||
|
if (asp_valid) {
|
||||||
|
asp = asp_raw;
|
||||||
|
if (asp >= 25 && asp <= 1100)
|
||||||
|
score += 12;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
hazard_t turbulence = HAZARD_NIL;
|
||||||
|
if (turbulence_valid) {
|
||||||
|
turbulence = (hazard_t) turbulence_raw;
|
||||||
|
score += 3;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
float humidity = 0;
|
||||||
|
if (humidity_valid) {
|
||||||
|
humidity = humidity_raw * (100.0 / 64.0);
|
||||||
|
score += 7;
|
||||||
|
} else {
|
||||||
|
score += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (source == MRAR_SOURCE_DMEDME && wind_valid && sat_valid && score > 0) {
|
||||||
|
// Some GICB messages can be easily mistaken for a MRAR:
|
||||||
|
//
|
||||||
|
// GICB bit 1: BDS 0,5 ES airborne position = 0 ]
|
||||||
|
// GICB bit 2: BDS 0,6 ES surface position = 0 ]
|
||||||
|
// GICB bit 3: BDS 0,7 ES status = 1 ]
|
||||||
|
// GICB bit 4: BDS 0,8 ES type & identification = 1 ] -> MRAR source = 3
|
||||||
|
// GICB bit 5: BDS 0,9 ES airborne velocity = 1 -> MRAR wind valid bit
|
||||||
|
// GICB bit 24: BDS 6,0 heading and speed report = 1 -> MRAR temp valid bit
|
||||||
|
// most trailing bits = 0
|
||||||
|
//
|
||||||
|
// so only treat this as MRAR as a last resort
|
||||||
|
score = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_MRAR;
|
||||||
|
mm->mrar_source_valid = 1;
|
||||||
|
mm->mrar_source = (mrar_source_t) source;
|
||||||
|
|
||||||
|
if (wind_valid) {
|
||||||
|
mm->wind_valid = 1;
|
||||||
|
mm->wind_speed = wind_speed;
|
||||||
|
mm->wind_dir = wind_dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sat_valid) {
|
||||||
|
mm->temperature_valid = 1;
|
||||||
|
mm->temperature = sat;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (asp_valid) {
|
||||||
|
mm->pressure_valid = 1;
|
||||||
|
mm->pressure = asp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (turbulence_valid) {
|
||||||
|
mm->turbulence_valid = 1;
|
||||||
|
mm->turbulence = turbulence;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (humidity_valid) {
|
||||||
|
mm->humidity_valid = 1;
|
||||||
|
mm->humidity = humidity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// BDS0,5 extended squitter airborne position
|
||||||
|
// (apparently this gets queried via comm-b sometimes??)
|
||||||
|
// We don't try to _use_ this as a position, but we can
|
||||||
|
// at least try to recognize it, to exclude other
|
||||||
|
// comm-b types (in particular they can be mistaken for MRAR)
|
||||||
|
static int decodeBDS05(struct modesMessage *mm, bool store)
|
||||||
|
{
|
||||||
|
// We recognize these by matching the position altitude against
|
||||||
|
// the altitude in the surrounding message, so we need a
|
||||||
|
// DF20 not a DF21
|
||||||
|
if (mm->msgtype != 20)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned char *msg = mm->MB;
|
||||||
|
|
||||||
|
unsigned typecode = getbits(msg, 1, 5);
|
||||||
|
if (typecode < 9 || typecode > 18)
|
||||||
|
return 0; // only consider typecodes that could be an airborne position with baro altitude
|
||||||
|
|
||||||
|
unsigned t_bit = getbit(msg, 21);
|
||||||
|
if (t_bit) // unlikely
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
unsigned ac12 = getbits(msg, 9, 20);
|
||||||
|
if (!ac12)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
// Insert M=0 to make an AC13 value, match against the
|
||||||
|
// AC13 value in the surrounding message
|
||||||
|
unsigned ac13 = ((ac12 & 0x0FC0) << 1) | (ac12 & 0x003F);
|
||||||
|
if (mm->AC != ac13)
|
||||||
|
return 0; // no altitude match
|
||||||
|
|
||||||
|
unsigned lat = getbits(msg, 23, 39);
|
||||||
|
unsigned lon = getbits(msg, 40, 56);
|
||||||
|
if (lat == 0 || lon == 0) // unlikely position
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (store) {
|
||||||
|
mm->commb_format = COMMB_AIRBORNE_POSITION;
|
||||||
|
// No further decoding done, we don't really trust this
|
||||||
|
// enough to use as real input to CPR
|
||||||
|
}
|
||||||
|
|
||||||
|
// Score this high enough to override everything else
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
// Part of dump1090, a Mode S message decoder for RTLSDR devices.
|
||||||
|
//
|
||||||
|
// comm_b.h: Comm-B message decoding (prototypes)
|
||||||
|
//
|
||||||
|
// Copyright (c) 2017 FlightAware, LLC
|
||||||
|
// Copyright (c) 2017 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
|
//
|
||||||
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
|
// under the terms of the GNU General Public License as published by the
|
||||||
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
|
// option) any later version.
|
||||||
|
//
|
||||||
|
// This file is distributed in the hope that it will be useful, but
|
||||||
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
// General Public License for more details.
|
||||||
|
//
|
||||||
|
// You should have received a copy of the GNU General Public License
|
||||||
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
#ifndef COMM_B_H
|
||||||
|
#define COMM_B_H
|
||||||
|
|
||||||
|
void decodeCommB(struct modesMessage *mm);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -58,8 +58,8 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include "../compat.h"
|
||||||
#include "clock_gettime.h"
|
#include <mach/mach_time.h>
|
||||||
#include <mach/clock.h> // for clock_get_time
|
#include <mach/clock.h> // for clock_get_time
|
||||||
#include <mach/clock_types.h> // for mach_timespec_t, CALENDAR_CLOCK, etc
|
#include <mach/clock_types.h> // for mach_timespec_t, CALENDAR_CLOCK, etc
|
||||||
#include <mach/kern_return.h> // for KERN_SUCCESS, kern_return_t
|
#include <mach/kern_return.h> // for KERN_SUCCESS, kern_return_t
|
||||||
|
|
@ -70,6 +70,8 @@
|
||||||
#include <errno.h> // for EINVAL, errno
|
#include <errno.h> // for EINVAL, errno
|
||||||
#include <unistd.h> // for getpid
|
#include <unistd.h> // for getpid
|
||||||
|
|
||||||
|
static mach_timebase_info_data_t __clock_gettime_inf;
|
||||||
|
|
||||||
int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||||
{
|
{
|
||||||
kern_return_t ret;
|
kern_return_t ret;
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,6 @@
|
||||||
#ifndef CLOCK_GETTIME_H
|
#ifndef CLOCK_GETTIME_H
|
||||||
#define CLOCK_GETTIME_H
|
#define CLOCK_GETTIME_H
|
||||||
|
|
||||||
#include <mach/mach_time.h> // Apple-only, but this isn't inclued on other BSDs
|
|
||||||
|
|
||||||
#ifdef _CLOCKID_T_DEFINED_
|
|
||||||
#define CLOCKID_T
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CLOCKID_T
|
|
||||||
#define CLOCKID_T
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
CLOCK_REALTIME,
|
|
||||||
CLOCK_MONOTONIC,
|
|
||||||
CLOCK_PROCESS_CPUTIME_ID,
|
|
||||||
CLOCK_THREAD_CPUTIME_ID
|
|
||||||
} clockid_t;
|
|
||||||
#endif // ifndef CLOCKID_T
|
|
||||||
|
|
||||||
struct timespec;
|
|
||||||
|
|
||||||
static mach_timebase_info_data_t __clock_gettime_inf;
|
|
||||||
|
|
||||||
int clock_gettime(clockid_t clk_id, struct timespec *tp);
|
int clock_gettime(clockid_t clk_id, struct timespec *tp);
|
||||||
|
|
||||||
#endif // CLOCK_GETTIME_H
|
#endif // CLOCK_GETTIME_H
|
||||||
|
|
|
||||||
|
|
@ -22,10 +22,7 @@
|
||||||
#include <errno.h> // for errno, EINVAL
|
#include <errno.h> // for errno, EINVAL
|
||||||
#include <time.h> // for nanosleep, NULL
|
#include <time.h> // for nanosleep, NULL
|
||||||
|
|
||||||
#include "clock_nanosleep.h"
|
#include "../compat.h"
|
||||||
#ifdef MISSING_GETTIME
|
|
||||||
#include "../clock_gettime/clock_gettime.h" // for clock_gettime
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int clock_nanosleep(clockid_t id, int flags, const struct timespec *ts,
|
int clock_nanosleep(clockid_t id, int flags, const struct timespec *ts,
|
||||||
struct timespec *ots) {
|
struct timespec *ots) {
|
||||||
|
|
|
||||||
|
|
@ -1,28 +1,6 @@
|
||||||
#ifndef CLOCK_NANOSLEEP_H
|
#ifndef CLOCK_NANOSLEEP_H
|
||||||
#define CLOCK_NANOSLEEP_H
|
#define CLOCK_NANOSLEEP_H
|
||||||
|
|
||||||
#ifdef _CLOCKID_T_DEFINED_
|
|
||||||
#define CLOCKID_T
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef CLOCKID_T
|
|
||||||
#define CLOCKID_T
|
|
||||||
typedef enum
|
|
||||||
{
|
|
||||||
CLOCK_REALTIME,
|
|
||||||
CLOCK_MONOTONIC,
|
|
||||||
CLOCK_PROCESS_CPUTIME_ID,
|
|
||||||
CLOCK_THREAD_CPUTIME_ID
|
|
||||||
} clockid_t;
|
|
||||||
#endif // ifndef CLOCKID_T
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef TIMER_ABSTIME
|
|
||||||
#define TIMER_ABSTIME 1
|
|
||||||
#endif // TIMER_ABSTIME
|
|
||||||
|
|
||||||
struct timespec;
|
|
||||||
|
|
||||||
int clock_nanosleep (clockid_t id, int flags, const struct timespec *ts,
|
int clock_nanosleep (clockid_t id, int flags, const struct timespec *ts,
|
||||||
struct timespec *ots);
|
struct timespec *ots);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,10 @@
|
||||||
# include <machine/endian.h>
|
# include <machine/endian.h>
|
||||||
# define le16toh(x) OSSwapLittleToHostInt16(x)
|
# define le16toh(x) OSSwapLittleToHostInt16(x)
|
||||||
# define le32toh(x) OSSwapLittleToHostInt32(x)
|
# define le32toh(x) OSSwapLittleToHostInt32(x)
|
||||||
|
# define le64toh(x) OSSwapLittleToHostInt64(x)
|
||||||
|
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
#include <sys/endian.h>
|
||||||
|
|
||||||
#else // other platforms
|
#else // other platforms
|
||||||
|
|
||||||
|
|
@ -24,6 +28,30 @@
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* clock_* and time-related types */
|
||||||
|
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#if defined(CLOCK_REALTIME)
|
||||||
|
# define HAVE_CLOCKID_T
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef HAVE_CLOCKID_T
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
CLOCK_REALTIME,
|
||||||
|
CLOCK_MONOTONIC,
|
||||||
|
CLOCK_PROCESS_CPUTIME_ID,
|
||||||
|
CLOCK_THREAD_CPUTIME_ID
|
||||||
|
} clockid_t;
|
||||||
|
#endif // !HAVE_CLOCKID_T
|
||||||
|
|
||||||
|
#ifndef TIMER_ABSTIME
|
||||||
|
#define TIMER_ABSTIME 1
|
||||||
|
#endif // !TIMER_ABSTIME
|
||||||
|
|
||||||
|
struct timespec;
|
||||||
|
|
||||||
#ifdef MISSING_NANOSLEEP
|
#ifdef MISSING_NANOSLEEP
|
||||||
#include "clock_nanosleep/clock_nanosleep.h"
|
#include "clock_nanosleep/clock_nanosleep.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
524
convert.c
524
convert.c
|
|
@ -4,498 +4,120 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
|
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
//
|
//
|
||||||
// This file is free software: you may copy, redistribute and/or modify it
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
// under the terms of the GNU General Public License as published by the
|
// under the terms of the GNU General Public License as published by the
|
||||||
// Free Software Foundation, either version 2 of the License, or (at your
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
// option) any later version.
|
// option) any later version.
|
||||||
//
|
//
|
||||||
// This file is distributed in the hope that it will be useful, but
|
// This file is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "dump1090.h"
|
#include "dump1090.h"
|
||||||
|
|
||||||
struct converter_state {
|
static void convert_uc8(void *iq_data,
|
||||||
float dc_a;
|
uint16_t *mag_data,
|
||||||
float dc_b;
|
unsigned nsamples,
|
||||||
float z1_I;
|
struct converter_state *state,
|
||||||
float z1_Q;
|
double *out_mean_level,
|
||||||
};
|
double *out_mean_power)
|
||||||
|
|
||||||
static uint16_t *uc8_lookup;
|
|
||||||
static bool init_uc8_lookup()
|
|
||||||
{
|
|
||||||
if (uc8_lookup)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
uc8_lookup = malloc(sizeof(uint16_t) * 256 * 256);
|
|
||||||
if (!uc8_lookup) {
|
|
||||||
fprintf(stderr, "can't allocate UC8 conversion lookup table\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i <= 255; i++) {
|
|
||||||
for (int q = 0; q <= 255; q++) {
|
|
||||||
float fI, fQ, magsq;
|
|
||||||
|
|
||||||
fI = (i - 127.5) / 127.5;
|
|
||||||
fQ = (q - 127.5) / 127.5;
|
|
||||||
magsq = fI * fI + fQ * fQ;
|
|
||||||
if (magsq > 1)
|
|
||||||
magsq = 1;
|
|
||||||
float mag = sqrtf(magsq);
|
|
||||||
|
|
||||||
uc8_lookup[le16toh((i*256)+q)] = (uint16_t) (mag * 65535.0f + 0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void convert_uc8_nodc(void *iq_data,
|
|
||||||
uint16_t *mag_data,
|
|
||||||
unsigned nsamples,
|
|
||||||
struct converter_state *state,
|
|
||||||
double *out_mean_level,
|
|
||||||
double *out_mean_power)
|
|
||||||
{
|
|
||||||
uint16_t *in = iq_data;
|
|
||||||
unsigned i;
|
|
||||||
uint64_t sum_level = 0;
|
|
||||||
uint64_t sum_power = 0;
|
|
||||||
uint16_t mag;
|
|
||||||
|
|
||||||
MODES_NOTUSED(state);
|
|
||||||
|
|
||||||
// unroll this a bit
|
|
||||||
|
|
||||||
#define DO_ONE_SAMPLE \
|
|
||||||
do { \
|
|
||||||
mag = uc8_lookup[*in++]; \
|
|
||||||
*mag_data++ = mag; \
|
|
||||||
sum_level += mag; \
|
|
||||||
sum_power += (uint32_t)mag * (uint32_t)mag; \
|
|
||||||
} while(0)
|
|
||||||
|
|
||||||
// unroll this a bit
|
|
||||||
for (i = 0; i < (nsamples>>3); ++i) {
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (i = 0; i < (nsamples&7); ++i) {
|
|
||||||
DO_ONE_SAMPLE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef DO_ONE_SAMPLE
|
|
||||||
|
|
||||||
if (out_mean_level) {
|
|
||||||
*out_mean_level = sum_level / 65536.0 / nsamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_power) {
|
|
||||||
*out_mean_power = sum_power / 65535.0 / 65535.0 / nsamples;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void convert_uc8_generic(void *iq_data,
|
|
||||||
uint16_t *mag_data,
|
|
||||||
unsigned nsamples,
|
|
||||||
struct converter_state *state,
|
|
||||||
double *out_mean_level,
|
|
||||||
double *out_mean_power)
|
|
||||||
{
|
|
||||||
uint8_t *in = iq_data;
|
|
||||||
float z1_I = state->z1_I;
|
|
||||||
float z1_Q = state->z1_Q;
|
|
||||||
const float dc_a = state->dc_a;
|
|
||||||
const float dc_b = state->dc_b;
|
|
||||||
|
|
||||||
unsigned i;
|
|
||||||
uint8_t I, Q;
|
|
||||||
float fI, fQ, magsq;
|
|
||||||
float sum_level = 0, sum_power = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < nsamples; ++i) {
|
|
||||||
I = *in++;
|
|
||||||
Q = *in++;
|
|
||||||
fI = (I - 127.5f) / 127.5f;
|
|
||||||
fQ = (Q - 127.5f) / 127.5f;
|
|
||||||
|
|
||||||
// DC block
|
|
||||||
z1_I = fI * dc_a + z1_I * dc_b;
|
|
||||||
z1_Q = fQ * dc_a + z1_Q * dc_b;
|
|
||||||
fI -= z1_I;
|
|
||||||
fQ -= z1_Q;
|
|
||||||
|
|
||||||
magsq = fI * fI + fQ * fQ;
|
|
||||||
if (magsq > 1)
|
|
||||||
magsq = 1;
|
|
||||||
|
|
||||||
float mag = sqrtf(magsq);
|
|
||||||
sum_power += magsq;
|
|
||||||
sum_level += mag;
|
|
||||||
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
state->z1_I = z1_I;
|
|
||||||
state->z1_Q = z1_Q;
|
|
||||||
|
|
||||||
if (out_mean_level) {
|
|
||||||
*out_mean_level = sum_level / nsamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_power) {
|
|
||||||
*out_mean_power = sum_power / nsamples;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void convert_sc16_generic(void *iq_data,
|
|
||||||
uint16_t *mag_data,
|
|
||||||
unsigned nsamples,
|
|
||||||
struct converter_state *state,
|
|
||||||
double *out_mean_level,
|
|
||||||
double *out_mean_power)
|
|
||||||
{
|
|
||||||
uint16_t *in = iq_data;
|
|
||||||
float z1_I = state->z1_I;
|
|
||||||
float z1_Q = state->z1_Q;
|
|
||||||
const float dc_a = state->dc_a;
|
|
||||||
const float dc_b = state->dc_b;
|
|
||||||
|
|
||||||
unsigned i;
|
|
||||||
int16_t I, Q;
|
|
||||||
float fI, fQ, magsq;
|
|
||||||
float sum_level = 0, sum_power = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < nsamples; ++i) {
|
|
||||||
I = (int16_t)le16toh(*in++);
|
|
||||||
Q = (int16_t)le16toh(*in++);
|
|
||||||
fI = I / 32768.0f;
|
|
||||||
fQ = Q / 32768.0f;
|
|
||||||
|
|
||||||
// DC block
|
|
||||||
z1_I = fI * dc_a + z1_I * dc_b;
|
|
||||||
z1_Q = fQ * dc_a + z1_Q * dc_b;
|
|
||||||
fI -= z1_I;
|
|
||||||
fQ -= z1_Q;
|
|
||||||
|
|
||||||
magsq = fI * fI + fQ * fQ;
|
|
||||||
if (magsq > 1)
|
|
||||||
magsq = 1;
|
|
||||||
|
|
||||||
float mag = sqrtf(magsq);
|
|
||||||
sum_power += magsq;
|
|
||||||
sum_level += mag;
|
|
||||||
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
state->z1_I = z1_I;
|
|
||||||
state->z1_Q = z1_Q;
|
|
||||||
|
|
||||||
if (out_mean_level) {
|
|
||||||
*out_mean_level = sum_level / nsamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_power) {
|
|
||||||
*out_mean_power = sum_power / nsamples;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void convert_sc16_nodc(void *iq_data,
|
|
||||||
uint16_t *mag_data,
|
|
||||||
unsigned nsamples,
|
|
||||||
struct converter_state *state,
|
|
||||||
double *out_mean_level,
|
|
||||||
double *out_mean_power)
|
|
||||||
{
|
{
|
||||||
MODES_NOTUSED(state);
|
MODES_NOTUSED(state);
|
||||||
|
|
||||||
uint16_t *in = iq_data;
|
const uc8_t *in = (const uc8_t *) iq_data;
|
||||||
|
|
||||||
unsigned i;
|
if (out_mean_level && out_mean_power) {
|
||||||
int16_t I, Q;
|
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data))
|
||||||
float fI, fQ, magsq;
|
starch_magnitude_power_uc8_aligned(in, mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
float sum_level = 0, sum_power = 0;
|
else
|
||||||
|
starch_magnitude_power_uc8(in, mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
for (i = 0; i < nsamples; ++i) {
|
} else {
|
||||||
I = (int16_t)le16toh(*in++);
|
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data))
|
||||||
Q = (int16_t)le16toh(*in++);
|
starch_magnitude_uc8_aligned(in, mag_data, nsamples);
|
||||||
fI = I / 32768.0f;
|
else
|
||||||
fQ = Q / 32768.0f;
|
starch_magnitude_uc8(in, mag_data, nsamples);
|
||||||
|
|
||||||
magsq = fI * fI + fQ * fQ;
|
|
||||||
if (magsq > 1)
|
|
||||||
magsq = 1;
|
|
||||||
|
|
||||||
float mag = sqrtf(magsq);
|
|
||||||
sum_power += magsq;
|
|
||||||
sum_level += mag;
|
|
||||||
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_level) {
|
|
||||||
*out_mean_level = sum_level / nsamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_power) {
|
|
||||||
*out_mean_power = sum_power / nsamples;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SC16Q11_TABLE_BITS controls the size of the lookup table
|
static void convert_sc16(void *iq_data,
|
||||||
// for SC16Q11 data. The size of the table is 2 * (1 << (2*BITS))
|
uint16_t *mag_data,
|
||||||
// bytes. Reducing the number of bits reduces precision but
|
unsigned nsamples,
|
||||||
// can run substantially faster by staying in cache.
|
struct converter_state *state,
|
||||||
// See convert_benchmark.c for some numbers.
|
double *out_mean_level,
|
||||||
|
double *out_mean_power)
|
||||||
// Leaving SC16QQ_TABLE_BITS undefined will disable the table lookup and always use
|
|
||||||
// the floating-point path, which may be faster on some systems
|
|
||||||
|
|
||||||
#if defined(SC16Q11_TABLE_BITS)
|
|
||||||
|
|
||||||
#define USE_BITS SC16Q11_TABLE_BITS
|
|
||||||
#define LOSE_BITS (11 - SC16Q11_TABLE_BITS)
|
|
||||||
|
|
||||||
static uint16_t *sc16q11_lookup;
|
|
||||||
static bool init_sc16q11_lookup()
|
|
||||||
{
|
|
||||||
if (sc16q11_lookup)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
sc16q11_lookup = malloc(sizeof(uint16_t) * (1 << (USE_BITS * 2)));
|
|
||||||
if (!sc16q11_lookup) {
|
|
||||||
fprintf(stderr, "can't allocate SC16Q11 conversion lookup table\n");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < 2048; i += (1 << LOSE_BITS)) {
|
|
||||||
for (int q = 0; q < 2048; q += (1 << LOSE_BITS)) {
|
|
||||||
float fI = i / 2048.0, fQ = q / 2048.0;
|
|
||||||
float magsq = fI * fI + fQ * fQ;
|
|
||||||
if (magsq > 1)
|
|
||||||
magsq = 1;
|
|
||||||
float mag = sqrtf(magsq);
|
|
||||||
|
|
||||||
unsigned index = ((i >> LOSE_BITS) << USE_BITS) | (q >> LOSE_BITS);
|
|
||||||
sc16q11_lookup[index] = (uint16_t)(mag * 65535.0f + 0.5f);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void convert_sc16q11_table(void *iq_data,
|
|
||||||
uint16_t *mag_data,
|
|
||||||
unsigned nsamples,
|
|
||||||
struct converter_state *state,
|
|
||||||
double *out_mean_level,
|
|
||||||
double *out_mean_power)
|
|
||||||
{
|
|
||||||
uint16_t *in = iq_data;
|
|
||||||
unsigned i;
|
|
||||||
uint16_t I, Q;
|
|
||||||
uint64_t sum_level = 0;
|
|
||||||
uint64_t sum_power = 0;
|
|
||||||
uint16_t mag;
|
|
||||||
|
|
||||||
MODES_NOTUSED(state);
|
|
||||||
|
|
||||||
for (i = 0; i < nsamples; ++i) {
|
|
||||||
I = abs((int16_t)le16toh(*in++)) & 2047;
|
|
||||||
Q = abs((int16_t)le16toh(*in++)) & 2047;
|
|
||||||
mag = sc16q11_lookup[((I >> LOSE_BITS) << USE_BITS) | (Q >> LOSE_BITS)];
|
|
||||||
*mag_data++ = mag;
|
|
||||||
sum_level += mag;
|
|
||||||
sum_power += (uint32_t)mag * (uint32_t)mag;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_level) {
|
|
||||||
*out_mean_level = sum_level / 65536.0 / nsamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_power) {
|
|
||||||
*out_mean_power = sum_power / 65535.0 / 65535.0 / nsamples;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#else /* ! defined(SC16Q11_TABLE_BITS) */
|
|
||||||
|
|
||||||
static void convert_sc16q11_nodc(void *iq_data,
|
|
||||||
uint16_t *mag_data,
|
|
||||||
unsigned nsamples,
|
|
||||||
struct converter_state *state,
|
|
||||||
double *out_mean_level,
|
|
||||||
double *out_mean_power)
|
|
||||||
{
|
{
|
||||||
MODES_NOTUSED(state);
|
MODES_NOTUSED(state);
|
||||||
|
|
||||||
uint16_t *in = iq_data;
|
const sc16_t *in = (const sc16_t *) iq_data;
|
||||||
|
|
||||||
unsigned i;
|
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data))
|
||||||
int16_t I, Q;
|
starch_magnitude_sc16_aligned(in, mag_data, nsamples);
|
||||||
float fI, fQ, magsq;
|
else
|
||||||
float sum_level = 0, sum_power = 0;
|
starch_magnitude_sc16(in, mag_data, nsamples);
|
||||||
|
|
||||||
for (i = 0; i < nsamples; ++i) {
|
if (out_mean_level && out_mean_power) {
|
||||||
I = (int16_t)le16toh(*in++);
|
if (STARCH_IS_ALIGNED(mag_data))
|
||||||
Q = (int16_t)le16toh(*in++);
|
starch_mean_power_u16_aligned(mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
fI = I / 2048.0f;
|
else
|
||||||
fQ = Q / 2048.0f;
|
starch_mean_power_u16(mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
|
|
||||||
magsq = fI * fI + fQ * fQ;
|
|
||||||
if (magsq > 1)
|
|
||||||
magsq = 1;
|
|
||||||
|
|
||||||
float mag = sqrtf(magsq);
|
|
||||||
sum_power += magsq;
|
|
||||||
sum_level += mag;
|
|
||||||
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_level) {
|
|
||||||
*out_mean_level = sum_level / nsamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_power) {
|
|
||||||
*out_mean_power = sum_power / nsamples;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* defined(SC16Q11_TABLE_BITS) */
|
static void convert_sc16q11(void *iq_data,
|
||||||
|
uint16_t *mag_data,
|
||||||
static void convert_sc16q11_generic(void *iq_data,
|
unsigned nsamples,
|
||||||
uint16_t *mag_data,
|
struct converter_state *state,
|
||||||
unsigned nsamples,
|
double *out_mean_level,
|
||||||
struct converter_state *state,
|
double *out_mean_power)
|
||||||
double *out_mean_level,
|
|
||||||
double *out_mean_power)
|
|
||||||
{
|
{
|
||||||
uint16_t *in = iq_data;
|
MODES_NOTUSED(state);
|
||||||
float z1_I = state->z1_I;
|
|
||||||
float z1_Q = state->z1_Q;
|
|
||||||
const float dc_a = state->dc_a;
|
|
||||||
const float dc_b = state->dc_b;
|
|
||||||
|
|
||||||
unsigned i;
|
const sc16_t *in = (const sc16_t *) iq_data;
|
||||||
int16_t I, Q;
|
|
||||||
float fI, fQ, magsq;
|
|
||||||
float sum_level = 0, sum_power = 0;
|
|
||||||
|
|
||||||
for (i = 0; i < nsamples; ++i) {
|
if (STARCH_IS_ALIGNED(in) && STARCH_IS_ALIGNED(mag_data))
|
||||||
I = (int16_t)le16toh(*in++);
|
starch_magnitude_sc16q11_aligned(in, mag_data, nsamples);
|
||||||
Q = (int16_t)le16toh(*in++);
|
else
|
||||||
fI = I / 2048.0f;
|
starch_magnitude_sc16q11(in, mag_data, nsamples);
|
||||||
fQ = Q / 2048.0f;
|
|
||||||
|
|
||||||
// DC block
|
if (out_mean_level && out_mean_power) {
|
||||||
z1_I = fI * dc_a + z1_I * dc_b;
|
if (STARCH_IS_ALIGNED(mag_data))
|
||||||
z1_Q = fQ * dc_a + z1_Q * dc_b;
|
starch_mean_power_u16_aligned(mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
fI -= z1_I;
|
else
|
||||||
fQ -= z1_Q;
|
starch_mean_power_u16(mag_data, nsamples, out_mean_level, out_mean_power);
|
||||||
|
|
||||||
magsq = fI * fI + fQ * fQ;
|
|
||||||
if (magsq > 1)
|
|
||||||
magsq = 1;
|
|
||||||
|
|
||||||
float mag = sqrtf(magsq);
|
|
||||||
sum_power += magsq;
|
|
||||||
sum_level += mag;
|
|
||||||
*mag_data++ = (uint16_t)(mag * 65535.0f + 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
state->z1_I = z1_I;
|
|
||||||
state->z1_Q = z1_Q;
|
|
||||||
|
|
||||||
if (out_mean_level) {
|
|
||||||
*out_mean_level = sum_level / nsamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (out_mean_power) {
|
|
||||||
*out_mean_power = sum_power / nsamples;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct {
|
|
||||||
input_format_t format;
|
|
||||||
int can_filter_dc;
|
|
||||||
iq_convert_fn fn;
|
|
||||||
const char *description;
|
|
||||||
bool (*init)();
|
|
||||||
} converters_table[] = {
|
|
||||||
// In order of preference
|
|
||||||
{ INPUT_UC8, 0, convert_uc8_nodc, "UC8, integer/table path", init_uc8_lookup },
|
|
||||||
{ INPUT_UC8, 1, convert_uc8_generic, "UC8, float path", NULL },
|
|
||||||
{ INPUT_SC16, 0, convert_sc16_nodc, "SC16, float path, no DC", NULL },
|
|
||||||
{ INPUT_SC16, 1, convert_sc16_generic, "SC16, float path", NULL },
|
|
||||||
#if defined(SC16Q11_TABLE_BITS)
|
|
||||||
{ INPUT_SC16Q11, 0, convert_sc16q11_table, "SC16Q11, integer/table path", init_sc16q11_lookup },
|
|
||||||
#else
|
|
||||||
{ INPUT_SC16Q11, 0, convert_sc16q11_nodc, "SC16Q11, float path, no DC", NULL },
|
|
||||||
#endif
|
|
||||||
{ INPUT_SC16Q11, 1, convert_sc16q11_generic, "SC16Q11, float path", NULL },
|
|
||||||
{ 0, 0, NULL, NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
||||||
iq_convert_fn init_converter(input_format_t format,
|
iq_convert_fn init_converter(input_format_t format,
|
||||||
double sample_rate,
|
double sample_rate,
|
||||||
int filter_dc,
|
int filter_dc,
|
||||||
struct converter_state **out_state)
|
struct converter_state **out_state)
|
||||||
{
|
{
|
||||||
int i;
|
MODES_NOTUSED(sample_rate);
|
||||||
|
MODES_NOTUSED(out_state);
|
||||||
for (i = 0; converters_table[i].fn; ++i) {
|
|
||||||
if (converters_table[i].format != format)
|
|
||||||
continue;
|
|
||||||
if (filter_dc && !converters_table[i].can_filter_dc)
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!converters_table[i].fn) {
|
|
||||||
fprintf(stderr, "no suitable converter for format=%d dc=%d\n",
|
|
||||||
format, filter_dc);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (converters_table[i].init) {
|
|
||||||
if (!converters_table[i].init())
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_state = malloc(sizeof(struct converter_state));
|
|
||||||
if (! *out_state) {
|
|
||||||
fprintf(stderr, "can't allocate converter state\n");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
(*out_state)->z1_I = 0;
|
|
||||||
(*out_state)->z1_Q = 0;
|
|
||||||
|
|
||||||
if (filter_dc) {
|
if (filter_dc) {
|
||||||
// init DC block @ 1Hz
|
fprintf(stderr, "DC filtering not supported (yet)\n");
|
||||||
(*out_state)->dc_b = exp(-2.0 * M_PI * 1.0 / sample_rate);
|
return NULL;
|
||||||
(*out_state)->dc_a = 1.0 - (*out_state)->dc_b;
|
|
||||||
} else {
|
|
||||||
// if the converter does filtering, make sure it has no effect
|
|
||||||
(*out_state)->dc_b = 1.0;
|
|
||||||
(*out_state)->dc_a = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return converters_table[i].fn;
|
switch (format) {
|
||||||
|
case INPUT_UC8:
|
||||||
|
return convert_uc8;
|
||||||
|
case INPUT_SC16:
|
||||||
|
return convert_sc16;
|
||||||
|
case INPUT_SC16Q11:
|
||||||
|
return convert_sc16q11;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "no suitable converter for format=%d\n", format);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_converter(struct converter_state *state)
|
void cleanup_converter(struct converter_state *state)
|
||||||
{
|
{
|
||||||
free(state);
|
MODES_NOTUSED(state);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
14
convert.h
14
convert.h
|
|
@ -4,17 +4,17 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
|
// Copyright (c) 2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
//
|
//
|
||||||
// This file is free software: you may copy, redistribute and/or modify it
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
// under the terms of the GNU General Public License as published by the
|
// under the terms of the GNU General Public License as published by the
|
||||||
// Free Software Foundation, either version 2 of the License, or (at your
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
// option) any later version.
|
// option) any later version.
|
||||||
//
|
//
|
||||||
// This file is distributed in the hope that it will be useful, but
|
// This file is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#ifndef DUMP1090_CONVERT_H
|
#ifndef DUMP1090_CONVERT_H
|
||||||
|
|
|
||||||
22
cpr.c
22
cpr.c
|
|
@ -4,20 +4,20 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
//
|
//
|
||||||
// This file is free software: you may copy, redistribute and/or modify it
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
// under the terms of the GNU General Public License as published by the
|
// under the terms of the GNU General Public License as published by the
|
||||||
// Free Software Foundation, either version 2 of the License, or (at your
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
// option) any later version.
|
// option) any later version.
|
||||||
//
|
//
|
||||||
// This file is distributed in the hope that it will be useful, but
|
// This file is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
// This file incorporates work covered by the following copyright and
|
// This file incorporates work covered by the following copyright and
|
||||||
// permission notice:
|
// permission notice:
|
||||||
//
|
//
|
||||||
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
|
// Copyright (C) 2012 by Salvatore Sanfilippo <antirez@gmail.com>
|
||||||
|
|
@ -47,6 +47,8 @@
|
||||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
|
#include "cpr.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
|
@ -345,9 +347,9 @@ int decodeCPRrelative(double reflat, double reflon,
|
||||||
return (-1); // Time to give up - Latitude error
|
return (-1); // Time to give up - Latitude error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check to see that answer is reasonable - ie no more than 1/2 cell away
|
// Check to see that answer is reasonable - ie no more than 1/2 cell away
|
||||||
if (fabs(rlat - reflat) > (AirDlat/2)) {
|
if (fabs(rlat - reflat) > (AirDlat/2)) {
|
||||||
return (-1); // Time to give up - Latitude error
|
return (-1); // Time to give up - Latitude error
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute the Longitude Index "m"
|
// Compute the Longitude Index "m"
|
||||||
|
|
|
||||||
14
cpr.h
14
cpr.h
|
|
@ -4,17 +4,17 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
//
|
//
|
||||||
// This file is free software: you may copy, redistribute and/or modify it
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
// under the terms of the GNU General Public License as published by the
|
// under the terms of the GNU General Public License as published by the
|
||||||
// Free Software Foundation, either version 2 of the License, or (at your
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
// option) any later version.
|
// option) any later version.
|
||||||
//
|
//
|
||||||
// This file is distributed in the hope that it will be useful, but
|
// This file is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#ifndef DUMP1090_CPR_H
|
#ifndef DUMP1090_CPR_H
|
||||||
|
|
|
||||||
14
cprtests.c
14
cprtests.c
|
|
@ -4,17 +4,17 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
//
|
//
|
||||||
// This file is free software: you may copy, redistribute and/or modify it
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
// under the terms of the GNU General Public License as published by the
|
// under the terms of the GNU General Public License as published by the
|
||||||
// Free Software Foundation, either version 2 of the License, or (at your
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
// option) any later version.
|
// option) any later version.
|
||||||
//
|
//
|
||||||
// This file is distributed in the hope that it will be useful, but
|
// This file is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
#include "cpu.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef ENABLE_CPUFEATURES
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//
|
||||||
|
// x86
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_X86
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
static X86Info *x86_info()
|
||||||
|
{
|
||||||
|
static bool valid = false;
|
||||||
|
static X86Info cache;
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
cache = GetX86Info();
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int cpu_supports_avx(void)
|
||||||
|
{
|
||||||
|
#ifdef CPU_FEATURES_ARCH_X86
|
||||||
|
return x86_info()->features.avx;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
int cpu_supports_avx2(void)
|
||||||
|
{
|
||||||
|
#ifdef CPU_FEATURES_ARCH_X86
|
||||||
|
return x86_info()->features.avx2;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// ARM
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_ARM
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
|
||||||
|
static ArmInfo *arm_info()
|
||||||
|
{
|
||||||
|
static bool valid = false;
|
||||||
|
static ArmInfo cache;
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
cache = GetArmInfo();
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int cpu_supports_armv7_neon_vfpv4(void)
|
||||||
|
{
|
||||||
|
#ifdef CPU_FEATURES_ARCH_ARM
|
||||||
|
return arm_info()->architecture >= 7 && arm_info()->features.neon && arm_info()->features.vfpv4 && arm_info()->features.vfpd32;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// AARCH64
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_AARCH64
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
|
||||||
|
static Aarch64Info *aarch64_info()
|
||||||
|
{
|
||||||
|
static bool valid = false;
|
||||||
|
static Aarch64Info cache;
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
cache = GetAarch64Info();
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return &cache;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int cpu_supports_armv8_simd(void)
|
||||||
|
{
|
||||||
|
#ifdef CPU_FEATURES_ARCH_AARCH64
|
||||||
|
return aarch64_info()->features.asimd;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
#ifndef DUMP1090_CPU_H
|
||||||
|
#define DUMP1090_CPU_H
|
||||||
|
|
||||||
|
// x86
|
||||||
|
int cpu_supports_avx(void);
|
||||||
|
int cpu_supports_avx2(void);
|
||||||
|
|
||||||
|
// ARM
|
||||||
|
int cpu_supports_armv7_neon_vfpv4(void);
|
||||||
|
|
||||||
|
// AARCH64
|
||||||
|
int cpu_supports_armv8_simd(void);
|
||||||
|
int cpu_supports_armv8_simd_sve(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
---
|
||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: Google
|
||||||
|
...
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
cmake_build/
|
||||||
|
build/
|
||||||
|
|
||||||
|
*.swp
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
language: c
|
||||||
|
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
cache:
|
||||||
|
timeout: 1000
|
||||||
|
directories:
|
||||||
|
- $HOME/cpu_features_archives
|
||||||
|
|
||||||
|
addons:
|
||||||
|
apt_packages:
|
||||||
|
- ninja-build
|
||||||
|
|
||||||
|
env:
|
||||||
|
global:
|
||||||
|
TOOLCHAIN=NATIVE
|
||||||
|
CMAKE_GENERATOR=Ninja
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
include:
|
||||||
|
- os: linux
|
||||||
|
compiler: gcc
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-linux-gnu
|
||||||
|
- os: linux
|
||||||
|
compiler: clang
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-linux-gnu
|
||||||
|
- os: osx
|
||||||
|
compiler: gcc
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-osx
|
||||||
|
CMAKE_GENERATOR="Unix Makefiles"
|
||||||
|
- os: osx
|
||||||
|
compiler: clang
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-osx
|
||||||
|
CMAKE_GENERATOR="Unix Makefiles"
|
||||||
|
- os: windows
|
||||||
|
env:
|
||||||
|
TARGET=x86_64-windows
|
||||||
|
CMAKE_GENERATOR="Visual Studio 15 2017 Win64"
|
||||||
|
|
||||||
|
# see: https://docs.travis-ci.com/user/multi-cpu-architectures/
|
||||||
|
- os: linux
|
||||||
|
arch: ppc64le
|
||||||
|
compiler: gcc
|
||||||
|
env:
|
||||||
|
TARGET=ppc64le-linux-gnu
|
||||||
|
- os: linux
|
||||||
|
arch: ppc64le
|
||||||
|
compiler: clang
|
||||||
|
env:
|
||||||
|
TARGET=ppc64le-linux-gnu
|
||||||
|
|
||||||
|
# Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=aarch64-linux-gnu
|
||||||
|
QEMU_ARCH=aarch64
|
||||||
|
# Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=arm-linux-gnueabihf
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
# Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armv8l-linux-gnueabihf
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
# Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=arm-linux-gnueabi
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
# Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=aarch64_be-linux-gnu
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
# Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armeb-linux-gnueabihf
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
# Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armeb-linux-gnueabi
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips32
|
||||||
|
QEMU_ARCH=mips
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips32el
|
||||||
|
QEMU_ARCH=mipsel
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips64
|
||||||
|
QEMU_ARCH=mips64
|
||||||
|
- os: linux
|
||||||
|
env:
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips64el
|
||||||
|
QEMU_ARCH=mips64el
|
||||||
|
|
||||||
|
script:
|
||||||
|
- cmake --version
|
||||||
|
- bash -e -x ./scripts/run_integration.sh
|
||||||
|
|
@ -0,0 +1,259 @@
|
||||||
|
cmake_minimum_required(VERSION 3.0)
|
||||||
|
|
||||||
|
# option() honors normal variables.
|
||||||
|
# see: https://cmake.org/cmake/help/git-stage/policy/CMP0077.html
|
||||||
|
if(POLICY CMP0077)
|
||||||
|
cmake_policy(SET CMP0077 NEW)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
project(CpuFeatures VERSION 0.6.0 LANGUAGES C)
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 99)
|
||||||
|
|
||||||
|
# Default Build Type to be Release
|
||||||
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
|
set(CMAKE_BUILD_TYPE "Release" CACHE STRING
|
||||||
|
"Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel."
|
||||||
|
FORCE)
|
||||||
|
endif(NOT CMAKE_BUILD_TYPE)
|
||||||
|
|
||||||
|
# BUILD_TESTING is a standard CMake variable, but we declare it here to make it
|
||||||
|
# prominent in the GUI.
|
||||||
|
option(BUILD_TESTING "Enable test (depends on googletest)." OFF)
|
||||||
|
# BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to make
|
||||||
|
# it prominent in the GUI.
|
||||||
|
# cpu_features uses bit-fields which are - to some extends - implementation-defined (see https://en.cppreference.com/w/c/language/bit_field).
|
||||||
|
# As a consequence it is discouraged to use cpu_features as a shared library because different compilers may interpret the code in different ways.
|
||||||
|
# Prefer static linking from source whenever possible.
|
||||||
|
option(BUILD_SHARED_LIBS "Build library as shared." OFF)
|
||||||
|
# PIC
|
||||||
|
option(BUILD_PIC "Build with Position Independant Code." OFF) # Default is off at least for GCC
|
||||||
|
|
||||||
|
# Force PIC on unix when building shared libs
|
||||||
|
# see: https://en.wikipedia.org/wiki/Position-independent_code
|
||||||
|
if(BUILD_SHARED_LIBS AND UNIX)
|
||||||
|
set(BUILD_PIC ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CheckIncludeFile)
|
||||||
|
include(CheckSymbolExists)
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
|
macro(setup_include_and_definitions TARGET_NAME)
|
||||||
|
target_include_directories(${TARGET_NAME}
|
||||||
|
PUBLIC $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||||
|
PRIVATE $<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include/internal>
|
||||||
|
)
|
||||||
|
target_compile_definitions(${TARGET_NAME}
|
||||||
|
PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024
|
||||||
|
)
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
set(PROCESSOR_IS_MIPS FALSE)
|
||||||
|
set(PROCESSOR_IS_ARM FALSE)
|
||||||
|
set(PROCESSOR_IS_AARCH64 FALSE)
|
||||||
|
set(PROCESSOR_IS_X86 FALSE)
|
||||||
|
set(PROCESSOR_IS_POWER FALSE)
|
||||||
|
|
||||||
|
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^mips")
|
||||||
|
set(PROCESSOR_IS_MIPS TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^arm")
|
||||||
|
set(PROCESSOR_IS_ARM TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^aarch64")
|
||||||
|
set(PROCESSOR_IS_AARCH64 TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(AMD64|amd64)|(^i.86$)")
|
||||||
|
set(PROCESSOR_IS_X86 TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(powerpc|ppc)")
|
||||||
|
set(PROCESSOR_IS_POWER TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
macro(add_cpu_features_headers_and_sources HDRS_LIST_NAME SRCS_LIST_NAME)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_macros.h)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpu_features_cache_info.h)
|
||||||
|
if(PROCESSOR_IS_MIPS)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_mips.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_mips.c)
|
||||||
|
elseif(PROCESSOR_IS_ARM)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_arm.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_arm.c)
|
||||||
|
elseif(PROCESSOR_IS_AARCH64)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_aarch64.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_aarch64.c)
|
||||||
|
elseif(PROCESSOR_IS_X86)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_x86.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/internal/cpuid_x86.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_x86.c)
|
||||||
|
elseif(PROCESSOR_IS_POWER)
|
||||||
|
list(APPEND ${HDRS_LIST_NAME} ${PROJECT_SOURCE_DIR}/include/cpuinfo_ppc.h)
|
||||||
|
list(APPEND ${SRCS_LIST_NAME} ${PROJECT_SOURCE_DIR}/src/cpuinfo_ppc.c)
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unsupported architectures ${CMAKE_SYSTEM_PROCESSOR}")
|
||||||
|
endif()
|
||||||
|
endmacro()
|
||||||
|
|
||||||
|
#
|
||||||
|
# library : utils
|
||||||
|
#
|
||||||
|
|
||||||
|
add_library(utils OBJECT
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/bit_utils.h
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/filesystem.h
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/stack_line_reader.h
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/string_view.h
|
||||||
|
${PROJECT_SOURCE_DIR}/src/filesystem.c
|
||||||
|
${PROJECT_SOURCE_DIR}/src/stack_line_reader.c
|
||||||
|
${PROJECT_SOURCE_DIR}/src/string_view.c
|
||||||
|
)
|
||||||
|
set_property(TARGET utils PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||||
|
setup_include_and_definitions(utils)
|
||||||
|
|
||||||
|
#
|
||||||
|
# library : unix_based_hardware_detection
|
||||||
|
#
|
||||||
|
|
||||||
|
if(UNIX)
|
||||||
|
add_library(unix_based_hardware_detection OBJECT
|
||||||
|
${PROJECT_SOURCE_DIR}/include/internal/hwcaps.h
|
||||||
|
${PROJECT_SOURCE_DIR}/src/hwcaps.c
|
||||||
|
)
|
||||||
|
setup_include_and_definitions(unix_based_hardware_detection)
|
||||||
|
check_include_file(dlfcn.h HAVE_DLFCN_H)
|
||||||
|
if(HAVE_DLFCN_H)
|
||||||
|
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_DLFCN_H)
|
||||||
|
endif()
|
||||||
|
check_symbol_exists(getauxval "sys/auxv.h" HAVE_STRONG_GETAUXVAL)
|
||||||
|
if(HAVE_STRONG_GETAUXVAL)
|
||||||
|
target_compile_definitions(unix_based_hardware_detection PRIVATE HAVE_STRONG_GETAUXVAL)
|
||||||
|
endif()
|
||||||
|
set_property(TARGET unix_based_hardware_detection PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# library : cpu_features
|
||||||
|
#
|
||||||
|
set (CPU_FEATURES_HDRS)
|
||||||
|
set (CPU_FEATURES_SRCS)
|
||||||
|
add_cpu_features_headers_and_sources(CPU_FEATURES_HDRS CPU_FEATURES_SRCS)
|
||||||
|
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:utils>)
|
||||||
|
if(NOT PROCESSOR_IS_X86 AND UNIX)
|
||||||
|
list(APPEND CPU_FEATURES_SRCS $<TARGET_OBJECTS:unix_based_hardware_detection>)
|
||||||
|
endif()
|
||||||
|
add_library(cpu_features ${CPU_FEATURES_HDRS} ${CPU_FEATURES_SRCS})
|
||||||
|
set_target_properties(cpu_features PROPERTIES PUBLIC_HEADER "${CPU_FEATURES_HDRS}")
|
||||||
|
setup_include_and_definitions(cpu_features)
|
||||||
|
target_link_libraries(cpu_features PUBLIC ${CMAKE_DL_LIBS})
|
||||||
|
set_property(TARGET cpu_features PROPERTY POSITION_INDEPENDENT_CODE ${BUILD_PIC})
|
||||||
|
target_include_directories(cpu_features
|
||||||
|
PUBLIC $<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}/cpu_features>
|
||||||
|
)
|
||||||
|
if(PROCESSOR_IS_X86)
|
||||||
|
if(APPLE)
|
||||||
|
target_compile_definitions(cpu_features PRIVATE HAVE_SYSCTLBYNAME)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
add_library(CpuFeature::cpu_features ALIAS cpu_features)
|
||||||
|
|
||||||
|
#
|
||||||
|
# program : list_cpu_features
|
||||||
|
#
|
||||||
|
|
||||||
|
add_executable(list_cpu_features ${PROJECT_SOURCE_DIR}/src/utils/list_cpu_features.c)
|
||||||
|
target_link_libraries(list_cpu_features PRIVATE cpu_features)
|
||||||
|
add_executable(CpuFeature::list_cpu_features ALIAS list_cpu_features)
|
||||||
|
|
||||||
|
#
|
||||||
|
# ndk_compat
|
||||||
|
#
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
add_subdirectory(ndk_compat)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# tests
|
||||||
|
#
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
if(BUILD_TESTING)
|
||||||
|
# Automatically incorporate googletest into the CMake Project if target not
|
||||||
|
# found.
|
||||||
|
enable_language(CXX)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_EXTENSIONS OFF) # prefer use of -std11 instead of -gnustd11
|
||||||
|
|
||||||
|
if(NOT TARGET gtest OR NOT TARGET gmock_main)
|
||||||
|
# Download and unpack googletest at configure time.
|
||||||
|
configure_file(
|
||||||
|
cmake/googletest.CMakeLists.txt.in
|
||||||
|
googletest-download/CMakeLists.txt
|
||||||
|
)
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} -G "${CMAKE_GENERATOR}" .
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "CMake step for googletest failed: ${result}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
execute_process(
|
||||||
|
COMMAND ${CMAKE_COMMAND} --build .
|
||||||
|
RESULT_VARIABLE result
|
||||||
|
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/googletest-download)
|
||||||
|
|
||||||
|
if(result)
|
||||||
|
message(FATAL_ERROR "Build step for googletest failed: ${result}")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Prevent overriding the parent project's compiler/linker settings on
|
||||||
|
# Windows.
|
||||||
|
set(gtest_force_shared_crt ON CACHE BOOL "" FORCE)
|
||||||
|
|
||||||
|
# Add googletest directly to our build. This defines the gtest and
|
||||||
|
# gtest_main targets.
|
||||||
|
add_subdirectory(${CMAKE_BINARY_DIR}/googletest-src
|
||||||
|
${CMAKE_BINARY_DIR}/googletest-build
|
||||||
|
EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(test)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
#
|
||||||
|
# Install cpu_features and list_cpu_features
|
||||||
|
#
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS cpu_features list_cpu_features
|
||||||
|
EXPORT CpuFeaturesTargets
|
||||||
|
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cpu_features
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
|
install(EXPORT CpuFeaturesTargets
|
||||||
|
NAMESPACE CpuFeatures::
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
configure_package_config_file(cmake/CpuFeaturesConfig.cmake.in
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
|
||||||
|
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
|
||||||
|
NO_SET_AND_CHECK_MACRO
|
||||||
|
NO_CHECK_REQUIRED_COMPONENTS_MACRO
|
||||||
|
)
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
|
||||||
|
COMPATIBILITY SameMajorVersion
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesConfig.cmake"
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesConfigVersion.cmake"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeatures"
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,23 @@
|
||||||
|
# How to Contribute
|
||||||
|
|
||||||
|
We'd love to accept your patches and contributions to this project. There are
|
||||||
|
just a few small guidelines you need to follow.
|
||||||
|
|
||||||
|
## Contributor License Agreement
|
||||||
|
|
||||||
|
Contributions to this project must be accompanied by a Contributor License
|
||||||
|
Agreement. You (or your employer) retain the copyright to your contribution;
|
||||||
|
this simply gives us permission to use and redistribute your contributions as
|
||||||
|
part of the project. Head over to <https://cla.developers.google.com/> to see
|
||||||
|
your current agreements on file or to sign a new one.
|
||||||
|
|
||||||
|
You generally only need to submit a CLA once, so if you've already submitted one
|
||||||
|
(even if it was for a different project), you probably don't need to do it
|
||||||
|
again.
|
||||||
|
|
||||||
|
## Code reviews
|
||||||
|
|
||||||
|
All submissions, including submissions by project members, require review. We
|
||||||
|
use GitHub pull requests for this purpose. Consult
|
||||||
|
[GitHub Help](https://help.github.com/articles/about-pull-requests/) for more
|
||||||
|
information on using pull requests.
|
||||||
|
|
@ -0,0 +1,230 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
For files in the `ndk_compat` folder:
|
||||||
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
|
Copyright (C) 2010 The Android Open Source Project
|
||||||
|
All rights reserved.
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
* Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
* Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in
|
||||||
|
the documentation and/or other materials provided with the
|
||||||
|
distribution.
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGE.
|
||||||
|
|
@ -0,0 +1,199 @@
|
||||||
|
# cpu_features [](https://travis-ci.org/google/cpu_features) [](https://ci.appveyor.com/project/gchatelet/cpu-features/branch/master)
|
||||||
|
|
||||||
|
A cross-platform C library to retrieve CPU features (such as available
|
||||||
|
instructions) at runtime.
|
||||||
|
|
||||||
|
## Table of Contents
|
||||||
|
|
||||||
|
- [Design Rationale](#rationale)
|
||||||
|
- [Code samples](#codesample)
|
||||||
|
- [Running sample code](#usagesample)
|
||||||
|
- [What's supported](#support)
|
||||||
|
- [Android NDK's drop in replacement](#ndk)
|
||||||
|
- [License](#license)
|
||||||
|
- [Build with cmake](#cmake)
|
||||||
|
|
||||||
|
<a name="rationale"></a>
|
||||||
|
## Design Rationale
|
||||||
|
|
||||||
|
- **Simple to use.** See the snippets below for examples.
|
||||||
|
- **Extensible.** Easy to add missing features or architectures.
|
||||||
|
- **Compatible with old compilers** and available on many architectures so it
|
||||||
|
can be used widely. To ensure that cpu_features works on as many platforms
|
||||||
|
as possible, we implemented it in a highly portable version of C: C99.
|
||||||
|
- **Sandbox-compatible.** The library uses a variety of strategies to cope
|
||||||
|
with sandboxed environments or when `cpuid` is unavailable. This is useful
|
||||||
|
when running integration tests in hermetic environments.
|
||||||
|
- **Thread safe, no memory allocation, and raises no exceptions.**
|
||||||
|
cpu_features is suitable for implementing fundamental libc functions like
|
||||||
|
`malloc`, `memcpy`, and `memcmp`.
|
||||||
|
- **Unit tested.**
|
||||||
|
|
||||||
|
<a name="codesample"></a>
|
||||||
|
## Code samples
|
||||||
|
|
||||||
|
**Note:** For C++ code, the library functions are defined in the `CpuFeatures` namespace.
|
||||||
|
|
||||||
|
### Checking features at runtime
|
||||||
|
|
||||||
|
Here's a simple example that executes a codepath if the CPU supports both the
|
||||||
|
AES and the SSE4.2 instruction sets:
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
// For C++, add `using namespace CpuFeatures;`
|
||||||
|
static const X86Features features = GetX86Info().features;
|
||||||
|
|
||||||
|
void Compute(void) {
|
||||||
|
if (features.aes && features.sse4_2) {
|
||||||
|
// Run optimized code.
|
||||||
|
} else {
|
||||||
|
// Run standard code.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Caching for faster evaluation of complex checks
|
||||||
|
|
||||||
|
If you wish, you can read all the features at once into a global variable, and
|
||||||
|
then query for the specific features you care about. Below, we store all the ARM
|
||||||
|
features and then check whether AES and NEON are supported.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
|
||||||
|
// For C++, add `using namespace CpuFeatures;`
|
||||||
|
static const ArmFeatures features = GetArmInfo().features;
|
||||||
|
static const bool has_aes_and_neon = features.aes && features.neon;
|
||||||
|
|
||||||
|
// use has_aes_and_neon.
|
||||||
|
```
|
||||||
|
|
||||||
|
This is a good approach to take if you're checking for combinations of features
|
||||||
|
when using a compiler that is slow to extract individual bits from bit-packed
|
||||||
|
structures.
|
||||||
|
|
||||||
|
### Checking compile time flags
|
||||||
|
|
||||||
|
The following code determines whether the compiler was told to use the AVX
|
||||||
|
instruction set (e.g., `g++ -mavx`) and sets `has_avx` accordingly.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
// For C++, add `using namespace CpuFeatures;`
|
||||||
|
static const X86Features features = GetX86Info().features;
|
||||||
|
static const bool has_avx = CPU_FEATURES_COMPILED_X86_AVX || features.avx;
|
||||||
|
|
||||||
|
// use has_avx.
|
||||||
|
```
|
||||||
|
|
||||||
|
`CPU_FEATURES_COMPILED_X86_AVX` is set to 1 if the compiler was instructed to
|
||||||
|
use AVX and 0 otherwise, combining compile time and runtime knowledge.
|
||||||
|
|
||||||
|
### Rejecting poor hardware implementations based on microarchitecture
|
||||||
|
|
||||||
|
On x86, the first incarnation of a feature in a microarchitecture might not be
|
||||||
|
the most efficient (e.g. AVX on Sandy Bridge). We provide a function to retrieve
|
||||||
|
the underlying microarchitecture so you can decide whether to use it.
|
||||||
|
|
||||||
|
Below, `has_fast_avx` is set to 1 if the CPU supports the AVX instruction
|
||||||
|
set—but only if it's not Sandy Bridge.
|
||||||
|
|
||||||
|
```c
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
// For C++, add `using namespace CpuFeatures;`
|
||||||
|
static const X86Info info = GetX86Info();
|
||||||
|
static const X86Microarchitecture uarch = GetX86Microarchitecture(&info);
|
||||||
|
static const bool has_fast_avx = info.features.avx && uarch != INTEL_SNB;
|
||||||
|
|
||||||
|
// use has_fast_avx.
|
||||||
|
```
|
||||||
|
|
||||||
|
This feature is currently available only for x86 microarchitectures.
|
||||||
|
|
||||||
|
<a name="usagesample"></a>
|
||||||
|
### Running sample code
|
||||||
|
|
||||||
|
Building `cpu_features` (check [quickstart](#quickstart) below) brings a small executable to test the library.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
% ./build/list_cpu_features
|
||||||
|
arch : x86
|
||||||
|
brand : Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz
|
||||||
|
family : 6 (0x06)
|
||||||
|
model : 45 (0x2D)
|
||||||
|
stepping : 7 (0x07)
|
||||||
|
uarch : INTEL_SNB
|
||||||
|
flags : aes,avx,cx16,smx,sse4_1,sse4_2,ssse3
|
||||||
|
```
|
||||||
|
|
||||||
|
```shell
|
||||||
|
% ./build/list_cpu_features --json
|
||||||
|
{"arch":"x86","brand":" Intel(R) Xeon(R) CPU E5-1650 0 @ 3.20GHz","family":6,"model":45,"stepping":7,"uarch":"INTEL_SNB","flags":["aes","avx","cx16","smx","sse4_1","sse4_2","ssse3"]}
|
||||||
|
```
|
||||||
|
|
||||||
|
<a name="support"></a>
|
||||||
|
## What's supported
|
||||||
|
|
||||||
|
| | x86³ | ARM | AArch64 | MIPS⁴ | POWER |
|
||||||
|
|---------|:----:|:-------:|:-------:|:------:|:-------:|
|
||||||
|
| Android | yes² | yes¹ | yes¹ | yes¹ | N/A |
|
||||||
|
| iOS | N/A | not yet | not yet | N/A | N/A |
|
||||||
|
| Linux | yes² | yes¹ | yes¹ | yes¹ | yes¹ |
|
||||||
|
| MacOs | yes² | N/A | not yet | N/A | no |
|
||||||
|
| Windows | yes² | not yet | not yet | N/A | N/A |
|
||||||
|
|
||||||
|
1. **Features revealed from Linux.** We gather data from several sources
|
||||||
|
depending on availability:
|
||||||
|
+ from glibc's
|
||||||
|
[getauxval](https://www.gnu.org/software/libc/manual/html_node/Auxiliary-Vector.html)
|
||||||
|
+ by parsing `/proc/self/auxv`
|
||||||
|
+ by parsing `/proc/cpuinfo`
|
||||||
|
2. **Features revealed from CPU.** features are retrieved by using the `cpuid`
|
||||||
|
instruction.
|
||||||
|
3. **Microarchitecture detection.** On x86 some features are not always
|
||||||
|
implemented efficiently in hardware (e.g. AVX on Sandybridge). Exposing the
|
||||||
|
microarchitecture allows the client to reject particular microarchitectures.
|
||||||
|
4. All flavors of Mips are supported, little and big endian as well as 32/64
|
||||||
|
bits.
|
||||||
|
|
||||||
|
<a name="ndk"></a>
|
||||||
|
## Android NDK's drop in replacement
|
||||||
|
|
||||||
|
[cpu_features](https://github.com/google/cpu_features) is now officially
|
||||||
|
supporting Android and offers a drop in replacement of for the NDK's [cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h)
|
||||||
|
, see [ndk_compat](ndk_compat) folder for details.
|
||||||
|
|
||||||
|
<a name="license"></a>
|
||||||
|
## License
|
||||||
|
|
||||||
|
The cpu_features library is licensed under the terms of the Apache license.
|
||||||
|
See [LICENSE](LICENSE) for more information.
|
||||||
|
|
||||||
|
<a name="cmake"></a>
|
||||||
|
## Build with CMake
|
||||||
|
|
||||||
|
Please check the [CMake build instructions](cmake/README.md).
|
||||||
|
|
||||||
|
<a name="quickstart"></a>
|
||||||
|
### Quickstart with `Ninja`
|
||||||
|
|
||||||
|
- build `list_cpu_features`
|
||||||
|
```
|
||||||
|
cmake -B/tmp/cpu_features -H. -GNinja -DCMAKE_BUILD_TYPE=Release
|
||||||
|
ninja -C/tmp/cpu_features
|
||||||
|
/tmp/cpu_features/list_cpu_features --json
|
||||||
|
```
|
||||||
|
|
||||||
|
- run tests
|
||||||
|
```
|
||||||
|
cmake -B/tmp/cpu_features -H. -GNinja -DBUILD_TESTING=ON
|
||||||
|
ninja -C/tmp/cpu_features
|
||||||
|
ninja -C/tmp/cpu_features test
|
||||||
|
```
|
||||||
|
|
@ -0,0 +1,7 @@
|
||||||
|
# ===== googletest =====
|
||||||
|
|
||||||
|
git_repository(
|
||||||
|
name = "com_google_googletest",
|
||||||
|
remote = "https://github.com/google/googletest.git",
|
||||||
|
commit = "c3f65335b79f47b05629e79a54685d899bc53b93",
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
version: '{build}'
|
||||||
|
shallow_clone: true
|
||||||
|
|
||||||
|
platform: x64
|
||||||
|
|
||||||
|
environment:
|
||||||
|
matrix:
|
||||||
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
CMAKE_GENERATOR: "Visual Studio 15 2017 Win64"
|
||||||
|
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
|
CMAKE_GENERATOR: "Visual Studio 14 2015 Win64"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
|
|
||||||
|
before_build:
|
||||||
|
- cmake --version
|
||||||
|
- cmake -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON -H. -Bcmake_build -G "%CMAKE_GENERATOR%"
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
- cmake --build cmake_build --config Debug --target ALL_BUILD
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
- cmake --build cmake_build --config Debug --target RUN_TESTS
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# CpuFeatures CMake configuration file
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesTargets.cmake")
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
# CpuFeaturesNdkCompat CMake configuration file
|
||||||
|
|
||||||
|
include("${CMAKE_CURRENT_LIST_DIR}/CpuFeaturesNdkCompatTargets.cmake")
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
# CMake build instructions
|
||||||
|
|
||||||
|
## Recommended usage : Incorporating cpu_features into a CMake project
|
||||||
|
|
||||||
|
For API / ABI compatibility reasons, it is recommended to build and use
|
||||||
|
cpu_features in a subdirectory of your project or as an embedded dependency.
|
||||||
|
|
||||||
|
This is similar to the recommended usage of the googletest framework
|
||||||
|
( https://github.com/google/googletest/blob/master/googletest/README.md )
|
||||||
|
|
||||||
|
Build and use step-by-step
|
||||||
|
|
||||||
|
|
||||||
|
1- Download cpu_features and copy it in a sub-directory in your project.
|
||||||
|
or add cpu_features as a git-submodule in your project
|
||||||
|
|
||||||
|
2- You can then use the cmake command `add_subdirectory()` to include
|
||||||
|
cpu_features directly and use the `cpu_features` target in your project.
|
||||||
|
|
||||||
|
3- Add the `cpu_features` target to the `target_link_libraries()` section of
|
||||||
|
your executable or of your library.
|
||||||
|
|
||||||
|
## Enabling tests
|
||||||
|
|
||||||
|
CMake default options for cpu_features is Release built type with tests
|
||||||
|
disabled. To enable testing set cmake `BUILD_TESTING` variable to `ON`,
|
||||||
|
[.travis.yml](../.travis.yml) and [appveyor.yml](../appveyor.yml) have up to
|
||||||
|
date examples.
|
||||||
|
|
@ -0,0 +1,15 @@
|
||||||
|
cmake_minimum_required(VERSION 2.8.2)
|
||||||
|
|
||||||
|
project(googletest-download NONE)
|
||||||
|
|
||||||
|
include(ExternalProject)
|
||||||
|
ExternalProject_Add(googletest
|
||||||
|
GIT_REPOSITORY https://github.com/google/googletest.git
|
||||||
|
GIT_TAG master
|
||||||
|
SOURCE_DIR "${CMAKE_BINARY_DIR}/googletest-src"
|
||||||
|
BINARY_DIR "${CMAKE_BINARY_DIR}/googletest-build"
|
||||||
|
CONFIGURE_COMMAND ""
|
||||||
|
BUILD_COMMAND ""
|
||||||
|
INSTALL_COMMAND ""
|
||||||
|
TEST_COMMAND ""
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CPU_FEATURE_CACHE_NULL = 0,
|
||||||
|
CPU_FEATURE_CACHE_DATA = 1,
|
||||||
|
CPU_FEATURE_CACHE_INSTRUCTION = 2,
|
||||||
|
CPU_FEATURE_CACHE_UNIFIED = 3,
|
||||||
|
CPU_FEATURE_CACHE_TLB = 4,
|
||||||
|
CPU_FEATURE_CACHE_DTLB = 5,
|
||||||
|
CPU_FEATURE_CACHE_STLB = 6,
|
||||||
|
CPU_FEATURE_CACHE_PREFETCH = 7
|
||||||
|
} CacheType;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int level;
|
||||||
|
CacheType cache_type;
|
||||||
|
int cache_size; // Cache size in bytes
|
||||||
|
int ways; // Associativity, 0 undefined, 0xFF fully associative
|
||||||
|
int line_size; // Cache line size in bytes
|
||||||
|
int tlb_entries; // number of entries for TLB
|
||||||
|
int partitioning; // number of lines per sector
|
||||||
|
} CacheLevelInfo;
|
||||||
|
|
||||||
|
// Increase this value if more cache levels are needed.
|
||||||
|
#ifndef CPU_FEATURES_MAX_CACHE_LEVEL
|
||||||
|
#define CPU_FEATURES_MAX_CACHE_LEVEL 10
|
||||||
|
#endif
|
||||||
|
typedef struct {
|
||||||
|
int size;
|
||||||
|
CacheLevelInfo levels[CPU_FEATURES_MAX_CACHE_LEVEL];
|
||||||
|
} CacheInfo;
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_COMMON_H_
|
||||||
|
|
@ -0,0 +1,216 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Architectures
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(__pnacl__) || defined(__CLR_VER)
|
||||||
|
#define CPU_FEATURES_ARCH_VM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(_M_IX86) || defined(__i386__)) && !defined(CPU_FEATURES_ARCH_VM)
|
||||||
|
#define CPU_FEATURES_ARCH_X86_32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(_M_X64) || defined(__x86_64__)) && !defined(CPU_FEATURES_ARCH_VM)
|
||||||
|
#define CPU_FEATURES_ARCH_X86_64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86_32) || defined(CPU_FEATURES_ARCH_X86_64)
|
||||||
|
#define CPU_FEATURES_ARCH_X86
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__arm__) || defined(_M_ARM))
|
||||||
|
#define CPU_FEATURES_ARCH_ARM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__aarch64__)
|
||||||
|
#define CPU_FEATURES_ARCH_AARCH64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(CPU_FEATURES_ARCH_AARCH64) || defined(CPU_FEATURES_ARCH_ARM))
|
||||||
|
#define CPU_FEATURES_ARCH_ANY_ARM
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mips64)
|
||||||
|
#define CPU_FEATURES_ARCH_MIPS64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__mips__) && !defined(__mips64) // mips64 also declares __mips__
|
||||||
|
#define CPU_FEATURES_ARCH_MIPS32
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_MIPS32) || defined(CPU_FEATURES_ARCH_MIPS64)
|
||||||
|
#define CPU_FEATURES_ARCH_MIPS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__powerpc__)
|
||||||
|
#define CPU_FEATURES_ARCH_PPC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Os
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
#define CPU_FEATURES_OS_LINUX_OR_ANDROID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#define CPU_FEATURES_OS_ANDROID
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(_WIN64) || defined(_WIN32))
|
||||||
|
#define CPU_FEATURES_OS_WINDOWS
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__apple__) || defined(__APPLE__) || defined(__MACH__))
|
||||||
|
#define CPU_FEATURES_OS_DARWIN
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compilers
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(__clang__)
|
||||||
|
#define CPU_FEATURES_COMPILER_CLANG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__GNUC__) && !defined(__clang__)
|
||||||
|
#define CPU_FEATURES_COMPILER_GCC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
#define CPU_FEATURES_COMPILER_MSC
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Cpp
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
#define CPU_FEATURES_START_CPP_NAMESPACE \
|
||||||
|
namespace cpu_features { \
|
||||||
|
extern "C" {
|
||||||
|
#define CPU_FEATURES_END_CPP_NAMESPACE \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
#define CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Compiler flags
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
// Use the following to check if a feature is known to be available at
|
||||||
|
// compile time. See README.md for an example.
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
|
||||||
|
#if defined(__AES__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AES 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AES 0
|
||||||
|
#endif // defined(__AES__)
|
||||||
|
|
||||||
|
#if defined(__F16C__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_F16C 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_F16C 0
|
||||||
|
#endif // defined(__F16C__)
|
||||||
|
|
||||||
|
#if defined(__BMI__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_BMI 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_BMI 0
|
||||||
|
#endif // defined(__BMI__)
|
||||||
|
|
||||||
|
#if defined(__BMI2__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_BMI2 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_BMI2 0
|
||||||
|
#endif // defined(__BMI2__)
|
||||||
|
|
||||||
|
#if (defined(__SSE__) || (_M_IX86_FP >= 1))
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (defined(__SSE2__) || (_M_IX86_FP >= 2))
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE2 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE2 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SSE3__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE3 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE3 0
|
||||||
|
#endif // defined(__SSE3__)
|
||||||
|
|
||||||
|
#if defined(__SSSE3__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSSE3 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSSE3 0
|
||||||
|
#endif // defined(__SSSE3__)
|
||||||
|
|
||||||
|
#if defined(__SSE4_1__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE4_1 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE4_1 0
|
||||||
|
#endif // defined(__SSE4_1__)
|
||||||
|
|
||||||
|
#if defined(__SSE4_2__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE4_2 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_SSE4_2 0
|
||||||
|
#endif // defined(__SSE4_2__)
|
||||||
|
|
||||||
|
#if defined(__AVX__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AVX 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AVX 0
|
||||||
|
#endif // defined(__AVX__)
|
||||||
|
|
||||||
|
#if defined(__AVX2__)
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AVX2 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_X86_AVX2 0
|
||||||
|
#endif // defined(__AVX2__)
|
||||||
|
|
||||||
|
#endif // defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||||
|
#if defined(__ARM_NEON__)
|
||||||
|
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_ANY_ARM_NEON 0
|
||||||
|
#endif // defined(__ARM_NEON__)
|
||||||
|
#endif // defined(CPU_FEATURES_ARCH_ANY_ARM)
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
#if defined(__mips_msa)
|
||||||
|
#define CPU_FEATURES_COMPILED_MIPS_MSA 1
|
||||||
|
#else
|
||||||
|
#define CPU_FEATURES_COMPILED_MIPS_MSA 0
|
||||||
|
#endif // defined(__mips_msa)
|
||||||
|
#endif // defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPU_FEATURES_MACROS_H_
|
||||||
|
|
@ -0,0 +1,156 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int fp : 1; // Floating-point.
|
||||||
|
int asimd : 1; // Advanced SIMD.
|
||||||
|
int evtstrm : 1; // Generic timer generated events.
|
||||||
|
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
|
||||||
|
int pmull : 1; // Polynomial multiply long.
|
||||||
|
int sha1 : 1; // Hardware-accelerated SHA1.
|
||||||
|
int sha2 : 1; // Hardware-accelerated SHA2-256.
|
||||||
|
int crc32 : 1; // Hardware-accelerated CRC-32.
|
||||||
|
int atomics : 1; // Armv8.1 atomic instructions.
|
||||||
|
int fphp : 1; // Half-precision floating point support.
|
||||||
|
int asimdhp : 1; // Advanced SIMD half-precision support.
|
||||||
|
int cpuid : 1; // Access to certain ID registers.
|
||||||
|
int asimdrdm : 1; // Rounding Double Multiply Accumulate/Subtract.
|
||||||
|
int jscvt : 1; // Support for JavaScript conversion.
|
||||||
|
int fcma : 1; // Floating point complex numbers.
|
||||||
|
int lrcpc : 1; // Support for weaker release consistency.
|
||||||
|
int dcpop : 1; // Data persistence writeback.
|
||||||
|
int sha3 : 1; // Hardware-accelerated SHA3.
|
||||||
|
int sm3 : 1; // Hardware-accelerated SM3.
|
||||||
|
int sm4 : 1; // Hardware-accelerated SM4.
|
||||||
|
int asimddp : 1; // Dot product instruction.
|
||||||
|
int sha512 : 1; // Hardware-accelerated SHA512.
|
||||||
|
int sve : 1; // Scalable Vector Extension.
|
||||||
|
int asimdfhm : 1; // Additional half-precision instructions.
|
||||||
|
int dit : 1; // Data independent timing.
|
||||||
|
int uscat : 1; // Unaligned atomics support.
|
||||||
|
int ilrcpc : 1; // Additional support for weaker release consistency.
|
||||||
|
int flagm : 1; // Flag manipulation instructions.
|
||||||
|
int ssbs : 1; // Speculative Store Bypass Safe PSTATE bit.
|
||||||
|
int sb : 1; // Speculation barrier.
|
||||||
|
int paca : 1; // Address authentication.
|
||||||
|
int pacg : 1; // Generic authentication.
|
||||||
|
int dcpodp : 1; // Data cache clean to point of persistence.
|
||||||
|
int sve2 : 1; // Scalable Vector Extension (version 2).
|
||||||
|
int sveaes : 1; // SVE AES instructions.
|
||||||
|
int svepmull : 1; // SVE polynomial multiply long instructions.
|
||||||
|
int svebitperm : 1; // SVE bit permute instructions.
|
||||||
|
int svesha3 : 1; // SVE SHA3 instructions.
|
||||||
|
int svesm4 : 1; // SVE SM4 instructions.
|
||||||
|
int flagm2 : 1; // Additional flag manipulation instructions.
|
||||||
|
int frint : 1; // Floating point to integer rounding.
|
||||||
|
int svei8mm : 1; // SVE Int8 matrix multiplication instructions.
|
||||||
|
int svef32mm : 1; // SVE FP32 matrix multiplication instruction.
|
||||||
|
int svef64mm : 1; // SVE FP64 matrix multiplication instructions.
|
||||||
|
int svebf16 : 1; // SVE BFloat16 instructions.
|
||||||
|
int i8mm : 1; // Int8 matrix multiplication instructions.
|
||||||
|
int bf16 : 1; // BFloat16 instructions.
|
||||||
|
int dgh : 1; // Data Gathering Hint instruction.
|
||||||
|
int rng : 1; // True random number generator support.
|
||||||
|
int bti : 1; // Branch target identification.
|
||||||
|
|
||||||
|
// Make sure to update Aarch64FeaturesEnum below if you add a field here.
|
||||||
|
} Aarch64Features;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
Aarch64Features features;
|
||||||
|
int implementer;
|
||||||
|
int variant;
|
||||||
|
int part;
|
||||||
|
int revision;
|
||||||
|
} Aarch64Info;
|
||||||
|
|
||||||
|
Aarch64Info GetAarch64Info(void);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AARCH64_FP,
|
||||||
|
AARCH64_ASIMD,
|
||||||
|
AARCH64_EVTSTRM,
|
||||||
|
AARCH64_AES,
|
||||||
|
AARCH64_PMULL,
|
||||||
|
AARCH64_SHA1,
|
||||||
|
AARCH64_SHA2,
|
||||||
|
AARCH64_CRC32,
|
||||||
|
AARCH64_ATOMICS,
|
||||||
|
AARCH64_FPHP,
|
||||||
|
AARCH64_ASIMDHP,
|
||||||
|
AARCH64_CPUID,
|
||||||
|
AARCH64_ASIMDRDM,
|
||||||
|
AARCH64_JSCVT,
|
||||||
|
AARCH64_FCMA,
|
||||||
|
AARCH64_LRCPC,
|
||||||
|
AARCH64_DCPOP,
|
||||||
|
AARCH64_SHA3,
|
||||||
|
AARCH64_SM3,
|
||||||
|
AARCH64_SM4,
|
||||||
|
AARCH64_ASIMDDP,
|
||||||
|
AARCH64_SHA512,
|
||||||
|
AARCH64_SVE,
|
||||||
|
AARCH64_ASIMDFHM,
|
||||||
|
AARCH64_DIT,
|
||||||
|
AARCH64_USCAT,
|
||||||
|
AARCH64_ILRCPC,
|
||||||
|
AARCH64_FLAGM,
|
||||||
|
AARCH64_SSBS,
|
||||||
|
AARCH64_SB,
|
||||||
|
AARCH64_PACA,
|
||||||
|
AARCH64_PACG,
|
||||||
|
AARCH64_DCPODP,
|
||||||
|
AARCH64_SVE2,
|
||||||
|
AARCH64_SVEAES,
|
||||||
|
AARCH64_SVEPMULL,
|
||||||
|
AARCH64_SVEBITPERM,
|
||||||
|
AARCH64_SVESHA3,
|
||||||
|
AARCH64_SVESM4,
|
||||||
|
AARCH64_FLAGM2,
|
||||||
|
AARCH64_FRINT,
|
||||||
|
AARCH64_SVEI8MM,
|
||||||
|
AARCH64_SVEF32MM,
|
||||||
|
AARCH64_SVEF64MM,
|
||||||
|
AARCH64_SVEBF16,
|
||||||
|
AARCH64_I8MM,
|
||||||
|
AARCH64_BF16,
|
||||||
|
AARCH64_DGH,
|
||||||
|
AARCH64_RNG,
|
||||||
|
AARCH64_BTI,
|
||||||
|
AARCH64_LAST_,
|
||||||
|
} Aarch64FeaturesEnum;
|
||||||
|
|
||||||
|
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
|
||||||
|
Aarch64FeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
#error "Including cpuinfo_aarch64.h from a non-aarch64 target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_AARCH64_H_
|
||||||
|
|
@ -0,0 +1,121 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||||
|
|
||||||
|
#include <stdint.h> // uint32_t
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int swp : 1; // SWP instruction (atomic read-modify-write)
|
||||||
|
int half : 1; // Half-word loads and stores
|
||||||
|
int thumb : 1; // Thumb (16-bit instruction set)
|
||||||
|
int _26bit : 1; // "26 Bit" Model (Processor status register folded into
|
||||||
|
// program counter)
|
||||||
|
int fastmult : 1; // 32x32->64-bit multiplication
|
||||||
|
int fpa : 1; // Floating point accelerator
|
||||||
|
int vfp : 1; // Vector Floating Point.
|
||||||
|
int edsp : 1; // DSP extensions (the 'e' variant of the ARM9 CPUs, and all
|
||||||
|
// others above)
|
||||||
|
int java : 1; // Jazelle (Java bytecode accelerator)
|
||||||
|
int iwmmxt : 1; // Intel Wireless MMX Technology.
|
||||||
|
int crunch : 1; // MaverickCrunch coprocessor
|
||||||
|
int thumbee : 1; // ThumbEE
|
||||||
|
int neon : 1; // Advanced SIMD.
|
||||||
|
int vfpv3 : 1; // VFP version 3
|
||||||
|
int vfpv3d16 : 1; // VFP version 3 with 16 D-registers
|
||||||
|
int tls : 1; // TLS register
|
||||||
|
int vfpv4 : 1; // VFP version 4 with fast context switching
|
||||||
|
int idiva : 1; // SDIV and UDIV hardware division in ARM mode.
|
||||||
|
int idivt : 1; // SDIV and UDIV hardware division in Thumb mode.
|
||||||
|
int vfpd32 : 1; // VFP with 32 D-registers
|
||||||
|
int lpae : 1; // Large Physical Address Extension (>4GB physical memory on
|
||||||
|
// 32-bit architecture)
|
||||||
|
int evtstrm : 1; // kernel event stream using generic architected timer
|
||||||
|
int aes : 1; // Hardware-accelerated Advanced Encryption Standard.
|
||||||
|
int pmull : 1; // Polynomial multiply long.
|
||||||
|
int sha1 : 1; // Hardware-accelerated SHA1.
|
||||||
|
int sha2 : 1; // Hardware-accelerated SHA2-256.
|
||||||
|
int crc32 : 1; // Hardware-accelerated CRC-32.
|
||||||
|
|
||||||
|
// Make sure to update ArmFeaturesEnum below if you add a field here.
|
||||||
|
} ArmFeatures;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
ArmFeatures features;
|
||||||
|
int implementer;
|
||||||
|
int architecture;
|
||||||
|
int variant;
|
||||||
|
int part;
|
||||||
|
int revision;
|
||||||
|
} ArmInfo;
|
||||||
|
|
||||||
|
// TODO(user): Add macros to know which features are present at compile
|
||||||
|
// time.
|
||||||
|
|
||||||
|
ArmInfo GetArmInfo(void);
|
||||||
|
|
||||||
|
// Compute CpuId from ArmInfo.
|
||||||
|
uint32_t GetArmCpuId(const ArmInfo* const info);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
ARM_SWP,
|
||||||
|
ARM_HALF,
|
||||||
|
ARM_THUMB,
|
||||||
|
ARM_26BIT,
|
||||||
|
ARM_FASTMULT,
|
||||||
|
ARM_FPA,
|
||||||
|
ARM_VFP,
|
||||||
|
ARM_EDSP,
|
||||||
|
ARM_JAVA,
|
||||||
|
ARM_IWMMXT,
|
||||||
|
ARM_CRUNCH,
|
||||||
|
ARM_THUMBEE,
|
||||||
|
ARM_NEON,
|
||||||
|
ARM_VFPV3,
|
||||||
|
ARM_VFPV3D16,
|
||||||
|
ARM_TLS,
|
||||||
|
ARM_VFPV4,
|
||||||
|
ARM_IDIVA,
|
||||||
|
ARM_IDIVT,
|
||||||
|
ARM_VFPD32,
|
||||||
|
ARM_LPAE,
|
||||||
|
ARM_EVTSTRM,
|
||||||
|
ARM_AES,
|
||||||
|
ARM_PMULL,
|
||||||
|
ARM_SHA1,
|
||||||
|
ARM_SHA2,
|
||||||
|
ARM_CRC32,
|
||||||
|
ARM_LAST_,
|
||||||
|
} ArmFeaturesEnum;
|
||||||
|
|
||||||
|
int GetArmFeaturesEnumValue(const ArmFeatures* features, ArmFeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetArmFeaturesEnumName(ArmFeaturesEnum);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
#error "Including cpuinfo_arm.h from a non-arm target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_ARM_H_
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int msa : 1; // MIPS SIMD Architecture
|
||||||
|
// https://www.mips.com/products/architectures/ase/simd/
|
||||||
|
int eva : 1; // Enhanced Virtual Addressing
|
||||||
|
// https://www.mips.com/products/architectures/mips64/
|
||||||
|
int r6 : 1; // True if is release 6 of the processor.
|
||||||
|
|
||||||
|
// Make sure to update MipsFeaturesEnum below if you add a field here.
|
||||||
|
} MipsFeatures;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
MipsFeatures features;
|
||||||
|
} MipsInfo;
|
||||||
|
|
||||||
|
MipsInfo GetMipsInfo(void);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
MIPS_MSA,
|
||||||
|
MIPS_EVA,
|
||||||
|
MIPS_R6,
|
||||||
|
MIPS_LAST_,
|
||||||
|
} MipsFeaturesEnum;
|
||||||
|
|
||||||
|
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
|
||||||
|
MipsFeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
#error "Including cpuinfo_mips.h from a non-mips target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_MIPS_H_
|
||||||
|
|
@ -0,0 +1,146 @@
|
||||||
|
// Copyright 2018 IBM
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int ppc32 : 1;
|
||||||
|
int ppc64 : 1;
|
||||||
|
int ppc601 : 1;
|
||||||
|
int altivec : 1;
|
||||||
|
int fpu : 1;
|
||||||
|
int mmu : 1;
|
||||||
|
int mac_4xx : 1;
|
||||||
|
int unifiedcache : 1;
|
||||||
|
int spe : 1;
|
||||||
|
int efpsingle : 1;
|
||||||
|
int efpdouble : 1;
|
||||||
|
int no_tb : 1;
|
||||||
|
int power4 : 1;
|
||||||
|
int power5 : 1;
|
||||||
|
int power5plus : 1;
|
||||||
|
int cell : 1;
|
||||||
|
int booke : 1;
|
||||||
|
int smt : 1;
|
||||||
|
int icachesnoop : 1;
|
||||||
|
int arch205 : 1;
|
||||||
|
int pa6t : 1;
|
||||||
|
int dfp : 1;
|
||||||
|
int power6ext : 1;
|
||||||
|
int arch206 : 1;
|
||||||
|
int vsx : 1;
|
||||||
|
int pseries_perfmon_compat : 1;
|
||||||
|
int truele : 1;
|
||||||
|
int ppcle : 1;
|
||||||
|
int arch207 : 1;
|
||||||
|
int htm : 1;
|
||||||
|
int dscr : 1;
|
||||||
|
int ebb : 1;
|
||||||
|
int isel : 1;
|
||||||
|
int tar : 1;
|
||||||
|
int vcrypto : 1;
|
||||||
|
int htm_nosc : 1;
|
||||||
|
int arch300 : 1;
|
||||||
|
int ieee128 : 1;
|
||||||
|
int darn : 1;
|
||||||
|
int scv : 1;
|
||||||
|
int htm_no_suspend : 1;
|
||||||
|
|
||||||
|
// Make sure to update PPCFeaturesEnum below if you add a field here.
|
||||||
|
} PPCFeatures;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
PPCFeatures features;
|
||||||
|
} PPCInfo;
|
||||||
|
|
||||||
|
// This function is guaranteed to be malloc, memset and memcpy free.
|
||||||
|
PPCInfo GetPPCInfo(void);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char platform[64]; // 0 terminated string
|
||||||
|
char model[64]; // 0 terminated string
|
||||||
|
char machine[64]; // 0 terminated string
|
||||||
|
char cpu[64]; // 0 terminated string
|
||||||
|
PlatformType type;
|
||||||
|
} PPCPlatformStrings;
|
||||||
|
|
||||||
|
PPCPlatformStrings GetPPCPlatformStrings(void);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PPC_32, /* 32 bit mode execution */
|
||||||
|
PPC_64, /* 64 bit mode execution */
|
||||||
|
PPC_601_INSTR, /* Old POWER ISA */
|
||||||
|
PPC_HAS_ALTIVEC, /* SIMD Unit*/
|
||||||
|
PPC_HAS_FPU, /* Floating Point Unit */
|
||||||
|
PPC_HAS_MMU, /* Memory management unit */
|
||||||
|
PPC_HAS_4xxMAC,
|
||||||
|
PPC_UNIFIED_CACHE, /* Unified instruction and data cache */
|
||||||
|
PPC_HAS_SPE, /* Signal processing extention unit */
|
||||||
|
PPC_HAS_EFP_SINGLE, /* SPE single precision fpu */
|
||||||
|
PPC_HAS_EFP_DOUBLE, /* SPE double precision fpu */
|
||||||
|
PPC_NO_TB, /* No timebase */
|
||||||
|
PPC_POWER4,
|
||||||
|
PPC_POWER5,
|
||||||
|
PPC_POWER5_PLUS,
|
||||||
|
PPC_CELL, /* Cell broadband engine */
|
||||||
|
PPC_BOOKE, /* Embedded ISA */
|
||||||
|
PPC_SMT, /* Simultaneous multi-threading */
|
||||||
|
PPC_ICACHE_SNOOP,
|
||||||
|
PPC_ARCH_2_05, /* ISA 2.05 - POWER6 */
|
||||||
|
PPC_PA6T, /* PA Semi 6T core ISA */
|
||||||
|
PPC_HAS_DFP, /* Decimal floating point unit */
|
||||||
|
PPC_POWER6_EXT,
|
||||||
|
PPC_ARCH_2_06, /* ISA 2.06 - POWER7 */
|
||||||
|
PPC_HAS_VSX, /* Vector-scalar extension */
|
||||||
|
PPC_PSERIES_PERFMON_COMPAT, /* Set of backwards compatibile performance
|
||||||
|
monitoring events */
|
||||||
|
PPC_TRUE_LE,
|
||||||
|
PPC_PPC_LE,
|
||||||
|
PPC_ARCH_2_07, /* ISA 2.07 - POWER8 */
|
||||||
|
PPC_HTM, /* Hardware Transactional Memory */
|
||||||
|
PPC_DSCR, /* Data stream control register */
|
||||||
|
PPC_EBB, /* Event base branching */
|
||||||
|
PPC_ISEL, /* Integer select instructions */
|
||||||
|
PPC_TAR, /* Target address register */
|
||||||
|
PPC_VEC_CRYPTO, /* Vector cryptography instructions */
|
||||||
|
PPC_HTM_NOSC, /* Transactions aborted when syscall made*/
|
||||||
|
PPC_ARCH_3_00, /* ISA 3.00 - POWER9 */
|
||||||
|
PPC_HAS_IEEE128, /* VSX IEEE Binary Float 128-bit */
|
||||||
|
PPC_DARN, /* Deliver a random number instruction */
|
||||||
|
PPC_SCV, /* scv syscall */
|
||||||
|
PPC_HTM_NO_SUSPEND, /* TM w/out suspended state */
|
||||||
|
PPC_LAST_,
|
||||||
|
} PPCFeaturesEnum;
|
||||||
|
|
||||||
|
int GetPPCFeaturesEnumValue(const PPCFeatures* features, PPCFeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
#error "Including cpuinfo_ppc.h from a non-ppc target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_PPC_H_
|
||||||
|
|
@ -0,0 +1,231 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
// Copyright 2020 Intel Corporation
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||||
|
|
||||||
|
#include "cpu_features_cache_info.h"
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
// See https://en.wikipedia.org/wiki/CPUID for a list of x86 cpu features.
|
||||||
|
// The field names are based on the short name provided in the wikipedia tables.
|
||||||
|
typedef struct {
|
||||||
|
int fpu : 1;
|
||||||
|
int tsc : 1;
|
||||||
|
int cx8 : 1;
|
||||||
|
int clfsh : 1;
|
||||||
|
int mmx : 1;
|
||||||
|
int aes : 1;
|
||||||
|
int erms : 1;
|
||||||
|
int f16c : 1;
|
||||||
|
int fma4 : 1;
|
||||||
|
int fma3 : 1;
|
||||||
|
int vaes : 1;
|
||||||
|
int vpclmulqdq : 1;
|
||||||
|
int bmi1 : 1;
|
||||||
|
int hle : 1;
|
||||||
|
int bmi2 : 1;
|
||||||
|
int rtm : 1;
|
||||||
|
int rdseed : 1;
|
||||||
|
int clflushopt : 1;
|
||||||
|
int clwb : 1;
|
||||||
|
|
||||||
|
int sse : 1;
|
||||||
|
int sse2 : 1;
|
||||||
|
int sse3 : 1;
|
||||||
|
int ssse3 : 1;
|
||||||
|
int sse4_1 : 1;
|
||||||
|
int sse4_2 : 1;
|
||||||
|
int sse4a : 1;
|
||||||
|
|
||||||
|
int avx : 1;
|
||||||
|
int avx2 : 1;
|
||||||
|
|
||||||
|
int avx512f : 1;
|
||||||
|
int avx512cd : 1;
|
||||||
|
int avx512er : 1;
|
||||||
|
int avx512pf : 1;
|
||||||
|
int avx512bw : 1;
|
||||||
|
int avx512dq : 1;
|
||||||
|
int avx512vl : 1;
|
||||||
|
int avx512ifma : 1;
|
||||||
|
int avx512vbmi : 1;
|
||||||
|
int avx512vbmi2 : 1;
|
||||||
|
int avx512vnni : 1;
|
||||||
|
int avx512bitalg : 1;
|
||||||
|
int avx512vpopcntdq : 1;
|
||||||
|
int avx512_4vnniw : 1;
|
||||||
|
int avx512_4vbmi2 : 1;
|
||||||
|
int avx512_second_fma : 1;
|
||||||
|
int avx512_4fmaps : 1;
|
||||||
|
int avx512_bf16 : 1;
|
||||||
|
int avx512_vp2intersect : 1;
|
||||||
|
int amx_bf16 : 1;
|
||||||
|
int amx_tile : 1;
|
||||||
|
int amx_int8 : 1;
|
||||||
|
|
||||||
|
int pclmulqdq : 1;
|
||||||
|
int smx : 1;
|
||||||
|
int sgx : 1;
|
||||||
|
int cx16 : 1; // aka. CMPXCHG16B
|
||||||
|
int sha : 1;
|
||||||
|
int popcnt : 1;
|
||||||
|
int movbe : 1;
|
||||||
|
int rdrnd : 1;
|
||||||
|
|
||||||
|
int dca : 1;
|
||||||
|
int ss : 1;
|
||||||
|
// Make sure to update X86FeaturesEnum below if you add a field here.
|
||||||
|
} X86Features;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
X86Features features;
|
||||||
|
int family;
|
||||||
|
int model;
|
||||||
|
int stepping;
|
||||||
|
char vendor[13]; // 0 terminated string
|
||||||
|
} X86Info;
|
||||||
|
|
||||||
|
// Calls cpuid and returns an initialized X86info.
|
||||||
|
// This function is guaranteed to be malloc, memset and memcpy free.
|
||||||
|
X86Info GetX86Info(void);
|
||||||
|
|
||||||
|
// Returns cache hierarchy informations.
|
||||||
|
// Can call cpuid multiple times.
|
||||||
|
// Only works on Intel CPU at the moment.
|
||||||
|
// This function is guaranteed to be malloc, memset and memcpy free.
|
||||||
|
CacheInfo GetX86CacheInfo(void);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
X86_UNKNOWN,
|
||||||
|
INTEL_CORE, // CORE
|
||||||
|
INTEL_PNR, // PENRYN
|
||||||
|
INTEL_NHM, // NEHALEM
|
||||||
|
INTEL_ATOM_BNL, // BONNELL
|
||||||
|
INTEL_WSM, // WESTMERE
|
||||||
|
INTEL_SNB, // SANDYBRIDGE
|
||||||
|
INTEL_IVB, // IVYBRIDGE
|
||||||
|
INTEL_ATOM_SMT, // SILVERMONT
|
||||||
|
INTEL_HSW, // HASWELL
|
||||||
|
INTEL_BDW, // BROADWELL
|
||||||
|
INTEL_SKL, // SKYLAKE
|
||||||
|
INTEL_ATOM_GMT, // GOLDMONT
|
||||||
|
INTEL_KBL, // KABY LAKE
|
||||||
|
INTEL_CFL, // COFFEE LAKE
|
||||||
|
INTEL_WHL, // WHISKEY LAKE
|
||||||
|
INTEL_CNL, // CANNON LAKE
|
||||||
|
INTEL_ICL, // ICE LAKE
|
||||||
|
INTEL_TGL, // TIGER LAKE
|
||||||
|
INTEL_SPR, // SAPPHIRE RAPIDS
|
||||||
|
AMD_HAMMER, // K8
|
||||||
|
AMD_K10, // K10
|
||||||
|
AMD_BOBCAT, // K14
|
||||||
|
AMD_BULLDOZER, // K15
|
||||||
|
AMD_JAGUAR, // K16
|
||||||
|
AMD_ZEN, // K17
|
||||||
|
} X86Microarchitecture;
|
||||||
|
|
||||||
|
// Returns the underlying microarchitecture by looking at X86Info's vendor,
|
||||||
|
// family and model.
|
||||||
|
X86Microarchitecture GetX86Microarchitecture(const X86Info* info);
|
||||||
|
|
||||||
|
// Calls cpuid and fills the brand_string.
|
||||||
|
// - brand_string *must* be of size 49 (beware of array decaying).
|
||||||
|
// - brand_string will be zero terminated.
|
||||||
|
// - This function calls memcpy.
|
||||||
|
void FillX86BrandString(char brand_string[49]);
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
X86_FPU,
|
||||||
|
X86_TSC,
|
||||||
|
X86_CX8,
|
||||||
|
X86_CLFSH,
|
||||||
|
X86_MMX,
|
||||||
|
X86_AES,
|
||||||
|
X86_ERMS,
|
||||||
|
X86_F16C,
|
||||||
|
X86_FMA4,
|
||||||
|
X86_FMA3,
|
||||||
|
X86_VAES,
|
||||||
|
X86_VPCLMULQDQ,
|
||||||
|
X86_BMI1,
|
||||||
|
X86_HLE,
|
||||||
|
X86_BMI2,
|
||||||
|
X86_RTM,
|
||||||
|
X86_RDSEED,
|
||||||
|
X86_CLFLUSHOPT,
|
||||||
|
X86_CLWB,
|
||||||
|
X86_SSE,
|
||||||
|
X86_SSE2,
|
||||||
|
X86_SSE3,
|
||||||
|
X86_SSSE3,
|
||||||
|
X86_SSE4_1,
|
||||||
|
X86_SSE4_2,
|
||||||
|
X86_SSE4A,
|
||||||
|
X86_AVX,
|
||||||
|
X86_AVX2,
|
||||||
|
X86_AVX512F,
|
||||||
|
X86_AVX512CD,
|
||||||
|
X86_AVX512ER,
|
||||||
|
X86_AVX512PF,
|
||||||
|
X86_AVX512BW,
|
||||||
|
X86_AVX512DQ,
|
||||||
|
X86_AVX512VL,
|
||||||
|
X86_AVX512IFMA,
|
||||||
|
X86_AVX512VBMI,
|
||||||
|
X86_AVX512VBMI2,
|
||||||
|
X86_AVX512VNNI,
|
||||||
|
X86_AVX512BITALG,
|
||||||
|
X86_AVX512VPOPCNTDQ,
|
||||||
|
X86_AVX512_4VNNIW,
|
||||||
|
X86_AVX512_4VBMI2,
|
||||||
|
X86_AVX512_SECOND_FMA,
|
||||||
|
X86_AVX512_4FMAPS,
|
||||||
|
X86_AVX512_BF16,
|
||||||
|
X86_AVX512_VP2INTERSECT,
|
||||||
|
X86_AMX_BF16,
|
||||||
|
X86_AMX_TILE,
|
||||||
|
X86_AMX_INT8,
|
||||||
|
X86_PCLMULQDQ,
|
||||||
|
X86_SMX,
|
||||||
|
X86_SGX,
|
||||||
|
X86_CX16,
|
||||||
|
X86_SHA,
|
||||||
|
X86_POPCNT,
|
||||||
|
X86_MOVBE,
|
||||||
|
X86_RDRND,
|
||||||
|
X86_DCA,
|
||||||
|
X86_SS,
|
||||||
|
X86_LAST_,
|
||||||
|
} X86FeaturesEnum;
|
||||||
|
|
||||||
|
int GetX86FeaturesEnumValue(const X86Features* features, X86FeaturesEnum value);
|
||||||
|
|
||||||
|
const char* GetX86FeaturesEnumName(X86FeaturesEnum);
|
||||||
|
|
||||||
|
const char* GetX86MicroarchitectureName(X86Microarchitecture);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#if !defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
#error "Including cpuinfo_x86.h from a non-x86 target."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_CPUINFO_X86_H_
|
||||||
|
|
@ -0,0 +1,40 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
inline static bool IsBitSet(uint32_t reg, uint32_t bit) {
|
||||||
|
return (reg >> bit) & 0x1;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static uint32_t ExtractBitRange(uint32_t reg, uint32_t msb,
|
||||||
|
uint32_t lsb) {
|
||||||
|
const uint64_t bits = msb - lsb + 1ULL;
|
||||||
|
const uint64_t mask = (1ULL << bits) - 1ULL;
|
||||||
|
assert(msb >= lsb);
|
||||||
|
return (reg >> lsb) & mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_BIT_UTILS_H_
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
// A struct to hold the result of a call to cpuid.
|
||||||
|
typedef struct {
|
||||||
|
uint32_t eax, ebx, ecx, edx;
|
||||||
|
} Leaf;
|
||||||
|
|
||||||
|
// Returns the result of a call to the cpuid instruction.
|
||||||
|
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx);
|
||||||
|
|
||||||
|
// Returns the eax value of the XCR0 register.
|
||||||
|
uint32_t GetXCR0Eax(void);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_CPUID_X86_H_
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// An interface for the filesystem that allows mocking the filesystem in
|
||||||
|
// unittests.
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
// Same as linux "open(filename, O_RDONLY)", retries automatically on EINTR.
|
||||||
|
int CpuFeatures_OpenFile(const char* filename);
|
||||||
|
|
||||||
|
// Same as linux "read(file_descriptor, buffer, buffer_size)", retries
|
||||||
|
// automatically on EINTR.
|
||||||
|
int CpuFeatures_ReadFile(int file_descriptor, void* buffer, size_t buffer_size);
|
||||||
|
|
||||||
|
// Same as linux "close(file_descriptor)".
|
||||||
|
void CpuFeatures_CloseFile(int file_descriptor);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_FILESYSTEM_H_
|
||||||
|
|
@ -0,0 +1,186 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Interface to retrieve hardware capabilities. It relies on Linux's getauxval
|
||||||
|
// or `/proc/self/auxval` under the hood.
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
// To avoid depending on the linux kernel we reproduce the architecture specific
|
||||||
|
// constants here.
|
||||||
|
|
||||||
|
// http://elixir.free-electrons.com/linux/latest/source/arch/arm64/include/uapi/asm/hwcap.h
|
||||||
|
#define AARCH64_HWCAP_FP (1UL << 0)
|
||||||
|
#define AARCH64_HWCAP_ASIMD (1UL << 1)
|
||||||
|
#define AARCH64_HWCAP_EVTSTRM (1UL << 2)
|
||||||
|
#define AARCH64_HWCAP_AES (1UL << 3)
|
||||||
|
#define AARCH64_HWCAP_PMULL (1UL << 4)
|
||||||
|
#define AARCH64_HWCAP_SHA1 (1UL << 5)
|
||||||
|
#define AARCH64_HWCAP_SHA2 (1UL << 6)
|
||||||
|
#define AARCH64_HWCAP_CRC32 (1UL << 7)
|
||||||
|
#define AARCH64_HWCAP_ATOMICS (1UL << 8)
|
||||||
|
#define AARCH64_HWCAP_FPHP (1UL << 9)
|
||||||
|
#define AARCH64_HWCAP_ASIMDHP (1UL << 10)
|
||||||
|
#define AARCH64_HWCAP_CPUID (1UL << 11)
|
||||||
|
#define AARCH64_HWCAP_ASIMDRDM (1UL << 12)
|
||||||
|
#define AARCH64_HWCAP_JSCVT (1UL << 13)
|
||||||
|
#define AARCH64_HWCAP_FCMA (1UL << 14)
|
||||||
|
#define AARCH64_HWCAP_LRCPC (1UL << 15)
|
||||||
|
#define AARCH64_HWCAP_DCPOP (1UL << 16)
|
||||||
|
#define AARCH64_HWCAP_SHA3 (1UL << 17)
|
||||||
|
#define AARCH64_HWCAP_SM3 (1UL << 18)
|
||||||
|
#define AARCH64_HWCAP_SM4 (1UL << 19)
|
||||||
|
#define AARCH64_HWCAP_ASIMDDP (1UL << 20)
|
||||||
|
#define AARCH64_HWCAP_SHA512 (1UL << 21)
|
||||||
|
#define AARCH64_HWCAP_SVE (1UL << 22)
|
||||||
|
#define AARCH64_HWCAP_ASIMDFHM (1UL << 23)
|
||||||
|
#define AARCH64_HWCAP_DIT (1UL << 24)
|
||||||
|
#define AARCH64_HWCAP_USCAT (1UL << 25)
|
||||||
|
#define AARCH64_HWCAP_ILRCPC (1UL << 26)
|
||||||
|
#define AARCH64_HWCAP_FLAGM (1UL << 27)
|
||||||
|
#define AARCH64_HWCAP_SSBS (1UL << 28)
|
||||||
|
#define AARCH64_HWCAP_SB (1UL << 29)
|
||||||
|
#define AARCH64_HWCAP_PACA (1UL << 30)
|
||||||
|
#define AARCH64_HWCAP_PACG (1UL << 31)
|
||||||
|
|
||||||
|
#define AARCH64_HWCAP2_DCPODP (1UL << 0)
|
||||||
|
#define AARCH64_HWCAP2_SVE2 (1UL << 1)
|
||||||
|
#define AARCH64_HWCAP2_SVEAES (1UL << 2)
|
||||||
|
#define AARCH64_HWCAP2_SVEPMULL (1UL << 3)
|
||||||
|
#define AARCH64_HWCAP2_SVEBITPERM (1UL << 4)
|
||||||
|
#define AARCH64_HWCAP2_SVESHA3 (1UL << 5)
|
||||||
|
#define AARCH64_HWCAP2_SVESM4 (1UL << 6)
|
||||||
|
#define AARCH64_HWCAP2_FLAGM2 (1UL << 7)
|
||||||
|
#define AARCH64_HWCAP2_FRINT (1UL << 8)
|
||||||
|
#define AARCH64_HWCAP2_SVEI8MM (1UL << 9)
|
||||||
|
#define AARCH64_HWCAP2_SVEF32MM (1UL << 10)
|
||||||
|
#define AARCH64_HWCAP2_SVEF64MM (1UL << 11)
|
||||||
|
#define AARCH64_HWCAP2_SVEBF16 (1UL << 12)
|
||||||
|
#define AARCH64_HWCAP2_I8MM (1UL << 13)
|
||||||
|
#define AARCH64_HWCAP2_BF16 (1UL << 14)
|
||||||
|
#define AARCH64_HWCAP2_DGH (1UL << 15)
|
||||||
|
#define AARCH64_HWCAP2_RNG (1UL << 16)
|
||||||
|
#define AARCH64_HWCAP2_BTI (1UL << 17)
|
||||||
|
|
||||||
|
// http://elixir.free-electrons.com/linux/latest/source/arch/arm/include/uapi/asm/hwcap.h
|
||||||
|
#define ARM_HWCAP_SWP (1UL << 0)
|
||||||
|
#define ARM_HWCAP_HALF (1UL << 1)
|
||||||
|
#define ARM_HWCAP_THUMB (1UL << 2)
|
||||||
|
#define ARM_HWCAP_26BIT (1UL << 3)
|
||||||
|
#define ARM_HWCAP_FAST_MULT (1UL << 4)
|
||||||
|
#define ARM_HWCAP_FPA (1UL << 5)
|
||||||
|
#define ARM_HWCAP_VFP (1UL << 6)
|
||||||
|
#define ARM_HWCAP_EDSP (1UL << 7)
|
||||||
|
#define ARM_HWCAP_JAVA (1UL << 8)
|
||||||
|
#define ARM_HWCAP_IWMMXT (1UL << 9)
|
||||||
|
#define ARM_HWCAP_CRUNCH (1UL << 10)
|
||||||
|
#define ARM_HWCAP_THUMBEE (1UL << 11)
|
||||||
|
#define ARM_HWCAP_NEON (1UL << 12)
|
||||||
|
#define ARM_HWCAP_VFPV3 (1UL << 13)
|
||||||
|
#define ARM_HWCAP_VFPV3D16 (1UL << 14)
|
||||||
|
#define ARM_HWCAP_TLS (1UL << 15)
|
||||||
|
#define ARM_HWCAP_VFPV4 (1UL << 16)
|
||||||
|
#define ARM_HWCAP_IDIVA (1UL << 17)
|
||||||
|
#define ARM_HWCAP_IDIVT (1UL << 18)
|
||||||
|
#define ARM_HWCAP_VFPD32 (1UL << 19)
|
||||||
|
#define ARM_HWCAP_LPAE (1UL << 20)
|
||||||
|
#define ARM_HWCAP_EVTSTRM (1UL << 21)
|
||||||
|
#define ARM_HWCAP2_AES (1UL << 0)
|
||||||
|
#define ARM_HWCAP2_PMULL (1UL << 1)
|
||||||
|
#define ARM_HWCAP2_SHA1 (1UL << 2)
|
||||||
|
#define ARM_HWCAP2_SHA2 (1UL << 3)
|
||||||
|
#define ARM_HWCAP2_CRC32 (1UL << 4)
|
||||||
|
|
||||||
|
// http://elixir.free-electrons.com/linux/latest/source/arch/mips/include/uapi/asm/hwcap.h
|
||||||
|
#define MIPS_HWCAP_R6 (1UL << 0)
|
||||||
|
#define MIPS_HWCAP_MSA (1UL << 1)
|
||||||
|
#define MIPS_HWCAP_CRC32 (1UL << 2)
|
||||||
|
|
||||||
|
// http://elixir.free-electrons.com/linux/latest/source/arch/powerpc/include/uapi/asm/cputable.h
|
||||||
|
#ifndef _UAPI__ASM_POWERPC_CPUTABLE_H
|
||||||
|
/* in AT_HWCAP */
|
||||||
|
#define PPC_FEATURE_32 0x80000000
|
||||||
|
#define PPC_FEATURE_64 0x40000000
|
||||||
|
#define PPC_FEATURE_601_INSTR 0x20000000
|
||||||
|
#define PPC_FEATURE_HAS_ALTIVEC 0x10000000
|
||||||
|
#define PPC_FEATURE_HAS_FPU 0x08000000
|
||||||
|
#define PPC_FEATURE_HAS_MMU 0x04000000
|
||||||
|
#define PPC_FEATURE_HAS_4xxMAC 0x02000000
|
||||||
|
#define PPC_FEATURE_UNIFIED_CACHE 0x01000000
|
||||||
|
#define PPC_FEATURE_HAS_SPE 0x00800000
|
||||||
|
#define PPC_FEATURE_HAS_EFP_SINGLE 0x00400000
|
||||||
|
#define PPC_FEATURE_HAS_EFP_DOUBLE 0x00200000
|
||||||
|
#define PPC_FEATURE_NO_TB 0x00100000
|
||||||
|
#define PPC_FEATURE_POWER4 0x00080000
|
||||||
|
#define PPC_FEATURE_POWER5 0x00040000
|
||||||
|
#define PPC_FEATURE_POWER5_PLUS 0x00020000
|
||||||
|
#define PPC_FEATURE_CELL 0x00010000
|
||||||
|
#define PPC_FEATURE_BOOKE 0x00008000
|
||||||
|
#define PPC_FEATURE_SMT 0x00004000
|
||||||
|
#define PPC_FEATURE_ICACHE_SNOOP 0x00002000
|
||||||
|
#define PPC_FEATURE_ARCH_2_05 0x00001000
|
||||||
|
#define PPC_FEATURE_PA6T 0x00000800
|
||||||
|
#define PPC_FEATURE_HAS_DFP 0x00000400
|
||||||
|
#define PPC_FEATURE_POWER6_EXT 0x00000200
|
||||||
|
#define PPC_FEATURE_ARCH_2_06 0x00000100
|
||||||
|
#define PPC_FEATURE_HAS_VSX 0x00000080
|
||||||
|
|
||||||
|
#define PPC_FEATURE_PSERIES_PERFMON_COMPAT 0x00000040
|
||||||
|
|
||||||
|
/* Reserved - do not use 0x00000004 */
|
||||||
|
#define PPC_FEATURE_TRUE_LE 0x00000002
|
||||||
|
#define PPC_FEATURE_PPC_LE 0x00000001
|
||||||
|
|
||||||
|
/* in AT_HWCAP2 */
|
||||||
|
#define PPC_FEATURE2_ARCH_2_07 0x80000000
|
||||||
|
#define PPC_FEATURE2_HTM 0x40000000
|
||||||
|
#define PPC_FEATURE2_DSCR 0x20000000
|
||||||
|
#define PPC_FEATURE2_EBB 0x10000000
|
||||||
|
#define PPC_FEATURE2_ISEL 0x08000000
|
||||||
|
#define PPC_FEATURE2_TAR 0x04000000
|
||||||
|
#define PPC_FEATURE2_VEC_CRYPTO 0x02000000
|
||||||
|
#define PPC_FEATURE2_HTM_NOSC 0x01000000
|
||||||
|
#define PPC_FEATURE2_ARCH_3_00 0x00800000
|
||||||
|
#define PPC_FEATURE2_HAS_IEEE128 0x00400000
|
||||||
|
#define PPC_FEATURE2_DARN 0x00200000
|
||||||
|
#define PPC_FEATURE2_SCV 0x00100000
|
||||||
|
#define PPC_FEATURE2_HTM_NO_SUSPEND 0x00080000
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
unsigned long hwcaps;
|
||||||
|
unsigned long hwcaps2;
|
||||||
|
} HardwareCapabilities;
|
||||||
|
|
||||||
|
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
|
||||||
|
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
|
||||||
|
const HardwareCapabilities hwcaps);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char platform[64]; // 0 terminated string
|
||||||
|
char base_platform[64]; // 0 terminated string
|
||||||
|
} PlatformType;
|
||||||
|
|
||||||
|
PlatformType CpuFeatures_GetPlatformType(void);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_HWCAPS_H_
|
||||||
|
|
@ -0,0 +1,49 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Reads a file line by line and stores the data on the stack. This allows
|
||||||
|
// parsing files in one go without allocating.
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
char buffer[STACK_LINE_READER_BUFFER_SIZE];
|
||||||
|
StringView view;
|
||||||
|
int fd;
|
||||||
|
bool skip_mode;
|
||||||
|
} StackLineReader;
|
||||||
|
|
||||||
|
// Initializes a StackLineReader.
|
||||||
|
void StackLineReader_Initialize(StackLineReader* reader, int fd);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
StringView line; // A view of the line.
|
||||||
|
bool eof; // Nothing more to read, we reached EOF.
|
||||||
|
bool full_line; // If false the line was truncated to
|
||||||
|
// STACK_LINE_READER_BUFFER_SIZE.
|
||||||
|
} LineResult;
|
||||||
|
|
||||||
|
// Reads the file pointed to by fd and tries to read a full line.
|
||||||
|
LineResult StackLineReader_NextLine(StackLineReader* reader);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STACK_LINE_READER_H_
|
||||||
|
|
@ -0,0 +1,109 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// A view over a piece of string. The view is not 0 terminated.
|
||||||
|
#ifndef CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||||
|
#define CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
CPU_FEATURES_START_CPP_NAMESPACE
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* ptr;
|
||||||
|
size_t size;
|
||||||
|
} StringView;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
static const StringView kEmptyStringView = {NULL, 0};
|
||||||
|
#else
|
||||||
|
static const StringView kEmptyStringView;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Returns a StringView from the provided string.
|
||||||
|
// Passing NULL is valid only if size is 0.
|
||||||
|
static inline StringView view(const char* str, const size_t size) {
|
||||||
|
StringView view;
|
||||||
|
view.ptr = str;
|
||||||
|
view.size = size;
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline StringView str(const char* str) { return view(str, strlen(str)); }
|
||||||
|
|
||||||
|
// Returns the index of the first occurrence of c in view or -1 if not found.
|
||||||
|
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c);
|
||||||
|
|
||||||
|
// Returns the index of the first occurrence of sub_view in view or -1 if not
|
||||||
|
// found.
|
||||||
|
int CpuFeatures_StringView_IndexOf(const StringView view,
|
||||||
|
const StringView sub_view);
|
||||||
|
|
||||||
|
// Returns whether a is equal to b (same content).
|
||||||
|
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b);
|
||||||
|
|
||||||
|
// Returns whether a starts with b.
|
||||||
|
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b);
|
||||||
|
|
||||||
|
// Removes count characters from the beginning of view or kEmptyStringView if
|
||||||
|
// count if greater than view.size.
|
||||||
|
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
// Removes count characters from the end of view or kEmptyStringView if count if
|
||||||
|
// greater than view.size.
|
||||||
|
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
// Keeps the count first characters of view or view if count if greater than
|
||||||
|
// view.size.
|
||||||
|
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
|
||||||
|
size_t count);
|
||||||
|
|
||||||
|
// Retrieves the first character of view. If view is empty the behavior is
|
||||||
|
// undefined.
|
||||||
|
char CpuFeatures_StringView_Front(const StringView view);
|
||||||
|
|
||||||
|
// Retrieves the last character of view. If view is empty the behavior is
|
||||||
|
// undefined.
|
||||||
|
char CpuFeatures_StringView_Back(const StringView view);
|
||||||
|
|
||||||
|
// Removes leading and tailing space characters.
|
||||||
|
StringView CpuFeatures_StringView_TrimWhitespace(StringView view);
|
||||||
|
|
||||||
|
// Convert StringView to positive integer. e.g. "42", "0x2a".
|
||||||
|
// Returns -1 on error.
|
||||||
|
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view);
|
||||||
|
|
||||||
|
// Copies src StringView to dst buffer.
|
||||||
|
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||||
|
size_t dst_size);
|
||||||
|
|
||||||
|
// Checks if line contains the specified whitespace separated word.
|
||||||
|
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||||
|
const char* const word);
|
||||||
|
|
||||||
|
// Get key/value from line. key and value are separated by ": ".
|
||||||
|
// key and value are cleaned up from leading and trailing whitespaces.
|
||||||
|
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
|
||||||
|
StringView* key,
|
||||||
|
StringView* value);
|
||||||
|
|
||||||
|
CPU_FEATURES_END_CPP_NAMESPACE
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_INCLUDE_INTERNAL_STRING_VIEW_H_
|
||||||
|
|
@ -0,0 +1,60 @@
|
||||||
|
|
||||||
|
#
|
||||||
|
# library : NDK compat
|
||||||
|
#
|
||||||
|
find_package(Threads REQUIRED)
|
||||||
|
set (NDK_COMPAT_HDRS cpu-features.h)
|
||||||
|
set (NDK_COMPAT_SRCS
|
||||||
|
cpu-features.c
|
||||||
|
$<TARGET_OBJECTS:utils>
|
||||||
|
$<TARGET_OBJECTS:unix_based_hardware_detection>
|
||||||
|
)
|
||||||
|
# Note that following `add_cpu_features_headers_and_sources` will use
|
||||||
|
# NDK_COMPAT_SRCS in lieu of NDK_COMPAT_HDRS because we don't want cpu_features
|
||||||
|
# headers to be installed alongside ndk_compat.
|
||||||
|
add_cpu_features_headers_and_sources(NDK_COMPAT_SRCS NDK_COMPAT_SRCS)
|
||||||
|
add_library(ndk_compat ${NDK_COMPAT_HDRS} ${NDK_COMPAT_SRCS})
|
||||||
|
setup_include_and_definitions(ndk_compat)
|
||||||
|
target_include_directories(ndk_compat PUBLIC $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>)
|
||||||
|
target_link_libraries(ndk_compat PUBLIC ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT})
|
||||||
|
set_target_properties(ndk_compat PROPERTIES PUBLIC_HEADER "${NDK_COMPAT_HDRS}")
|
||||||
|
|
||||||
|
include(GNUInstallDirs)
|
||||||
|
install(TARGETS ndk_compat
|
||||||
|
EXPORT CpuFeaturesNdkCompatTargets
|
||||||
|
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/ndk_compat
|
||||||
|
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||||
|
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||||
|
)
|
||||||
|
install(EXPORT CpuFeaturesNdkCompatTargets
|
||||||
|
NAMESPACE CpuFeatures::
|
||||||
|
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
||||||
|
include(CMakePackageConfigHelpers)
|
||||||
|
configure_package_config_file(${PROJECT_SOURCE_DIR}/cmake/CpuFeaturesNdkCompatConfig.cmake.in
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake"
|
||||||
|
INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat"
|
||||||
|
NO_SET_AND_CHECK_MACRO
|
||||||
|
NO_CHECK_REQUIRED_COMPONENTS_MACRO
|
||||||
|
)
|
||||||
|
write_basic_package_version_file(
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake"
|
||||||
|
COMPATIBILITY SameMajorVersion
|
||||||
|
)
|
||||||
|
install(
|
||||||
|
FILES
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfig.cmake"
|
||||||
|
"${PROJECT_BINARY_DIR}/CpuFeaturesNdkCompatConfigVersion.cmake"
|
||||||
|
DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/CpuFeaturesNdkCompat"
|
||||||
|
COMPONENT Devel
|
||||||
|
)
|
||||||
|
|
||||||
|
#
|
||||||
|
# program : NDK compat test program
|
||||||
|
#
|
||||||
|
if(ENABLE_TESTING)
|
||||||
|
add_executable(ndk-compat-test ndk-compat-test.c)
|
||||||
|
target_link_libraries(ndk-compat-test PRIVATE ndk_compat)
|
||||||
|
endif()
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
Provides a header compatible with [android's NDK cpu-features.h](https://android.googlesource.com/platform/ndk/+/master/sources/android/cpufeatures/cpu-features.h).
|
||||||
|
|
||||||
|
It is intended to be a drop in replacement for this header and help users
|
||||||
|
transition from the NDK to [Google's cpu_features library](https://github.com/google/cpu_features).
|
||||||
|
|
@ -0,0 +1,205 @@
|
||||||
|
#include "cpu-features.h"
|
||||||
|
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
#include "cpuinfo_mips.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static pthread_once_t g_once;
|
||||||
|
static int g_inited;
|
||||||
|
static uint64_t g_cpuFeatures;
|
||||||
|
static int g_cpuCount;
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_ARM
|
||||||
|
static uint32_t g_cpuIdArm;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static void set_cpu_mask_bit(uint32_t index, uint32_t* cpu_mask) {
|
||||||
|
*cpu_mask |= 1UL << index;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Examples of valid inputs: "31", "4-31"
|
||||||
|
static void parse_cpu_mask(const StringView text, uint32_t* cpu_mask) {
|
||||||
|
int separator_index = CpuFeatures_StringView_IndexOfChar(text, '-');
|
||||||
|
if (separator_index < 0) { // A single cpu index
|
||||||
|
int cpu_index = CpuFeatures_StringView_ParsePositiveNumber(text);
|
||||||
|
if (cpu_index < 0) return;
|
||||||
|
set_cpu_mask_bit(cpu_index, cpu_mask);
|
||||||
|
} else {
|
||||||
|
int cpu_index_a = CpuFeatures_StringView_ParsePositiveNumber(
|
||||||
|
CpuFeatures_StringView_KeepFront(text, separator_index));
|
||||||
|
int cpu_index_b = CpuFeatures_StringView_ParsePositiveNumber(
|
||||||
|
CpuFeatures_StringView_PopFront(text, separator_index + 1));
|
||||||
|
int i;
|
||||||
|
if (cpu_index_a < 0 || cpu_index_b < 0) return;
|
||||||
|
for (i = cpu_index_a; i <= cpu_index_b; ++i) {
|
||||||
|
if (i < 32) {
|
||||||
|
set_cpu_mask_bit(i, cpu_mask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format specification from
|
||||||
|
// https://www.kernel.org/doc/Documentation/cputopology.txt
|
||||||
|
// Examples of valid inputs: "31", "2,4-31,32-63", "0-1,3"
|
||||||
|
static void parse_cpu_mask_line(const LineResult result, uint32_t* cpu_mask) {
|
||||||
|
if (!result.full_line || result.eof) return;
|
||||||
|
StringView line = result.line;
|
||||||
|
for (; line.size > 0;) {
|
||||||
|
int next_entry_index = CpuFeatures_StringView_IndexOfChar(line, ',');
|
||||||
|
if (next_entry_index < 0) {
|
||||||
|
parse_cpu_mask(line, cpu_mask);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
StringView entry = CpuFeatures_StringView_KeepFront(line, next_entry_index);
|
||||||
|
parse_cpu_mask(entry, cpu_mask);
|
||||||
|
line = CpuFeatures_StringView_PopFront(line, next_entry_index + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void update_cpu_mask_from_file(const char* filename,
|
||||||
|
uint32_t* cpu_mask) {
|
||||||
|
const int fd = CpuFeatures_OpenFile(filename);
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
parse_cpu_mask_line(StackLineReader_NextLine(&reader), cpu_mask);
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int get_cpu_count(void) {
|
||||||
|
uint32_t cpu_mask = 0;
|
||||||
|
update_cpu_mask_from_file("/sys/devices/system/cpu/present", &cpu_mask);
|
||||||
|
update_cpu_mask_from_file("/sys/devices/system/cpu/possible", &cpu_mask);
|
||||||
|
return __builtin_popcount(cpu_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void android_cpuInit(void) {
|
||||||
|
g_cpuFeatures = 0;
|
||||||
|
g_cpuCount = 1;
|
||||||
|
g_inited = 1;
|
||||||
|
|
||||||
|
g_cpuCount = get_cpu_count();
|
||||||
|
if (g_cpuCount == 0) {
|
||||||
|
g_cpuCount = 1;
|
||||||
|
}
|
||||||
|
#if defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
ArmInfo info = GetArmInfo();
|
||||||
|
if (info.architecture == 7) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_ARMv7;
|
||||||
|
if (info.features.vfpv3) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv3;
|
||||||
|
if (info.features.neon) {
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON;
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_D32;
|
||||||
|
}
|
||||||
|
if (info.features.vfpv3d16) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FP16;
|
||||||
|
if (info.features.idiva) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_ARM;
|
||||||
|
if (info.features.idivt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2;
|
||||||
|
if (info.features.iwmmxt) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_iWMMXt;
|
||||||
|
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_AES;
|
||||||
|
if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_PMULL;
|
||||||
|
if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA1;
|
||||||
|
if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_SHA2;
|
||||||
|
if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_CRC32;
|
||||||
|
if (info.architecture >= 6)
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_LDREX_STREX;
|
||||||
|
if (info.features.vfp) g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFPv2;
|
||||||
|
if (info.features.vfpv4) {
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_VFP_FMA;
|
||||||
|
g_cpuFeatures |= ANDROID_CPU_ARM_FEATURE_NEON_FMA;
|
||||||
|
}
|
||||||
|
g_cpuIdArm = GetArmCpuId(&info);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
X86Info info = GetX86Info();
|
||||||
|
if (info.features.ssse3) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSSE3;
|
||||||
|
if (info.features.popcnt) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_POPCNT;
|
||||||
|
if (info.features.movbe) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_MOVBE;
|
||||||
|
if (info.features.sse4_1) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_1;
|
||||||
|
if (info.features.sse4_2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SSE4_2;
|
||||||
|
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AES_NI;
|
||||||
|
if (info.features.avx) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX;
|
||||||
|
if (info.features.rdrnd) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_RDRAND;
|
||||||
|
if (info.features.avx2) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_AVX2;
|
||||||
|
if (info.features.sha) g_cpuFeatures |= ANDROID_CPU_X86_FEATURE_SHA_NI;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
MipsInfo info = GetMipsInfo();
|
||||||
|
if (info.features.r6) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_R6;
|
||||||
|
if (info.features.msa) g_cpuFeatures |= ANDROID_CPU_MIPS_FEATURE_MSA;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
Aarch64Info info = GetAarch64Info();
|
||||||
|
if (info.features.fp) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_FP;
|
||||||
|
if (info.features.asimd) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_ASIMD;
|
||||||
|
if (info.features.aes) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_AES;
|
||||||
|
if (info.features.pmull) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_PMULL;
|
||||||
|
if (info.features.sha1) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA1;
|
||||||
|
if (info.features.sha2) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_SHA2;
|
||||||
|
if (info.features.crc32) g_cpuFeatures |= ANDROID_CPU_ARM64_FEATURE_CRC32;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
AndroidCpuFamily android_getCpuFamily(void) {
|
||||||
|
#if defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
return ANDROID_CPU_FAMILY_ARM;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_X86_32)
|
||||||
|
return ANDROID_CPU_FAMILY_X86;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS64)
|
||||||
|
return ANDROID_CPU_FAMILY_MIPS64;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS32)
|
||||||
|
return ANDROID_CPU_FAMILY_MIPS;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
return ANDROID_CPU_FAMILY_ARM64;
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_X86_64)
|
||||||
|
return ANDROID_CPU_FAMILY_X86_64;
|
||||||
|
#else
|
||||||
|
return ANDROID_CPU_FAMILY_UNKNOWN;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t android_getCpuFeatures(void) {
|
||||||
|
pthread_once(&g_once, android_cpuInit);
|
||||||
|
return g_cpuFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
|
int android_getCpuCount(void) {
|
||||||
|
pthread_once(&g_once, android_cpuInit);
|
||||||
|
return g_cpuCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void android_cpuInitDummy(void) { g_inited = 1; }
|
||||||
|
|
||||||
|
int android_setCpu(int cpu_count, uint64_t cpu_features) {
|
||||||
|
/* Fail if the library was already initialized. */
|
||||||
|
if (g_inited) return 0;
|
||||||
|
g_cpuCount = (cpu_count <= 0 ? 1 : cpu_count);
|
||||||
|
g_cpuFeatures = cpu_features;
|
||||||
|
pthread_once(&g_once, android_cpuInitDummy);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_ARCH_ARM
|
||||||
|
|
||||||
|
uint32_t android_getCpuIdArm(void) {
|
||||||
|
pthread_once(&g_once, android_cpuInit);
|
||||||
|
return g_cpuIdArm;
|
||||||
|
}
|
||||||
|
|
||||||
|
int android_setCpuArm(int cpu_count, uint64_t cpu_features, uint32_t cpu_id) {
|
||||||
|
if (!android_setCpu(cpu_count, cpu_features)) return 0;
|
||||||
|
g_cpuIdArm = cpu_id;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_ARCH_ARM
|
||||||
|
|
@ -0,0 +1,320 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2010 The Android Open Source Project
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||||
|
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
|
* SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#ifndef GOOGLE_CPU_FEATURES_H
|
||||||
|
#define GOOGLE_CPU_FEATURES_H
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/cdefs.h>
|
||||||
|
|
||||||
|
__BEGIN_DECLS
|
||||||
|
|
||||||
|
/* A list of valid values returned by android_getCpuFamily().
|
||||||
|
* They describe the CPU Architecture of the current process.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
ANDROID_CPU_FAMILY_UNKNOWN = 0,
|
||||||
|
ANDROID_CPU_FAMILY_ARM,
|
||||||
|
ANDROID_CPU_FAMILY_X86,
|
||||||
|
ANDROID_CPU_FAMILY_MIPS,
|
||||||
|
ANDROID_CPU_FAMILY_ARM64,
|
||||||
|
ANDROID_CPU_FAMILY_X86_64,
|
||||||
|
ANDROID_CPU_FAMILY_MIPS64,
|
||||||
|
ANDROID_CPU_FAMILY_MAX /* do not remove */
|
||||||
|
} AndroidCpuFamily;
|
||||||
|
|
||||||
|
/* Return the CPU family of the current process.
|
||||||
|
*
|
||||||
|
* Note that this matches the bitness of the current process. I.e. when
|
||||||
|
* running a 32-bit binary on a 64-bit capable CPU, this will return the
|
||||||
|
* 32-bit CPU family value.
|
||||||
|
*/
|
||||||
|
extern AndroidCpuFamily android_getCpuFamily(void);
|
||||||
|
|
||||||
|
/* Return a bitmap describing a set of optional CPU features that are
|
||||||
|
* supported by the current device's CPU. The exact bit-flags returned
|
||||||
|
* depend on the value returned by android_getCpuFamily(). See the
|
||||||
|
* documentation for the ANDROID_CPU_*_FEATURE_* flags below for details.
|
||||||
|
*/
|
||||||
|
extern uint64_t android_getCpuFeatures(void);
|
||||||
|
|
||||||
|
/* The list of feature flags for ANDROID_CPU_FAMILY_ARM that can be
|
||||||
|
* recognized by the library (see note below for 64-bit ARM). Value details
|
||||||
|
* are:
|
||||||
|
*
|
||||||
|
* VFPv2:
|
||||||
|
* CPU supports the VFPv2 instruction set. Many, but not all, ARMv6 CPUs
|
||||||
|
* support these instructions. VFPv2 is a subset of VFPv3 so this will
|
||||||
|
* be set whenever VFPv3 is set too.
|
||||||
|
*
|
||||||
|
* ARMv7:
|
||||||
|
* CPU supports the ARMv7-A basic instruction set.
|
||||||
|
* This feature is mandated by the 'armeabi-v7a' ABI.
|
||||||
|
*
|
||||||
|
* VFPv3:
|
||||||
|
* CPU supports the VFPv3-D16 instruction set, providing hardware FPU
|
||||||
|
* support for single and double precision floating point registers.
|
||||||
|
* Note that only 16 FPU registers are available by default, unless
|
||||||
|
* the D32 bit is set too. This feature is also mandated by the
|
||||||
|
* 'armeabi-v7a' ABI.
|
||||||
|
*
|
||||||
|
* VFP_D32:
|
||||||
|
* CPU VFP optional extension that provides 32 FPU registers,
|
||||||
|
* instead of 16. Note that ARM mandates this feature is the 'NEON'
|
||||||
|
* feature is implemented by the CPU.
|
||||||
|
*
|
||||||
|
* NEON:
|
||||||
|
* CPU FPU supports "ARM Advanced SIMD" instructions, also known as
|
||||||
|
* NEON. Note that this mandates the VFP_D32 feature as well, per the
|
||||||
|
* ARM Architecture specification.
|
||||||
|
*
|
||||||
|
* VFP_FP16:
|
||||||
|
* Half-width floating precision VFP extension. If set, the CPU
|
||||||
|
* supports instructions to perform floating-point operations on
|
||||||
|
* 16-bit registers. This is part of the VFPv4 specification, but
|
||||||
|
* not mandated by any Android ABI.
|
||||||
|
*
|
||||||
|
* VFP_FMA:
|
||||||
|
* Fused multiply-accumulate VFP instructions extension. Also part of
|
||||||
|
* the VFPv4 specification, but not mandated by any Android ABI.
|
||||||
|
*
|
||||||
|
* NEON_FMA:
|
||||||
|
* Fused multiply-accumulate NEON instructions extension. Optional
|
||||||
|
* extension from the VFPv4 specification, but not mandated by any
|
||||||
|
* Android ABI.
|
||||||
|
*
|
||||||
|
* IDIV_ARM:
|
||||||
|
* Integer division available in ARM mode. Only available
|
||||||
|
* on recent CPUs (e.g. Cortex-A15).
|
||||||
|
*
|
||||||
|
* IDIV_THUMB2:
|
||||||
|
* Integer division available in Thumb-2 mode. Only available
|
||||||
|
* on recent CPUs (e.g. Cortex-A15).
|
||||||
|
*
|
||||||
|
* iWMMXt:
|
||||||
|
* Optional extension that adds MMX registers and operations to an
|
||||||
|
* ARM CPU. This is only available on a few XScale-based CPU designs
|
||||||
|
* sold by Marvell. Pretty rare in practice.
|
||||||
|
*
|
||||||
|
* AES:
|
||||||
|
* CPU supports AES instructions. These instructions are only
|
||||||
|
* available for 32-bit applications running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* CRC32:
|
||||||
|
* CPU supports CRC32 instructions. These instructions are only
|
||||||
|
* available for 32-bit applications running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* SHA2:
|
||||||
|
* CPU supports SHA2 instructions. These instructions are only
|
||||||
|
* available for 32-bit applications running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* SHA1:
|
||||||
|
* CPU supports SHA1 instructions. These instructions are only
|
||||||
|
* available for 32-bit applications running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* PMULL:
|
||||||
|
* CPU supports 64-bit PMULL and PMULL2 instructions. These
|
||||||
|
* instructions are only available for 32-bit applications
|
||||||
|
* running on ARMv8 CPU.
|
||||||
|
*
|
||||||
|
* If you want to tell the compiler to generate code that targets one of
|
||||||
|
* the feature set above, you should probably use one of the following
|
||||||
|
* flags (for more details, see technical note at the end of this file):
|
||||||
|
*
|
||||||
|
* -mfpu=vfp
|
||||||
|
* -mfpu=vfpv2
|
||||||
|
* These are equivalent and tell GCC to use VFPv2 instructions for
|
||||||
|
* floating-point operations. Use this if you want your code to
|
||||||
|
* run on *some* ARMv6 devices, and any ARMv7-A device supported
|
||||||
|
* by Android.
|
||||||
|
*
|
||||||
|
* Generated code requires VFPv2 feature.
|
||||||
|
*
|
||||||
|
* -mfpu=vfpv3-d16
|
||||||
|
* Tell GCC to use VFPv3 instructions (using only 16 FPU registers).
|
||||||
|
* This should be generic code that runs on any CPU that supports the
|
||||||
|
* 'armeabi-v7a' Android ABI. Note that no ARMv6 CPU supports this.
|
||||||
|
*
|
||||||
|
* Generated code requires VFPv3 feature.
|
||||||
|
*
|
||||||
|
* -mfpu=vfpv3
|
||||||
|
* Tell GCC to use VFPv3 instructions with 32 FPU registers.
|
||||||
|
* Generated code requires VFPv3|VFP_D32 features.
|
||||||
|
*
|
||||||
|
* -mfpu=neon
|
||||||
|
* Tell GCC to use VFPv3 instructions with 32 FPU registers, and
|
||||||
|
* also support NEON intrinsics (see <arm_neon.h>).
|
||||||
|
* Generated code requires VFPv3|VFP_D32|NEON features.
|
||||||
|
*
|
||||||
|
* -mfpu=vfpv4-d16
|
||||||
|
* Generated code requires VFPv3|VFP_FP16|VFP_FMA features.
|
||||||
|
*
|
||||||
|
* -mfpu=vfpv4
|
||||||
|
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32 features.
|
||||||
|
*
|
||||||
|
* -mfpu=neon-vfpv4
|
||||||
|
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|NEON|NEON_FMA
|
||||||
|
* features.
|
||||||
|
*
|
||||||
|
* -mcpu=cortex-a7
|
||||||
|
* -mcpu=cortex-a15
|
||||||
|
* Generated code requires VFPv3|VFP_FP16|VFP_FMA|VFP_D32|
|
||||||
|
* NEON|NEON_FMA|IDIV_ARM|IDIV_THUMB2
|
||||||
|
* This flag implies -mfpu=neon-vfpv4.
|
||||||
|
*
|
||||||
|
* -mcpu=iwmmxt
|
||||||
|
* Allows the use of iWMMXt instrinsics with GCC.
|
||||||
|
*
|
||||||
|
* IMPORTANT NOTE: These flags should only be tested when
|
||||||
|
* android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM, i.e. this is a
|
||||||
|
* 32-bit process.
|
||||||
|
*
|
||||||
|
* When running a 64-bit ARM process on an ARMv8 CPU,
|
||||||
|
* android_getCpuFeatures() will return a different set of bitflags
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ANDROID_CPU_ARM_FEATURE_ARMv7 = (1 << 0),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFPv3 = (1 << 1),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_NEON = (1 << 2),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_LDREX_STREX = (1 << 3),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFPv2 = (1 << 4),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFP_D32 = (1 << 5),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFP_FP16 = (1 << 6),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_VFP_FMA = (1 << 7),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_NEON_FMA = (1 << 8),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_IDIV_ARM = (1 << 9),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_IDIV_THUMB2 = (1 << 10),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_iWMMXt = (1 << 11),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_AES = (1 << 12),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_PMULL = (1 << 13),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_SHA1 = (1 << 14),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_SHA2 = (1 << 15),
|
||||||
|
ANDROID_CPU_ARM_FEATURE_CRC32 = (1 << 16),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The bit flags corresponding to the output of android_getCpuFeatures()
|
||||||
|
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_ARM64. Value details
|
||||||
|
* are:
|
||||||
|
*
|
||||||
|
* FP:
|
||||||
|
* CPU has Floating-point unit.
|
||||||
|
*
|
||||||
|
* ASIMD:
|
||||||
|
* CPU has Advanced SIMD unit.
|
||||||
|
*
|
||||||
|
* AES:
|
||||||
|
* CPU supports AES instructions.
|
||||||
|
*
|
||||||
|
* CRC32:
|
||||||
|
* CPU supports CRC32 instructions.
|
||||||
|
*
|
||||||
|
* SHA2:
|
||||||
|
* CPU supports SHA2 instructions.
|
||||||
|
*
|
||||||
|
* SHA1:
|
||||||
|
* CPU supports SHA1 instructions.
|
||||||
|
*
|
||||||
|
* PMULL:
|
||||||
|
* CPU supports 64-bit PMULL and PMULL2 instructions.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_FP = (1 << 0),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_ASIMD = (1 << 1),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_AES = (1 << 2),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_PMULL = (1 << 3),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_SHA1 = (1 << 4),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_SHA2 = (1 << 5),
|
||||||
|
ANDROID_CPU_ARM64_FEATURE_CRC32 = (1 << 6),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The bit flags corresponding to the output of android_getCpuFeatures()
|
||||||
|
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_X86 or
|
||||||
|
* ANDROID_CPU_FAMILY_X86_64.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ANDROID_CPU_X86_FEATURE_SSSE3 = (1 << 0),
|
||||||
|
ANDROID_CPU_X86_FEATURE_POPCNT = (1 << 1),
|
||||||
|
ANDROID_CPU_X86_FEATURE_MOVBE = (1 << 2),
|
||||||
|
ANDROID_CPU_X86_FEATURE_SSE4_1 = (1 << 3),
|
||||||
|
ANDROID_CPU_X86_FEATURE_SSE4_2 = (1 << 4),
|
||||||
|
ANDROID_CPU_X86_FEATURE_AES_NI = (1 << 5),
|
||||||
|
ANDROID_CPU_X86_FEATURE_AVX = (1 << 6),
|
||||||
|
ANDROID_CPU_X86_FEATURE_RDRAND = (1 << 7),
|
||||||
|
ANDROID_CPU_X86_FEATURE_AVX2 = (1 << 8),
|
||||||
|
ANDROID_CPU_X86_FEATURE_SHA_NI = (1 << 9),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* The bit flags corresponding to the output of android_getCpuFeatures()
|
||||||
|
* when android_getCpuFamily() returns ANDROID_CPU_FAMILY_MIPS
|
||||||
|
* or ANDROID_CPU_FAMILY_MIPS64. Values are:
|
||||||
|
*
|
||||||
|
* R6:
|
||||||
|
* CPU executes MIPS Release 6 instructions natively, and
|
||||||
|
* supports obsoleted R1..R5 instructions only via kernel traps.
|
||||||
|
*
|
||||||
|
* MSA:
|
||||||
|
* CPU supports Mips SIMD Architecture instructions.
|
||||||
|
*/
|
||||||
|
enum {
|
||||||
|
ANDROID_CPU_MIPS_FEATURE_R6 = (1 << 0),
|
||||||
|
ANDROID_CPU_MIPS_FEATURE_MSA = (1 << 1),
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Return the number of CPU cores detected on this device.
|
||||||
|
* Please note the current implementation supports up to 32 cpus.
|
||||||
|
*/
|
||||||
|
extern int android_getCpuCount(void);
|
||||||
|
|
||||||
|
/* The following is used to force the CPU count and features
|
||||||
|
* mask in sandboxed processes. Under 4.1 and higher, these processes
|
||||||
|
* cannot access /proc, which is the only way to get information from
|
||||||
|
* the kernel about the current hardware (at least on ARM).
|
||||||
|
*
|
||||||
|
* It _must_ be called only once, and before any android_getCpuXXX
|
||||||
|
* function, any other case will fail.
|
||||||
|
*
|
||||||
|
* This function return 1 on success, and 0 on failure.
|
||||||
|
*/
|
||||||
|
extern int android_setCpu(int cpu_count, uint64_t cpu_features);
|
||||||
|
|
||||||
|
#ifdef __arm__
|
||||||
|
|
||||||
|
/* Retrieve the ARM 32-bit CPUID value from the kernel.
|
||||||
|
* Note that this cannot work on sandboxed processes under 4.1 and
|
||||||
|
* higher, unless you called android_setCpuArm() before.
|
||||||
|
*/
|
||||||
|
extern uint32_t android_getCpuIdArm(void);
|
||||||
|
|
||||||
|
/* An ARM-specific variant of android_setCpu() that also allows you
|
||||||
|
* to set the ARM CPUID field.
|
||||||
|
*/
|
||||||
|
extern int android_setCpuArm(int cpu_count, uint64_t cpu_features,
|
||||||
|
uint32_t cpu_id);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__END_DECLS
|
||||||
|
#endif /* GOOGLE_CPU_FEATURES_H */
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "cpu-features.h"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
printf("android_getCpuFamily()=%d\n", android_getCpuFamily());
|
||||||
|
printf("android_getCpuFeatures()=0x%08llx\n", android_getCpuFeatures());
|
||||||
|
printf("android_getCpuCount()=%d\n", android_getCpuCount());
|
||||||
|
#ifdef __arm__
|
||||||
|
printf("android_getCpuIdArm()=0x%04x\n", android_getCpuIdArm());
|
||||||
|
#endif //__arm__
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,209 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
readonly SCRIPT_FOLDER=$(cd -P -- "$(dirname -- "$0")" && pwd -P)
|
||||||
|
readonly PROJECT_FOLDER="${SCRIPT_FOLDER}/.."
|
||||||
|
readonly ARCHIVE_FOLDER=~/cpu_features_archives
|
||||||
|
readonly QEMU_INSTALL=${ARCHIVE_FOLDER}/qemu
|
||||||
|
readonly DEFAULT_CMAKE_ARGS=" -DCMAKE_BUILD_TYPE=Debug -DBUILD_TESTING=ON"
|
||||||
|
|
||||||
|
function extract() {
|
||||||
|
case $1 in
|
||||||
|
*.tar.bz2) tar xjf "$1" ;;
|
||||||
|
*.tar.xz) tar xJf "$1" ;;
|
||||||
|
*.tar.gz) tar xzf "$1" ;;
|
||||||
|
*)
|
||||||
|
echo "don't know how to extract '$1'..."
|
||||||
|
exit 1
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
|
||||||
|
function unpackifnotexists() {
|
||||||
|
mkdir -p "${ARCHIVE_FOLDER}"
|
||||||
|
cd "${ARCHIVE_FOLDER}" || exit
|
||||||
|
local URL=$1
|
||||||
|
local RELATIVE_FOLDER=$2
|
||||||
|
local DESTINATION="${ARCHIVE_FOLDER}/${RELATIVE_FOLDER}"
|
||||||
|
if [[ ! -d "${DESTINATION}" ]] ; then
|
||||||
|
local ARCHIVE_NAME=$(echo ${URL} | sed 's/.*\///')
|
||||||
|
test -f "${ARCHIVE_NAME}" || wget -q "${URL}"
|
||||||
|
extract "${ARCHIVE_NAME}"
|
||||||
|
rm -f "${ARCHIVE_NAME}"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function installqemuifneeded() {
|
||||||
|
local VERSION=${QEMU_VERSION:=2.11.1}
|
||||||
|
local ARCHES=${QEMU_ARCHES:=arm aarch64 i386 x86_64 mips mipsel mips64 mips64el}
|
||||||
|
local TARGETS=${QEMU_TARGETS:=$(echo "$ARCHES" | sed 's#$# #;s#\([^ ]*\) #\1-linux-user #g')}
|
||||||
|
|
||||||
|
if echo "${VERSION} ${TARGETS}" | cmp --silent ${QEMU_INSTALL}/.build -; then
|
||||||
|
echo "qemu ${VERSION} up to date!"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "VERSION: ${VERSION}"
|
||||||
|
echo "TARGETS: ${TARGETS}"
|
||||||
|
|
||||||
|
rm -rf ${QEMU_INSTALL}
|
||||||
|
|
||||||
|
# Checking for a tarball before downloading makes testing easier :-)
|
||||||
|
local QEMU_URL="http://wiki.qemu-project.org/download/qemu-${VERSION}.tar.xz"
|
||||||
|
local QEMU_FOLDER="qemu-${VERSION}"
|
||||||
|
unpackifnotexists ${QEMU_URL} ${QEMU_FOLDER}
|
||||||
|
cd ${QEMU_FOLDER} || exit
|
||||||
|
|
||||||
|
./configure \
|
||||||
|
--prefix="${QEMU_INSTALL}" \
|
||||||
|
--target-list="${TARGETS}" \
|
||||||
|
--disable-docs \
|
||||||
|
--disable-sdl \
|
||||||
|
--disable-gtk \
|
||||||
|
--disable-gnutls \
|
||||||
|
--disable-gcrypt \
|
||||||
|
--disable-nettle \
|
||||||
|
--disable-curses \
|
||||||
|
--static
|
||||||
|
|
||||||
|
make -j4
|
||||||
|
make install
|
||||||
|
|
||||||
|
echo "$VERSION $TARGETS" > ${QEMU_INSTALL}/.build
|
||||||
|
}
|
||||||
|
|
||||||
|
function assert_defined(){
|
||||||
|
local VALUE=${1}
|
||||||
|
: "${VALUE?"${1} needs to be defined"}"
|
||||||
|
}
|
||||||
|
|
||||||
|
function integrate() {
|
||||||
|
cd "${PROJECT_FOLDER}"
|
||||||
|
case "${OS}" in
|
||||||
|
"Windows_NT") CMAKE_BUILD_ARGS="--config Debug --target ALL_BUILD"
|
||||||
|
CMAKE_TEST_FILES="${BUILD_DIR}/test/Debug/*_test.exe"
|
||||||
|
DEMO=${BUILD_DIR}/Debug/list_cpu_features.exe
|
||||||
|
;;
|
||||||
|
*) CMAKE_BUILD_ARGS="--target all"
|
||||||
|
CMAKE_TEST_FILES="${BUILD_DIR}/test/*_test"
|
||||||
|
DEMO=${BUILD_DIR}/list_cpu_features
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
# Generating CMake configuration
|
||||||
|
cmake -H. -B"${BUILD_DIR}" ${DEFAULT_CMAKE_ARGS} "${CMAKE_ADDITIONAL_ARGS[@]}" -G"${CMAKE_GENERATOR:-Unix Makefiles}"
|
||||||
|
|
||||||
|
# Building
|
||||||
|
cmake --build "${BUILD_DIR}" ${CMAKE_BUILD_ARGS}
|
||||||
|
|
||||||
|
# Running tests if needed
|
||||||
|
if [[ "${QEMU_ARCH}" == "DISABLED" ]]; then
|
||||||
|
return
|
||||||
|
fi
|
||||||
|
RUN_CMD=""
|
||||||
|
if [[ -n "${QEMU_ARCH}" ]]; then
|
||||||
|
installqemuifneeded
|
||||||
|
RUN_CMD="${QEMU_INSTALL}/bin/qemu-${QEMU_ARCH} ${QEMU_ARGS[@]}"
|
||||||
|
fi
|
||||||
|
for test_binary in ${CMAKE_TEST_FILES}; do
|
||||||
|
${RUN_CMD} ${test_binary}
|
||||||
|
done
|
||||||
|
${RUN_CMD} ${DEMO}
|
||||||
|
}
|
||||||
|
|
||||||
|
function expand_linaro_config() {
|
||||||
|
assert_defined TARGET
|
||||||
|
local LINARO_ROOT_URL=https://releases.linaro.org/components/toolchain/binaries/7.2-2017.11
|
||||||
|
|
||||||
|
local GCC_URL=${LINARO_ROOT_URL}/${TARGET}/gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}.tar.xz
|
||||||
|
local GCC_RELATIVE_FOLDER="gcc-linaro-7.2.1-2017.11-x86_64_${TARGET}"
|
||||||
|
unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}"
|
||||||
|
|
||||||
|
local SYSROOT_URL=${LINARO_ROOT_URL}/${TARGET}/sysroot-glibc-linaro-2.25-2017.11-${TARGET}.tar.xz
|
||||||
|
local SYSROOT_RELATIVE_FOLDER=sysroot-glibc-linaro-2.25-2017.11-${TARGET}
|
||||||
|
unpackifnotexists "${SYSROOT_URL}" "${SYSROOT_RELATIVE_FOLDER}"
|
||||||
|
|
||||||
|
local SYSROOT_FOLDER=${ARCHIVE_FOLDER}/${SYSROOT_RELATIVE_FOLDER}
|
||||||
|
local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER}
|
||||||
|
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET})
|
||||||
|
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSROOT=${SYSROOT_FOLDER})
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=${GCC_FOLDER}/bin/${TARGET}-gcc)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=${GCC_FOLDER}/bin/${TARGET}-g++)
|
||||||
|
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PROGRAM=NEVER)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_INCLUDE=ONLY)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH_MODE_PACKAGE=ONLY)
|
||||||
|
|
||||||
|
QEMU_ARGS+=(-L ${SYSROOT_FOLDER})
|
||||||
|
QEMU_ARGS+=(-E LD_LIBRARY_PATH=/lib)
|
||||||
|
}
|
||||||
|
|
||||||
|
function expand_codescape_config() {
|
||||||
|
assert_defined TARGET
|
||||||
|
local DATE=2017.10-08
|
||||||
|
local CODESCAPE_URL=https://codescape.mips.com/components/toolchain/${DATE}/Codescape.GNU.Tools.Package.${DATE}.for.MIPS.MTI.Linux.CentOS-5.x86_64.tar.gz
|
||||||
|
local GCC_URL=${CODESCAPE_URL}
|
||||||
|
local GCC_RELATIVE_FOLDER="mips-mti-linux-gnu/${DATE}"
|
||||||
|
unpackifnotexists "${GCC_URL}" "${GCC_RELATIVE_FOLDER}"
|
||||||
|
|
||||||
|
local GCC_FOLDER=${ARCHIVE_FOLDER}/${GCC_RELATIVE_FOLDER}
|
||||||
|
local MIPS_FLAGS=""
|
||||||
|
local LIBC_FOLDER_SUFFIX=""
|
||||||
|
local FLAVOUR=""
|
||||||
|
case "${TARGET}" in
|
||||||
|
"mips32") MIPS_FLAGS="-EB -mabi=32"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;;
|
||||||
|
"mips32el") MIPS_FLAGS="-EL -mabi=32"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib" ;;
|
||||||
|
"mips64") MIPS_FLAGS="-EB -mabi=64"; FLAVOUR="mips-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;;
|
||||||
|
"mips64el") MIPS_FLAGS="-EL -mabi=64"; FLAVOUR="mipsel-r2-hard"; LIBC_FOLDER_SUFFIX="lib64" ;;
|
||||||
|
*) echo 'unknown mips platform'; exit 1;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_FIND_ROOT_PATH=${GCC_FOLDER})
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_NAME=Linux)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_SYSTEM_PROCESSOR=${TARGET})
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER=mips-mti-linux-gnu-gcc)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER=mips-mti-linux-gnu-g++)
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_C_COMPILER_ARG1="${MIPS_FLAGS}")
|
||||||
|
CMAKE_ADDITIONAL_ARGS+=(-DCMAKE_CXX_COMPILER_ARG1="${MIPS_FLAGS}")
|
||||||
|
|
||||||
|
local SYSROOT_FOLDER=${GCC_FOLDER}/sysroot/${FLAVOUR}
|
||||||
|
|
||||||
|
# Keeping only the sysroot of interest to save on travis cache.
|
||||||
|
if [[ "${CONTINUOUS_INTEGRATION}" = "true" ]]; then
|
||||||
|
for folder in ${GCC_FOLDER}/sysroot/*; do
|
||||||
|
if [[ "${folder}" != "${SYSROOT_FOLDER}" ]]; then
|
||||||
|
rm -rf ${folder}
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
|
local LIBC_FOLDER=${GCC_FOLDER}/mips-mti-linux-gnu/lib/${FLAVOUR}/${LIBC_FOLDER_SUFFIX}
|
||||||
|
QEMU_ARGS+=(-L ${SYSROOT_FOLDER})
|
||||||
|
QEMU_ARGS+=(-E LD_PRELOAD=${LIBC_FOLDER}/libstdc++.so.6:${LIBC_FOLDER}/libgcc_s.so.1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function expand_environment_and_integrate() {
|
||||||
|
assert_defined PROJECT_FOLDER
|
||||||
|
assert_defined TARGET
|
||||||
|
|
||||||
|
BUILD_DIR="${PROJECT_FOLDER}/cmake_build/${TARGET}"
|
||||||
|
mkdir -p "${BUILD_DIR}"
|
||||||
|
|
||||||
|
declare -a CONFIG_NAMES=()
|
||||||
|
declare -a QEMU_ARGS=()
|
||||||
|
declare -a CMAKE_ADDITIONAL_ARGS=()
|
||||||
|
|
||||||
|
case ${TOOLCHAIN} in
|
||||||
|
LINARO) expand_linaro_config ;;
|
||||||
|
CODESCAPE) expand_codescape_config ;;
|
||||||
|
NATIVE) QEMU_ARCH="" ;;
|
||||||
|
*) echo "Unknown toolchain '${TOOLCHAIN}'..."; exit 1;;
|
||||||
|
esac
|
||||||
|
integrate
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "${CONTINUOUS_INTEGRATION}" = "true" ]; then
|
||||||
|
QEMU_ARCHES=${QEMU_ARCH}
|
||||||
|
expand_environment_and_integrate
|
||||||
|
fi
|
||||||
|
|
@ -0,0 +1,106 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
source "$(dirname -- "$0")"/run_integration.sh
|
||||||
|
|
||||||
|
# Toolchains for little-endian, 64-bit ARMv8 for GNU/Linux systems
|
||||||
|
function set_aarch64-linux-gnu() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=aarch64-linux-gnu
|
||||||
|
QEMU_ARCH=aarch64
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for little-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
function set_arm-linux-gnueabihf() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=arm-linux-gnueabihf
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for little-endian, 32-bit ARMv8 for GNU/Linux systems
|
||||||
|
function set_armv8l-linux-gnueabihf() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armv8l-linux-gnueabihf
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for little-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
function set_arm-linux-gnueabi() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=arm-linux-gnueabi
|
||||||
|
QEMU_ARCH=arm
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for big-endian, 64-bit ARMv8 for GNU/Linux systems
|
||||||
|
function set_aarch64_be-linux-gnu() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=aarch64_be-linux-gnu
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for big-endian, hard-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
function set_armeb-linux-gnueabihf() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armeb-linux-gnueabihf
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
# Toolchains for big-endian, soft-float, 32-bit ARMv7 (and earlier) for GNU/Linux systems
|
||||||
|
function set_armeb-linux-gnueabi() {
|
||||||
|
TOOLCHAIN=LINARO
|
||||||
|
TARGET=armeb-linux-gnueabi
|
||||||
|
QEMU_ARCH=DISABLED
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mips32() {
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips32
|
||||||
|
QEMU_ARCH=mips
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mips32el() {
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips32el
|
||||||
|
QEMU_ARCH=mipsel
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mips64() {
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips64
|
||||||
|
QEMU_ARCH=mips64
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_mips64el() {
|
||||||
|
TOOLCHAIN=CODESCAPE
|
||||||
|
TARGET=mips64el
|
||||||
|
QEMU_ARCH=mips64el
|
||||||
|
}
|
||||||
|
|
||||||
|
function set_native() {
|
||||||
|
TOOLCHAIN=NATIVE
|
||||||
|
TARGET=native
|
||||||
|
QEMU_ARCH=""
|
||||||
|
}
|
||||||
|
|
||||||
|
ENVIRONMENTS="
|
||||||
|
set_aarch64-linux-gnu
|
||||||
|
set_arm-linux-gnueabihf
|
||||||
|
set_armv8l-linux-gnueabihf
|
||||||
|
set_arm-linux-gnueabi
|
||||||
|
set_aarch64_be-linux-gnu
|
||||||
|
set_armeb-linux-gnueabihf
|
||||||
|
set_armeb-linux-gnueabi
|
||||||
|
set_mips32
|
||||||
|
set_mips32el
|
||||||
|
set_mips64
|
||||||
|
set_mips64el
|
||||||
|
set_native
|
||||||
|
"
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
CMAKE_GENERATOR="Ninja"
|
||||||
|
|
||||||
|
for SET_ENVIRONMENT in ${ENVIRONMENTS}; do
|
||||||
|
${SET_ENVIRONMENT}
|
||||||
|
expand_environment_and_integrate
|
||||||
|
done
|
||||||
|
|
@ -0,0 +1,150 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
// Generation of feature's getters/setters functions and kGetters, kSetters,
|
||||||
|
// kCpuInfoFlags and kHardwareCapabilities global tables.
|
||||||
|
#define DEFINE_TABLE_FEATURES \
|
||||||
|
FEATURE(AARCH64_FP, fp, "fp", AARCH64_HWCAP_FP, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMD, asimd, "asimd", AARCH64_HWCAP_ASIMD, 0) \
|
||||||
|
FEATURE(AARCH64_EVTSTRM, evtstrm, "evtstrm", AARCH64_HWCAP_EVTSTRM, 0) \
|
||||||
|
FEATURE(AARCH64_AES, aes, "aes", AARCH64_HWCAP_AES, 0) \
|
||||||
|
FEATURE(AARCH64_PMULL, pmull, "pmull", AARCH64_HWCAP_PMULL, 0) \
|
||||||
|
FEATURE(AARCH64_SHA1, sha1, "sha1", AARCH64_HWCAP_SHA1, 0) \
|
||||||
|
FEATURE(AARCH64_SHA2, sha2, "sha2", AARCH64_HWCAP_SHA2, 0) \
|
||||||
|
FEATURE(AARCH64_CRC32, crc32, "crc32", AARCH64_HWCAP_CRC32, 0) \
|
||||||
|
FEATURE(AARCH64_ATOMICS, atomics, "atomics", AARCH64_HWCAP_ATOMICS, 0) \
|
||||||
|
FEATURE(AARCH64_FPHP, fphp, "fphp", AARCH64_HWCAP_FPHP, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMDHP, asimdhp, "asimdhp", AARCH64_HWCAP_ASIMDHP, 0) \
|
||||||
|
FEATURE(AARCH64_CPUID, cpuid, "cpuid", AARCH64_HWCAP_CPUID, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMDRDM, asimdrdm, "asimdrdm", AARCH64_HWCAP_ASIMDRDM, 0) \
|
||||||
|
FEATURE(AARCH64_JSCVT, jscvt, "jscvt", AARCH64_HWCAP_JSCVT, 0) \
|
||||||
|
FEATURE(AARCH64_FCMA, fcma, "fcma", AARCH64_HWCAP_FCMA, 0) \
|
||||||
|
FEATURE(AARCH64_LRCPC, lrcpc, "lrcpc", AARCH64_HWCAP_LRCPC, 0) \
|
||||||
|
FEATURE(AARCH64_DCPOP, dcpop, "dcpop", AARCH64_HWCAP_DCPOP, 0) \
|
||||||
|
FEATURE(AARCH64_SHA3, sha3, "sha3", AARCH64_HWCAP_SHA3, 0) \
|
||||||
|
FEATURE(AARCH64_SM3, sm3, "sm3", AARCH64_HWCAP_SM3, 0) \
|
||||||
|
FEATURE(AARCH64_SM4, sm4, "sm4", AARCH64_HWCAP_SM4, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMDDP, asimddp, "asimddp", AARCH64_HWCAP_ASIMDDP, 0) \
|
||||||
|
FEATURE(AARCH64_SHA512, sha512, "sha512", AARCH64_HWCAP_SHA512, 0) \
|
||||||
|
FEATURE(AARCH64_SVE, sve, "sve", AARCH64_HWCAP_SVE, 0) \
|
||||||
|
FEATURE(AARCH64_ASIMDFHM, asimdfhm, "asimdfhm", AARCH64_HWCAP_ASIMDFHM, 0) \
|
||||||
|
FEATURE(AARCH64_DIT, dit, "dit", AARCH64_HWCAP_DIT, 0) \
|
||||||
|
FEATURE(AARCH64_USCAT, uscat, "uscat", AARCH64_HWCAP_USCAT, 0) \
|
||||||
|
FEATURE(AARCH64_ILRCPC, ilrcpc, "ilrcpc", AARCH64_HWCAP_ILRCPC, 0) \
|
||||||
|
FEATURE(AARCH64_FLAGM, flagm, "flagm", AARCH64_HWCAP_FLAGM, 0) \
|
||||||
|
FEATURE(AARCH64_SSBS, ssbs, "ssbs", AARCH64_HWCAP_SSBS, 0) \
|
||||||
|
FEATURE(AARCH64_SB, sb, "sb", AARCH64_HWCAP_SB, 0) \
|
||||||
|
FEATURE(AARCH64_PACA, paca, "paca", AARCH64_HWCAP_PACA, 0) \
|
||||||
|
FEATURE(AARCH64_PACG, pacg, "pacg", AARCH64_HWCAP_PACG, 0) \
|
||||||
|
FEATURE(AARCH64_DCPODP, dcpodp, "dcpodp", 0, AARCH64_HWCAP2_DCPODP) \
|
||||||
|
FEATURE(AARCH64_SVE2, sve2, "sve2", 0, AARCH64_HWCAP2_SVE2) \
|
||||||
|
FEATURE(AARCH64_SVEAES, sveaes, "sveaes", 0, AARCH64_HWCAP2_SVEAES) \
|
||||||
|
FEATURE(AARCH64_SVEPMULL, svepmull, "svepmull", 0, AARCH64_HWCAP2_SVEPMULL) \
|
||||||
|
FEATURE(AARCH64_SVEBITPERM, svebitperm, "svebitperm", 0, \
|
||||||
|
AARCH64_HWCAP2_SVEBITPERM) \
|
||||||
|
FEATURE(AARCH64_SVESHA3, svesha3, "svesha3", 0, AARCH64_HWCAP2_SVESHA3) \
|
||||||
|
FEATURE(AARCH64_SVESM4, svesm4, "svesm4", 0, AARCH64_HWCAP2_SVESM4) \
|
||||||
|
FEATURE(AARCH64_FLAGM2, flagm2, "flagm2", 0, AARCH64_HWCAP2_FLAGM2) \
|
||||||
|
FEATURE(AARCH64_FRINT, frint, "frint", 0, AARCH64_HWCAP2_FRINT) \
|
||||||
|
FEATURE(AARCH64_SVEI8MM, svei8mm, "svei8mm", 0, AARCH64_HWCAP2_SVEI8MM) \
|
||||||
|
FEATURE(AARCH64_SVEF32MM, svef32mm, "svef32mm", 0, AARCH64_HWCAP2_SVEF32MM) \
|
||||||
|
FEATURE(AARCH64_SVEF64MM, svef64mm, "svef64mm", 0, AARCH64_HWCAP2_SVEF64MM) \
|
||||||
|
FEATURE(AARCH64_SVEBF16, svebf16, "svebf16", 0, AARCH64_HWCAP2_SVEBF16) \
|
||||||
|
FEATURE(AARCH64_I8MM, i8mm, "i8mm", 0, AARCH64_HWCAP2_I8MM) \
|
||||||
|
FEATURE(AARCH64_BF16, bf16, "bf16", 0, AARCH64_HWCAP2_BF16) \
|
||||||
|
FEATURE(AARCH64_DGH, dgh, "dgh", 0, AARCH64_HWCAP2_DGH) \
|
||||||
|
FEATURE(AARCH64_RNG, rng, "rng", 0, AARCH64_HWCAP2_RNG) \
|
||||||
|
FEATURE(AARCH64_BTI, bti, "bti", 0, AARCH64_HWCAP2_BTI)
|
||||||
|
#define DEFINE_TABLE_FEATURE_TYPE Aarch64Features
|
||||||
|
#include "define_tables.h"
|
||||||
|
|
||||||
|
static bool HandleAarch64Line(const LineResult result,
|
||||||
|
Aarch64Info* const info) {
|
||||||
|
StringView line = result.line;
|
||||||
|
StringView key, value;
|
||||||
|
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||||
|
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||||
|
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
|
||||||
|
kSetters[i](&info->features,
|
||||||
|
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||||
|
}
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
|
||||||
|
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
|
||||||
|
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
|
||||||
|
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
|
||||||
|
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !result.eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillProcCpuInfoData(Aarch64Info* const info) {
|
||||||
|
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
for (;;) {
|
||||||
|
if (!HandleAarch64Line(StackLineReader_NextLine(&reader), info)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Aarch64Info kEmptyAarch64Info;
|
||||||
|
|
||||||
|
Aarch64Info GetAarch64Info(void) {
|
||||||
|
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||||
|
// have some information if the executable is sandboxed (aka no access to
|
||||||
|
// /proc/cpuinfo).
|
||||||
|
Aarch64Info info = kEmptyAarch64Info;
|
||||||
|
|
||||||
|
FillProcCpuInfoData(&info);
|
||||||
|
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||||
|
for (size_t i = 0; i < AARCH64_LAST_; ++i) {
|
||||||
|
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||||
|
kSetters[i](&info.features, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
int GetAarch64FeaturesEnumValue(const Aarch64Features* features,
|
||||||
|
Aarch64FeaturesEnum value) {
|
||||||
|
if (value >= AARCH64_LAST_) return false;
|
||||||
|
return kGetters[value](features);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetAarch64FeaturesEnumName(Aarch64FeaturesEnum value) {
|
||||||
|
if (value >= AARCH64_LAST_) return "unknown feature";
|
||||||
|
return kCpuInfoFlags[value];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,212 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
#include "internal/bit_utils.h"
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
// Generation of feature's getters/setters functions and kGetters, kSetters,
|
||||||
|
// kCpuInfoFlags and kHardwareCapabilities global tables.
|
||||||
|
#define DEFINE_TABLE_FEATURES \
|
||||||
|
FEATURE(ARM_SWP, swp, "swp", ARM_HWCAP_SWP, 0) \
|
||||||
|
FEATURE(ARM_HALF, half, "half", ARM_HWCAP_HALF, 0) \
|
||||||
|
FEATURE(ARM_THUMB, thumb, "thumb", ARM_HWCAP_THUMB, 0) \
|
||||||
|
FEATURE(ARM_26BIT, _26bit, "26bit", ARM_HWCAP_26BIT, 0) \
|
||||||
|
FEATURE(ARM_FASTMULT, fastmult, "fastmult", ARM_HWCAP_FAST_MULT, 0) \
|
||||||
|
FEATURE(ARM_FPA, fpa, "fpa", ARM_HWCAP_FPA, 0) \
|
||||||
|
FEATURE(ARM_VFP, vfp, "vfp", ARM_HWCAP_VFP, 0) \
|
||||||
|
FEATURE(ARM_EDSP, edsp, "edsp", ARM_HWCAP_EDSP, 0) \
|
||||||
|
FEATURE(ARM_JAVA, java, "java", ARM_HWCAP_JAVA, 0) \
|
||||||
|
FEATURE(ARM_IWMMXT, iwmmxt, "iwmmxt", ARM_HWCAP_IWMMXT, 0) \
|
||||||
|
FEATURE(ARM_CRUNCH, crunch, "crunch", ARM_HWCAP_CRUNCH, 0) \
|
||||||
|
FEATURE(ARM_THUMBEE, thumbee, "thumbee", ARM_HWCAP_THUMBEE, 0) \
|
||||||
|
FEATURE(ARM_NEON, neon, "neon", ARM_HWCAP_NEON, 0) \
|
||||||
|
FEATURE(ARM_VFPV3, vfpv3, "vfpv3", ARM_HWCAP_VFPV3, 0) \
|
||||||
|
FEATURE(ARM_VFPV3D16, vfpv3d16, "vfpv3d16", ARM_HWCAP_VFPV3D16, 0) \
|
||||||
|
FEATURE(ARM_TLS, tls, "tls", ARM_HWCAP_TLS, 0) \
|
||||||
|
FEATURE(ARM_VFPV4, vfpv4, "vfpv4", ARM_HWCAP_VFPV4, 0) \
|
||||||
|
FEATURE(ARM_IDIVA, idiva, "idiva", ARM_HWCAP_IDIVA, 0) \
|
||||||
|
FEATURE(ARM_IDIVT, idivt, "idivt", ARM_HWCAP_IDIVT, 0) \
|
||||||
|
FEATURE(ARM_VFPD32, vfpd32, "vfpd32", ARM_HWCAP_VFPD32, 0) \
|
||||||
|
FEATURE(ARM_LPAE, lpae, "lpae", ARM_HWCAP_LPAE, 0) \
|
||||||
|
FEATURE(ARM_EVTSTRM, evtstrm, "evtstrm", ARM_HWCAP_EVTSTRM, 0) \
|
||||||
|
FEATURE(ARM_AES, aes, "aes", 0, ARM_HWCAP2_AES) \
|
||||||
|
FEATURE(ARM_PMULL, pmull, "pmull", 0, ARM_HWCAP2_PMULL) \
|
||||||
|
FEATURE(ARM_SHA1, sha1, "sha1", 0, ARM_HWCAP2_SHA1) \
|
||||||
|
FEATURE(ARM_SHA2, sha2, "sha2", 0, ARM_HWCAP2_SHA2) \
|
||||||
|
FEATURE(ARM_CRC32, crc32, "crc32", 0, ARM_HWCAP2_CRC32)
|
||||||
|
#define DEFINE_TABLE_FEATURE_TYPE ArmFeatures
|
||||||
|
#include "define_tables.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool processor_reports_armv6;
|
||||||
|
bool hardware_reports_goldfish;
|
||||||
|
} ProcCpuInfoData;
|
||||||
|
|
||||||
|
static int IndexOfNonDigit(StringView str) {
|
||||||
|
size_t index = 0;
|
||||||
|
while (str.size && isdigit(CpuFeatures_StringView_Front(str))) {
|
||||||
|
str = CpuFeatures_StringView_PopFront(str, 1);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool HandleArmLine(const LineResult result, ArmInfo* const info,
|
||||||
|
ProcCpuInfoData* const proc_info) {
|
||||||
|
StringView line = result.line;
|
||||||
|
StringView key, value;
|
||||||
|
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||||
|
if (CpuFeatures_StringView_IsEquals(key, str("Features"))) {
|
||||||
|
for (size_t i = 0; i < ARM_LAST_; ++i) {
|
||||||
|
kSetters[i](&info->features,
|
||||||
|
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||||
|
}
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU implementer"))) {
|
||||||
|
info->implementer = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU variant"))) {
|
||||||
|
info->variant = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU part"))) {
|
||||||
|
info->part = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU revision"))) {
|
||||||
|
info->revision = CpuFeatures_StringView_ParsePositiveNumber(value);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("CPU architecture"))) {
|
||||||
|
// CPU architecture is a number that may be followed by letters. e.g.
|
||||||
|
// "6TEJ", "7".
|
||||||
|
const StringView digits =
|
||||||
|
CpuFeatures_StringView_KeepFront(value, IndexOfNonDigit(value));
|
||||||
|
info->architecture = CpuFeatures_StringView_ParsePositiveNumber(digits);
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("Processor")) ||
|
||||||
|
CpuFeatures_StringView_IsEquals(key, str("model name"))) {
|
||||||
|
// Android reports this in a non-Linux standard "Processor" but sometimes
|
||||||
|
// also in "model name", Linux reports it only in "model name"
|
||||||
|
// see RaspberryPiZero (Linux) vs InvalidArmv7 (Android) test-cases
|
||||||
|
proc_info->processor_reports_armv6 =
|
||||||
|
CpuFeatures_StringView_IndexOf(value, str("(v6l)")) >= 0;
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("Hardware"))) {
|
||||||
|
proc_info->hardware_reports_goldfish =
|
||||||
|
CpuFeatures_StringView_IsEquals(value, str("Goldfish"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !result.eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetArmCpuId(const ArmInfo* const info) {
|
||||||
|
return (ExtractBitRange(info->implementer, 7, 0) << 24) |
|
||||||
|
(ExtractBitRange(info->variant, 3, 0) << 20) |
|
||||||
|
(ExtractBitRange(info->part, 11, 0) << 4) |
|
||||||
|
(ExtractBitRange(info->revision, 3, 0) << 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FixErrors(ArmInfo* const info,
|
||||||
|
ProcCpuInfoData* const proc_cpu_info_data) {
|
||||||
|
// Fixing Samsung kernel reporting invalid cpu architecture.
|
||||||
|
// http://code.google.com/p/android/issues/detail?id=10812
|
||||||
|
if (proc_cpu_info_data->processor_reports_armv6 && info->architecture >= 7) {
|
||||||
|
info->architecture = 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle kernel configuration bugs that prevent the correct reporting of CPU
|
||||||
|
// features.
|
||||||
|
switch (GetArmCpuId(info)) {
|
||||||
|
case 0x4100C080:
|
||||||
|
// Special case: The emulator-specific Android 4.2 kernel fails to report
|
||||||
|
// support for the 32-bit ARM IDIV instruction. Technically, this is a
|
||||||
|
// feature of the virtual CPU implemented by the emulator. Note that it
|
||||||
|
// could also support Thumb IDIV in the future, and this will have to be
|
||||||
|
// slightly updated.
|
||||||
|
if (info->architecture >= 7 &&
|
||||||
|
proc_cpu_info_data->hardware_reports_goldfish) {
|
||||||
|
info->features.idiva = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x511004D0:
|
||||||
|
// https://crbug.com/341598.
|
||||||
|
info->features.neon = false;
|
||||||
|
break;
|
||||||
|
case 0x510006F2:
|
||||||
|
case 0x510006F3:
|
||||||
|
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report
|
||||||
|
// IDIV support.
|
||||||
|
info->features.idiva = true;
|
||||||
|
info->features.idivt = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Propagate cpu features.
|
||||||
|
if (info->features.vfpv4) info->features.vfpv3 = true;
|
||||||
|
if (info->features.neon) info->features.vfpv3 = true;
|
||||||
|
if (info->features.vfpv3) info->features.vfp = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillProcCpuInfoData(ArmInfo* const info,
|
||||||
|
ProcCpuInfoData* proc_cpu_info_data) {
|
||||||
|
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
for (;;) {
|
||||||
|
if (!HandleArmLine(StackLineReader_NextLine(&reader), info,
|
||||||
|
proc_cpu_info_data)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const ArmInfo kEmptyArmInfo;
|
||||||
|
|
||||||
|
static const ProcCpuInfoData kEmptyProcCpuInfoData;
|
||||||
|
|
||||||
|
ArmInfo GetArmInfo(void) {
|
||||||
|
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||||
|
// have some information if the executable is sandboxed (aka no access to
|
||||||
|
// /proc/cpuinfo).
|
||||||
|
ArmInfo info = kEmptyArmInfo;
|
||||||
|
ProcCpuInfoData proc_cpu_info_data = kEmptyProcCpuInfoData;
|
||||||
|
|
||||||
|
FillProcCpuInfoData(&info, &proc_cpu_info_data);
|
||||||
|
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||||
|
for (size_t i = 0; i < ARM_LAST_; ++i) {
|
||||||
|
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||||
|
kSetters[i](&info.features, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FixErrors(&info, &proc_cpu_info_data);
|
||||||
|
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
int GetArmFeaturesEnumValue(const ArmFeatures* features,
|
||||||
|
ArmFeaturesEnum value) {
|
||||||
|
if (value >= ARM_LAST_) return false;
|
||||||
|
return kGetters[value](features);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetArmFeaturesEnumName(ArmFeaturesEnum value) {
|
||||||
|
if (value >= ARM_LAST_) return "unknown feature";
|
||||||
|
return kCpuInfoFlags[value];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_mips.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
// Generation of feature's getters/setters functions and kGetters, kSetters,
|
||||||
|
// kCpuInfoFlags and kHardwareCapabilities global tables.
|
||||||
|
#define DEFINE_TABLE_FEATURES \
|
||||||
|
FEATURE(MIPS_MSA, msa, "msa", MIPS_HWCAP_MSA, 0) \
|
||||||
|
FEATURE(MIPS_EVA, eva, "eva", 0, 0) \
|
||||||
|
FEATURE(MIPS_R6, r6, "r6", MIPS_HWCAP_R6, 0)
|
||||||
|
#define DEFINE_TABLE_FEATURE_TYPE MipsFeatures
|
||||||
|
#include "define_tables.h"
|
||||||
|
|
||||||
|
static bool HandleMipsLine(const LineResult result,
|
||||||
|
MipsFeatures* const features) {
|
||||||
|
StringView key, value;
|
||||||
|
// See tests for an example.
|
||||||
|
if (CpuFeatures_StringView_GetAttributeKeyValue(result.line, &key, &value)) {
|
||||||
|
if (CpuFeatures_StringView_IsEquals(key, str("ASEs implemented"))) {
|
||||||
|
for (size_t i = 0; i < MIPS_LAST_; ++i) {
|
||||||
|
kSetters[i](features,
|
||||||
|
CpuFeatures_StringView_HasWord(value, kCpuInfoFlags[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !result.eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillProcCpuInfoData(MipsFeatures* const features) {
|
||||||
|
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
for (;;) {
|
||||||
|
if (!HandleMipsLine(StackLineReader_NextLine(&reader), features)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const MipsInfo kEmptyMipsInfo;
|
||||||
|
|
||||||
|
MipsInfo GetMipsInfo(void) {
|
||||||
|
// capabilities are fetched from both getauxval and /proc/cpuinfo so we can
|
||||||
|
// have some information if the executable is sandboxed (aka no access to
|
||||||
|
// /proc/cpuinfo).
|
||||||
|
MipsInfo info = kEmptyMipsInfo;
|
||||||
|
|
||||||
|
FillProcCpuInfoData(&info.features);
|
||||||
|
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||||
|
for (size_t i = 0; i < MIPS_LAST_; ++i) {
|
||||||
|
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||||
|
kSetters[i](&info.features, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
int GetMipsFeaturesEnumValue(const MipsFeatures* features,
|
||||||
|
MipsFeaturesEnum value) {
|
||||||
|
if (value >= MIPS_LAST_) return false;
|
||||||
|
return kGetters[value](features);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetMipsFeaturesEnumName(MipsFeaturesEnum value) {
|
||||||
|
if (value >= MIPS_LAST_) return "unknown feature";
|
||||||
|
return kCpuInfoFlags[value];
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,154 @@
|
||||||
|
// Copyright 2018 IBM.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_ppc.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "internal/bit_utils.h"
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
// Generation of feature's getters/setters functions and kGetters, kSetters,
|
||||||
|
// kCpuInfoFlags and kHardwareCapabilities global tables.
|
||||||
|
#define DEFINE_TABLE_FEATURES \
|
||||||
|
FEATURE(PPC_32, ppc32, "ppc32", PPC_FEATURE_32, 0) \
|
||||||
|
FEATURE(PPC_64, ppc64, "ppc64", PPC_FEATURE_64, 0) \
|
||||||
|
FEATURE(PPC_601_INSTR, ppc601, "ppc601", PPC_FEATURE_601_INSTR, 0) \
|
||||||
|
FEATURE(PPC_HAS_ALTIVEC, altivec, "altivec", PPC_FEATURE_HAS_ALTIVEC, 0) \
|
||||||
|
FEATURE(PPC_HAS_FPU, fpu, "fpu", PPC_FEATURE_HAS_FPU, 0) \
|
||||||
|
FEATURE(PPC_HAS_MMU, mmu, "mmu", PPC_FEATURE_HAS_MMU, 0) \
|
||||||
|
FEATURE(PPC_HAS_4xxMAC, mac_4xx, "4xxmac", PPC_FEATURE_HAS_4xxMAC, 0) \
|
||||||
|
FEATURE(PPC_UNIFIED_CACHE, unifiedcache, "ucache", \
|
||||||
|
PPC_FEATURE_UNIFIED_CACHE, 0) \
|
||||||
|
FEATURE(PPC_HAS_SPE, spe, "spe", PPC_FEATURE_HAS_SPE, 0) \
|
||||||
|
FEATURE(PPC_HAS_EFP_SINGLE, efpsingle, "efpsingle", \
|
||||||
|
PPC_FEATURE_HAS_EFP_SINGLE, 0) \
|
||||||
|
FEATURE(PPC_HAS_EFP_DOUBLE, efpdouble, "efpdouble", \
|
||||||
|
PPC_FEATURE_HAS_EFP_DOUBLE, 0) \
|
||||||
|
FEATURE(PPC_NO_TB, no_tb, "notb", PPC_FEATURE_NO_TB, 0) \
|
||||||
|
FEATURE(PPC_POWER4, power4, "power4", PPC_FEATURE_POWER4, 0) \
|
||||||
|
FEATURE(PPC_POWER5, power5, "power5", PPC_FEATURE_POWER5, 0) \
|
||||||
|
FEATURE(PPC_POWER5_PLUS, power5plus, "power5+", PPC_FEATURE_POWER5_PLUS, 0) \
|
||||||
|
FEATURE(PPC_CELL, cell, "cellbe", PPC_FEATURE_CELL, 0) \
|
||||||
|
FEATURE(PPC_BOOKE, booke, "booke", PPC_FEATURE_BOOKE, 0) \
|
||||||
|
FEATURE(PPC_SMT, smt, "smt", PPC_FEATURE_SMT, 0) \
|
||||||
|
FEATURE(PPC_ICACHE_SNOOP, icachesnoop, "ic_snoop", PPC_FEATURE_ICACHE_SNOOP, \
|
||||||
|
0) \
|
||||||
|
FEATURE(PPC_ARCH_2_05, arch205, "arch_2_05", PPC_FEATURE_ARCH_2_05, 0) \
|
||||||
|
FEATURE(PPC_PA6T, pa6t, "pa6t", PPC_FEATURE_PA6T, 0) \
|
||||||
|
FEATURE(PPC_HAS_DFP, dfp, "dfp", PPC_FEATURE_HAS_DFP, 0) \
|
||||||
|
FEATURE(PPC_POWER6_EXT, power6ext, "power6x", PPC_FEATURE_POWER6_EXT, 0) \
|
||||||
|
FEATURE(PPC_ARCH_2_06, arch206, "arch_2_06", PPC_FEATURE_ARCH_2_06, 0) \
|
||||||
|
FEATURE(PPC_HAS_VSX, vsx, "vsx", PPC_FEATURE_HAS_VSX, 0) \
|
||||||
|
FEATURE(PPC_PSERIES_PERFMON_COMPAT, pseries_perfmon_compat, "archpmu", \
|
||||||
|
PPC_FEATURE_PSERIES_PERFMON_COMPAT, 0) \
|
||||||
|
FEATURE(PPC_TRUE_LE, truele, "true_le", PPC_FEATURE_TRUE_LE, 0) \
|
||||||
|
FEATURE(PPC_PPC_LE, ppcle, "ppcle", PPC_FEATURE_PPC_LE, 0) \
|
||||||
|
FEATURE(PPC_ARCH_2_07, arch207, "arch_2_07", 0, PPC_FEATURE2_ARCH_2_07) \
|
||||||
|
FEATURE(PPC_HTM, htm, "htm", 0, PPC_FEATURE2_HTM) \
|
||||||
|
FEATURE(PPC_DSCR, dscr, "dscr", 0, PPC_FEATURE2_DSCR) \
|
||||||
|
FEATURE(PPC_EBB, ebb, "ebb", 0, PPC_FEATURE2_EBB) \
|
||||||
|
FEATURE(PPC_ISEL, isel, "isel", 0, PPC_FEATURE2_ISEL) \
|
||||||
|
FEATURE(PPC_TAR, tar, "tar", 0, PPC_FEATURE2_TAR) \
|
||||||
|
FEATURE(PPC_VEC_CRYPTO, vcrypto, "vcrypto", 0, PPC_FEATURE2_VEC_CRYPTO) \
|
||||||
|
FEATURE(PPC_HTM_NOSC, htm_nosc, "htm-nosc", 0, PPC_FEATURE2_HTM_NOSC) \
|
||||||
|
FEATURE(PPC_ARCH_3_00, arch300, "arch_3_00", 0, PPC_FEATURE2_ARCH_3_00) \
|
||||||
|
FEATURE(PPC_HAS_IEEE128, ieee128, "ieee128", 0, PPC_FEATURE2_HAS_IEEE128) \
|
||||||
|
FEATURE(PPC_DARN, darn, "darn", 0, PPC_FEATURE2_DARN) \
|
||||||
|
FEATURE(PPC_SCV, scv, "scv", 0, PPC_FEATURE2_SCV) \
|
||||||
|
FEATURE(PPC_HTM_NO_SUSPEND, htm_no_suspend, "htm-no-suspend", 0, \
|
||||||
|
PPC_FEATURE2_HTM_NO_SUSPEND)
|
||||||
|
#define DEFINE_TABLE_FEATURE_TYPE PPCFeatures
|
||||||
|
#include "define_tables.h"
|
||||||
|
|
||||||
|
static bool HandlePPCLine(const LineResult result,
|
||||||
|
PPCPlatformStrings* const strings) {
|
||||||
|
StringView line = result.line;
|
||||||
|
StringView key, value;
|
||||||
|
if (CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value)) {
|
||||||
|
if (CpuFeatures_StringView_HasWord(key, "platform")) {
|
||||||
|
CpuFeatures_StringView_CopyString(value, strings->platform,
|
||||||
|
sizeof(strings->platform));
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("model"))) {
|
||||||
|
CpuFeatures_StringView_CopyString(value, strings->model,
|
||||||
|
sizeof(strings->platform));
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("machine"))) {
|
||||||
|
CpuFeatures_StringView_CopyString(value, strings->machine,
|
||||||
|
sizeof(strings->platform));
|
||||||
|
} else if (CpuFeatures_StringView_IsEquals(key, str("cpu"))) {
|
||||||
|
CpuFeatures_StringView_CopyString(value, strings->cpu,
|
||||||
|
sizeof(strings->platform));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return !result.eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void FillProcCpuInfoData(PPCPlatformStrings* const strings) {
|
||||||
|
const int fd = CpuFeatures_OpenFile("/proc/cpuinfo");
|
||||||
|
if (fd >= 0) {
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, fd);
|
||||||
|
for (;;) {
|
||||||
|
if (!HandlePPCLine(StackLineReader_NextLine(&reader), strings)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PPCInfo kEmptyPPCInfo;
|
||||||
|
|
||||||
|
PPCInfo GetPPCInfo(void) {
|
||||||
|
/*
|
||||||
|
* On Power feature flags aren't currently in cpuinfo so we only look at
|
||||||
|
* the auxilary vector.
|
||||||
|
*/
|
||||||
|
PPCInfo info = kEmptyPPCInfo;
|
||||||
|
const HardwareCapabilities hwcaps = CpuFeatures_GetHardwareCapabilities();
|
||||||
|
for (size_t i = 0; i < PPC_LAST_; ++i) {
|
||||||
|
if (CpuFeatures_IsHwCapsSet(kHardwareCapabilities[i], hwcaps)) {
|
||||||
|
kSetters[i](&info.features, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return info;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PPCPlatformStrings kEmptyPPCPlatformStrings;
|
||||||
|
|
||||||
|
PPCPlatformStrings GetPPCPlatformStrings(void) {
|
||||||
|
PPCPlatformStrings strings = kEmptyPPCPlatformStrings;
|
||||||
|
|
||||||
|
FillProcCpuInfoData(&strings);
|
||||||
|
strings.type = CpuFeatures_GetPlatformType();
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Introspection functions
|
||||||
|
|
||||||
|
int GetPPCFeaturesEnumValue(const PPCFeatures* features,
|
||||||
|
PPCFeaturesEnum value) {
|
||||||
|
if (value >= PPC_LAST_) return false;
|
||||||
|
return kGetters[value](features);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char* GetPPCFeaturesEnumName(PPCFeaturesEnum value) {
|
||||||
|
if (value >= PPC_LAST_) return "unknown feature";
|
||||||
|
return kCpuInfoFlags[value];
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,67 @@
|
||||||
|
// Copyright 2020 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// The following preprocessor constants must be defined before including this
|
||||||
|
// file:
|
||||||
|
// - DEFINE_TABLE_FEATURE_TYPE, the underlying type (e.g. X86Features)
|
||||||
|
// - DEFINE_TABLE_FEATURES, the list of FEATURE macros to be inserted.
|
||||||
|
|
||||||
|
// This file is to be included once per `cpuinfo_XXX.c` in order to construct
|
||||||
|
// feature getters and setters functions as well as several enum indexed tables
|
||||||
|
// from the db file.
|
||||||
|
// - `kGetters` a table of getters function pointers from feature enum to
|
||||||
|
// retrieve a feature,
|
||||||
|
// - `kSetters` a table of setters function pointers from feature enum to set a
|
||||||
|
// feature,
|
||||||
|
// - `kCpuInfoFlags` a table of strings from feature enum to /proc/cpuinfo
|
||||||
|
// flags,
|
||||||
|
// - `kHardwareCapabilities` a table of HardwareCapabilities structs indexed by
|
||||||
|
// their feature enum.
|
||||||
|
|
||||||
|
#ifndef SRC_DEFINE_TABLES_H_
|
||||||
|
#define SRC_DEFINE_TABLES_H_
|
||||||
|
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = CPUINFO_FLAG,
|
||||||
|
static const char* kCpuInfoFlags[] = {DEFINE_TABLE_FEATURES};
|
||||||
|
#undef FEATURE
|
||||||
|
|
||||||
|
#ifndef DEFINE_TABLE_DONT_GENERATE_HWCAPS
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
|
||||||
|
[ENUM] = (HardwareCapabilities){HWCAP, HWCAP2},
|
||||||
|
static const HardwareCapabilities kHardwareCapabilities[] = {
|
||||||
|
DEFINE_TABLE_FEATURES};
|
||||||
|
#undef FEATURE
|
||||||
|
#endif // DEFINE_TABLE_DONT_GENERATE_HWCAPS
|
||||||
|
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) \
|
||||||
|
static void set_##ENUM(DEFINE_TABLE_FEATURE_TYPE* features, bool value) { \
|
||||||
|
features->NAME = value; \
|
||||||
|
} \
|
||||||
|
static int get_##ENUM(const DEFINE_TABLE_FEATURE_TYPE* features) { \
|
||||||
|
return features->NAME; \
|
||||||
|
}
|
||||||
|
DEFINE_TABLE_FEATURES
|
||||||
|
#undef FEATURE
|
||||||
|
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = set_##ENUM,
|
||||||
|
static void (*const kSetters[])(DEFINE_TABLE_FEATURE_TYPE*,
|
||||||
|
bool) = {DEFINE_TABLE_FEATURES};
|
||||||
|
#undef FEATURE
|
||||||
|
|
||||||
|
#define FEATURE(ENUM, NAME, CPUINFO_FLAG, HWCAP, HWCAP2) [ENUM] = get_##ENUM,
|
||||||
|
static int (*const kGetters[])(const DEFINE_TABLE_FEATURE_TYPE*) = {
|
||||||
|
DEFINE_TABLE_FEATURES};
|
||||||
|
#undef FEATURE
|
||||||
|
|
||||||
|
#endif // SRC_DEFINE_TABLES_H_
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_MOCK_FILESYSTEM)
|
||||||
|
// Implementation will be provided by test/filesystem_for_testing.cc.
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#include <io.h>
|
||||||
|
int CpuFeatures_OpenFile(const char* filename) {
|
||||||
|
int fd = -1;
|
||||||
|
_sopen_s(&fd, filename, _O_RDONLY, _SH_DENYWR, _S_IREAD);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CpuFeatures_CloseFile(int file_descriptor) { _close(file_descriptor); }
|
||||||
|
|
||||||
|
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||||
|
size_t buffer_size) {
|
||||||
|
return _read(file_descriptor, buffer, (unsigned int)buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
int CpuFeatures_OpenFile(const char* filename) {
|
||||||
|
int result;
|
||||||
|
do {
|
||||||
|
result = open(filename, O_RDONLY);
|
||||||
|
} while (result == -1L && errno == EINTR);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CpuFeatures_CloseFile(int file_descriptor) { close(file_descriptor); }
|
||||||
|
|
||||||
|
int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||||
|
size_t buffer_size) {
|
||||||
|
int result;
|
||||||
|
do {
|
||||||
|
result = read(file_descriptor, buffer, buffer_size);
|
||||||
|
} while (result == -1L && errno == EINTR);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
static bool IsSet(const uint32_t mask, const uint32_t value) {
|
||||||
|
if (mask == 0) return false;
|
||||||
|
return (value & mask) == mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_IsHwCapsSet(const HardwareCapabilities hwcaps_mask,
|
||||||
|
const HardwareCapabilities hwcaps) {
|
||||||
|
return IsSet(hwcaps_mask.hwcaps, hwcaps.hwcaps) ||
|
||||||
|
IsSet(hwcaps_mask.hwcaps2, hwcaps.hwcaps2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CPU_FEATURES_TEST
|
||||||
|
// In test mode, hwcaps_for_testing will define the following functions.
|
||||||
|
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void);
|
||||||
|
PlatformType CpuFeatures_GetPlatformType(void);
|
||||||
|
#else
|
||||||
|
|
||||||
|
// Debug facilities
|
||||||
|
#if defined(NDEBUG)
|
||||||
|
#define D(...)
|
||||||
|
#else
|
||||||
|
#include <stdio.h>
|
||||||
|
#define D(...) \
|
||||||
|
do { \
|
||||||
|
printf(__VA_ARGS__); \
|
||||||
|
fflush(stdout); \
|
||||||
|
} while (0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Implementation of GetElfHwcapFromGetauxval
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
#define AT_HWCAP 16
|
||||||
|
#define AT_HWCAP2 26
|
||||||
|
#define AT_PLATFORM 15
|
||||||
|
#define AT_BASE_PLATFORM 24
|
||||||
|
|
||||||
|
#if defined(HAVE_STRONG_GETAUXVAL)
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
static unsigned long GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||||
|
return getauxval(hwcap_type);
|
||||||
|
}
|
||||||
|
#elif defined(HAVE_DLFCN_H)
|
||||||
|
// On Android we probe the system's C library for a 'getauxval' function and
|
||||||
|
// call it if it exits, or return 0 for failure. This function is available
|
||||||
|
// since API level 20.
|
||||||
|
//
|
||||||
|
// This code does *NOT* check for '__ANDROID_API__ >= 20' to support the edge
|
||||||
|
// case where some NDK developers use headers for a platform that is newer than
|
||||||
|
// the one really targetted by their application. This is typically done to use
|
||||||
|
// newer native APIs only when running on more recent Android versions, and
|
||||||
|
// requires careful symbol management.
|
||||||
|
//
|
||||||
|
// Note that getauxval() can't really be re-implemented here, because its
|
||||||
|
// implementation does not parse /proc/self/auxv. Instead it depends on values
|
||||||
|
// that are passed by the kernel at process-init time to the C runtime
|
||||||
|
// initialization layer.
|
||||||
|
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
typedef unsigned long getauxval_func_t(unsigned long);
|
||||||
|
|
||||||
|
static uint32_t GetElfHwcapFromGetauxval(uint32_t hwcap_type) {
|
||||||
|
uint32_t ret = 0;
|
||||||
|
void *libc_handle = NULL;
|
||||||
|
getauxval_func_t *func = NULL;
|
||||||
|
|
||||||
|
dlerror(); // Cleaning error state before calling dlopen.
|
||||||
|
libc_handle = dlopen("libc.so", RTLD_NOW);
|
||||||
|
if (!libc_handle) {
|
||||||
|
D("Could not dlopen() C library: %s\n", dlerror());
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
func = (getauxval_func_t *)dlsym(libc_handle, "getauxval");
|
||||||
|
if (!func) {
|
||||||
|
D("Could not find getauxval() in C library\n");
|
||||||
|
} else {
|
||||||
|
// Note: getauxval() returns 0 on failure. Doesn't touch errno.
|
||||||
|
ret = (uint32_t)(*func)(hwcap_type);
|
||||||
|
}
|
||||||
|
dlclose(libc_handle);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
#error "This platform does not provide hardware capabilities."
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Implementation of GetHardwareCapabilities for OS that provide
|
||||||
|
// GetElfHwcapFromGetauxval().
|
||||||
|
|
||||||
|
// Fallback when getauxval is not available, retrieves hwcaps from
|
||||||
|
// "/proc/self/auxv".
|
||||||
|
static uint32_t GetElfHwcapFromProcSelfAuxv(uint32_t hwcap_type) {
|
||||||
|
struct {
|
||||||
|
uint32_t tag;
|
||||||
|
uint32_t value;
|
||||||
|
} entry;
|
||||||
|
uint32_t result = 0;
|
||||||
|
const char filepath[] = "/proc/self/auxv";
|
||||||
|
const int fd = CpuFeatures_OpenFile(filepath);
|
||||||
|
if (fd < 0) {
|
||||||
|
D("Could not open %s\n", filepath);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (;;) {
|
||||||
|
const int ret = CpuFeatures_ReadFile(fd, (char *)&entry, sizeof entry);
|
||||||
|
if (ret < 0) {
|
||||||
|
D("Error while reading %s\n", filepath);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Detect end of list.
|
||||||
|
if (ret == 0 || (entry.tag == 0 && entry.value == 0)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (entry.tag == hwcap_type) {
|
||||||
|
result = entry.value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
CpuFeatures_CloseFile(fd);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves hardware capabilities by first trying to call getauxval, if not
|
||||||
|
// available falls back to reading "/proc/self/auxv".
|
||||||
|
static unsigned long GetHardwareCapabilitiesFor(uint32_t type) {
|
||||||
|
unsigned long hwcaps = GetElfHwcapFromGetauxval(type);
|
||||||
|
if (!hwcaps) {
|
||||||
|
D("Parsing /proc/self/auxv to extract ELF hwcaps!\n");
|
||||||
|
hwcaps = GetElfHwcapFromProcSelfAuxv(type);
|
||||||
|
}
|
||||||
|
return hwcaps;
|
||||||
|
}
|
||||||
|
|
||||||
|
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
|
||||||
|
HardwareCapabilities capabilities;
|
||||||
|
capabilities.hwcaps = GetHardwareCapabilitiesFor(AT_HWCAP);
|
||||||
|
capabilities.hwcaps2 = GetHardwareCapabilitiesFor(AT_HWCAP2);
|
||||||
|
return capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformType kEmptyPlatformType;
|
||||||
|
|
||||||
|
PlatformType CpuFeatures_GetPlatformType(void) {
|
||||||
|
PlatformType type = kEmptyPlatformType;
|
||||||
|
char *platform = (char *)GetHardwareCapabilitiesFor(AT_PLATFORM);
|
||||||
|
char *base_platform = (char *)GetHardwareCapabilitiesFor(AT_BASE_PLATFORM);
|
||||||
|
|
||||||
|
if (platform != NULL)
|
||||||
|
CpuFeatures_StringView_CopyString(str(platform), type.platform,
|
||||||
|
sizeof(type.platform));
|
||||||
|
if (base_platform != NULL)
|
||||||
|
CpuFeatures_StringView_CopyString(str(base_platform), type.base_platform,
|
||||||
|
sizeof(type.base_platform));
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_TEST
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
|
||||||
|
void StackLineReader_Initialize(StackLineReader* reader, int fd) {
|
||||||
|
reader->view.ptr = reader->buffer;
|
||||||
|
reader->view.size = 0;
|
||||||
|
reader->skip_mode = false;
|
||||||
|
reader->fd = fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Replaces the content of buffer with bytes from the file.
|
||||||
|
static int LoadFullBuffer(StackLineReader* reader) {
|
||||||
|
const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
|
||||||
|
STACK_LINE_READER_BUFFER_SIZE);
|
||||||
|
assert(read >= 0);
|
||||||
|
reader->view.ptr = reader->buffer;
|
||||||
|
reader->view.size = read;
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Appends with bytes from the file to buffer, filling the remaining space.
|
||||||
|
static int LoadMore(StackLineReader* reader) {
|
||||||
|
char* const ptr = reader->buffer + reader->view.size;
|
||||||
|
const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
|
||||||
|
const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
|
||||||
|
assert(read >= 0);
|
||||||
|
assert(read <= (int)size_to_read);
|
||||||
|
reader->view.size += read;
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int IndexOfEol(StackLineReader* reader) {
|
||||||
|
return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Relocate buffer's pending bytes at the beginning of the array and fills the
|
||||||
|
// remaining space with bytes from the file.
|
||||||
|
static int BringToFrontAndLoadMore(StackLineReader* reader) {
|
||||||
|
if (reader->view.size && reader->view.ptr != reader->buffer) {
|
||||||
|
memmove(reader->buffer, reader->view.ptr, reader->view.size);
|
||||||
|
}
|
||||||
|
reader->view.ptr = reader->buffer;
|
||||||
|
return LoadMore(reader);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loads chunks of buffer size from disks until it contains a newline character
|
||||||
|
// or end of file.
|
||||||
|
static void SkipToNextLine(StackLineReader* reader) {
|
||||||
|
for (;;) {
|
||||||
|
const int read = LoadFullBuffer(reader);
|
||||||
|
if (read == 0) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
const int eol_index = IndexOfEol(reader);
|
||||||
|
if (eol_index >= 0) {
|
||||||
|
reader->view =
|
||||||
|
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
|
||||||
|
LineResult result;
|
||||||
|
result.eof = eof;
|
||||||
|
result.full_line = full_line;
|
||||||
|
result.line = view;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper methods to provide clearer semantic in StackLineReader_NextLine.
|
||||||
|
static LineResult CreateEOFLineResult(StringView view) {
|
||||||
|
return CreateLineResult(true, true, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LineResult CreateTruncatedLineResult(StringView view) {
|
||||||
|
return CreateLineResult(false, false, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
static LineResult CreateValidLineResult(StringView view) {
|
||||||
|
return CreateLineResult(false, true, view);
|
||||||
|
}
|
||||||
|
|
||||||
|
LineResult StackLineReader_NextLine(StackLineReader* reader) {
|
||||||
|
if (reader->skip_mode) {
|
||||||
|
SkipToNextLine(reader);
|
||||||
|
reader->skip_mode = false;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const bool can_load_more =
|
||||||
|
reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
|
||||||
|
int eol_index = IndexOfEol(reader);
|
||||||
|
if (eol_index < 0 && can_load_more) {
|
||||||
|
const int read = BringToFrontAndLoadMore(reader);
|
||||||
|
if (read == 0) {
|
||||||
|
return CreateEOFLineResult(reader->view);
|
||||||
|
}
|
||||||
|
eol_index = IndexOfEol(reader);
|
||||||
|
}
|
||||||
|
if (eol_index < 0) {
|
||||||
|
reader->skip_mode = true;
|
||||||
|
return CreateTruncatedLineResult(reader->view);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
StringView line =
|
||||||
|
CpuFeatures_StringView_KeepFront(reader->view, eol_index);
|
||||||
|
reader->view =
|
||||||
|
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
|
||||||
|
return CreateValidLineResult(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,182 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
int CpuFeatures_StringView_IndexOfChar(const StringView view, char c) {
|
||||||
|
if (view.ptr && view.size) {
|
||||||
|
const char* const found = (const char*)memchr(view.ptr, c, view.size);
|
||||||
|
if (found) {
|
||||||
|
return (int)(found - view.ptr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CpuFeatures_StringView_IndexOf(const StringView view,
|
||||||
|
const StringView sub_view) {
|
||||||
|
if (sub_view.size) {
|
||||||
|
StringView remainder = view;
|
||||||
|
while (remainder.size >= sub_view.size) {
|
||||||
|
const int found_index =
|
||||||
|
CpuFeatures_StringView_IndexOfChar(remainder, sub_view.ptr[0]);
|
||||||
|
if (found_index < 0) break;
|
||||||
|
remainder = CpuFeatures_StringView_PopFront(remainder, found_index);
|
||||||
|
if (CpuFeatures_StringView_StartsWith(remainder, sub_view)) {
|
||||||
|
return (int)(remainder.ptr - view.ptr);
|
||||||
|
}
|
||||||
|
remainder = CpuFeatures_StringView_PopFront(remainder, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_StringView_IsEquals(const StringView a, const StringView b) {
|
||||||
|
if (a.size == b.size) {
|
||||||
|
return a.ptr == b.ptr || memcmp(a.ptr, b.ptr, b.size) == 0;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_StringView_StartsWith(const StringView a, const StringView b) {
|
||||||
|
return a.ptr && b.ptr && b.size && a.size >= b.size
|
||||||
|
? memcmp(a.ptr, b.ptr, b.size) == 0
|
||||||
|
: false;
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView CpuFeatures_StringView_PopFront(const StringView str_view,
|
||||||
|
size_t count) {
|
||||||
|
if (count > str_view.size) {
|
||||||
|
return kEmptyStringView;
|
||||||
|
}
|
||||||
|
return view(str_view.ptr + count, str_view.size - count);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView CpuFeatures_StringView_PopBack(const StringView str_view,
|
||||||
|
size_t count) {
|
||||||
|
if (count > str_view.size) {
|
||||||
|
return kEmptyStringView;
|
||||||
|
}
|
||||||
|
return view(str_view.ptr, str_view.size - count);
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView CpuFeatures_StringView_KeepFront(const StringView str_view,
|
||||||
|
size_t count) {
|
||||||
|
return count <= str_view.size ? view(str_view.ptr, count) : str_view;
|
||||||
|
}
|
||||||
|
|
||||||
|
char CpuFeatures_StringView_Front(const StringView view) {
|
||||||
|
assert(view.size);
|
||||||
|
assert(view.ptr);
|
||||||
|
return view.ptr[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
char CpuFeatures_StringView_Back(const StringView view) {
|
||||||
|
assert(view.size);
|
||||||
|
return view.ptr[view.size - 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
StringView CpuFeatures_StringView_TrimWhitespace(StringView view) {
|
||||||
|
while (view.size && isspace(CpuFeatures_StringView_Front(view)))
|
||||||
|
view = CpuFeatures_StringView_PopFront(view, 1);
|
||||||
|
while (view.size && isspace(CpuFeatures_StringView_Back(view)))
|
||||||
|
view = CpuFeatures_StringView_PopBack(view, 1);
|
||||||
|
return view;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int HexValue(const char c) {
|
||||||
|
if (c >= '0' && c <= '9') return c - '0';
|
||||||
|
if (c >= 'a' && c <= 'f') return c - 'a' + 10;
|
||||||
|
if (c >= 'A' && c <= 'F') return c - 'A' + 10;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns -1 if view contains non digits.
|
||||||
|
static int ParsePositiveNumberWithBase(const StringView view, int base) {
|
||||||
|
int result = 0;
|
||||||
|
StringView remainder = view;
|
||||||
|
for (; remainder.size;
|
||||||
|
remainder = CpuFeatures_StringView_PopFront(remainder, 1)) {
|
||||||
|
const int value = HexValue(CpuFeatures_StringView_Front(remainder));
|
||||||
|
if (value < 0 || value >= base) return -1;
|
||||||
|
result = (result * base) + value;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
int CpuFeatures_StringView_ParsePositiveNumber(const StringView view) {
|
||||||
|
if (view.size) {
|
||||||
|
const StringView hex_prefix = str("0x");
|
||||||
|
if (CpuFeatures_StringView_StartsWith(view, hex_prefix)) {
|
||||||
|
const StringView span_no_prefix =
|
||||||
|
CpuFeatures_StringView_PopFront(view, hex_prefix.size);
|
||||||
|
return ParsePositiveNumberWithBase(span_no_prefix, 16);
|
||||||
|
}
|
||||||
|
return ParsePositiveNumberWithBase(view, 10);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CpuFeatures_StringView_CopyString(const StringView src, char* dst,
|
||||||
|
size_t dst_size) {
|
||||||
|
if (dst_size > 0) {
|
||||||
|
const size_t max_copy_size = dst_size - 1;
|
||||||
|
const size_t copy_size =
|
||||||
|
src.size > max_copy_size ? max_copy_size : src.size;
|
||||||
|
memcpy(dst, src.ptr, copy_size);
|
||||||
|
dst[copy_size] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_StringView_HasWord(const StringView line,
|
||||||
|
const char* const word_str) {
|
||||||
|
const StringView word = str(word_str);
|
||||||
|
StringView remainder = line;
|
||||||
|
for (;;) {
|
||||||
|
const int index_of_word = CpuFeatures_StringView_IndexOf(remainder, word);
|
||||||
|
if (index_of_word < 0) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
const StringView before =
|
||||||
|
CpuFeatures_StringView_KeepFront(line, index_of_word);
|
||||||
|
const StringView after =
|
||||||
|
CpuFeatures_StringView_PopFront(line, index_of_word + word.size);
|
||||||
|
const bool valid_before =
|
||||||
|
before.size == 0 || CpuFeatures_StringView_Back(before) == ' ';
|
||||||
|
const bool valid_after =
|
||||||
|
after.size == 0 || CpuFeatures_StringView_Front(after) == ' ';
|
||||||
|
if (valid_before && valid_after) return true;
|
||||||
|
remainder =
|
||||||
|
CpuFeatures_StringView_PopFront(remainder, index_of_word + word.size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CpuFeatures_StringView_GetAttributeKeyValue(const StringView line,
|
||||||
|
StringView* key,
|
||||||
|
StringView* value) {
|
||||||
|
const StringView sep = str(": ");
|
||||||
|
const int index_of_separator = CpuFeatures_StringView_IndexOf(line, sep);
|
||||||
|
if (index_of_separator < 0) return false;
|
||||||
|
*value = CpuFeatures_StringView_TrimWhitespace(
|
||||||
|
CpuFeatures_StringView_PopFront(line, index_of_separator + sep.size));
|
||||||
|
*key = CpuFeatures_StringView_TrimWhitespace(
|
||||||
|
CpuFeatures_StringView_KeepFront(line, index_of_separator));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,438 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// This program dumps current host data to the standard output.
|
||||||
|
// Output can be text or json if the `--json` flag is passed.
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "cpu_features_macros.h"
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
#include "cpuinfo_mips.h"
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
#include "cpuinfo_ppc.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Design principles
|
||||||
|
// -----------------
|
||||||
|
// We build a tree structure containing all the data to be displayed.
|
||||||
|
// Then depending on the output type (text or json) we walk the tree and display
|
||||||
|
// the data accordingly.
|
||||||
|
|
||||||
|
// We use a bump allocator to allocate strings and nodes of the tree,
|
||||||
|
// Memory is not intended to be reclaimed.
|
||||||
|
typedef struct {
|
||||||
|
char* ptr;
|
||||||
|
size_t size;
|
||||||
|
} BumpAllocator;
|
||||||
|
|
||||||
|
char gGlobalBuffer[64 * 1024];
|
||||||
|
BumpAllocator gBumpAllocator = {.ptr = gGlobalBuffer,
|
||||||
|
.size = sizeof(gGlobalBuffer)};
|
||||||
|
|
||||||
|
static void internal_error() {
|
||||||
|
fputs("internal error\n", stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define ALIGN 8
|
||||||
|
|
||||||
|
static void assertAligned() {
|
||||||
|
if ((uintptr_t)(gBumpAllocator.ptr) % ALIGN) internal_error();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void BA_Align() {
|
||||||
|
while (gBumpAllocator.size && (uintptr_t)(gBumpAllocator.ptr) % ALIGN) {
|
||||||
|
--gBumpAllocator.size;
|
||||||
|
++gBumpAllocator.ptr;
|
||||||
|
}
|
||||||
|
assertAligned();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update the available memory left in the BumpAllocator.
|
||||||
|
static void* BA_Bump(size_t size) {
|
||||||
|
assertAligned();
|
||||||
|
// Align size to next 8B boundary.
|
||||||
|
size = (size + ALIGN - 1) / ALIGN * ALIGN;
|
||||||
|
if (gBumpAllocator.size < size) internal_error();
|
||||||
|
void* ptr = gBumpAllocator.ptr;
|
||||||
|
gBumpAllocator.size -= size;
|
||||||
|
gBumpAllocator.ptr += size;
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The type of the nodes in the tree.
|
||||||
|
typedef enum {
|
||||||
|
NT_INVALID,
|
||||||
|
NT_INT,
|
||||||
|
NT_MAP,
|
||||||
|
NT_MAP_ENTRY,
|
||||||
|
NT_ARRAY,
|
||||||
|
NT_ARRAY_ELEMENT,
|
||||||
|
NT_STRING,
|
||||||
|
} NodeType;
|
||||||
|
|
||||||
|
// The node in the tree.
|
||||||
|
typedef struct Node {
|
||||||
|
NodeType type;
|
||||||
|
unsigned integer;
|
||||||
|
const char* string;
|
||||||
|
struct Node* value;
|
||||||
|
struct Node* next;
|
||||||
|
} Node;
|
||||||
|
|
||||||
|
// Creates an initialized Node.
|
||||||
|
static Node* BA_CreateNode(NodeType type) {
|
||||||
|
Node* tv = (Node*)BA_Bump(sizeof(Node));
|
||||||
|
assert(tv);
|
||||||
|
*tv = (Node){.type = type};
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an integer node.
|
||||||
|
static Node* CreateInt(int value) {
|
||||||
|
Node* tv = BA_CreateNode(NT_INT);
|
||||||
|
tv->integer = value;
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a string node.
|
||||||
|
// `value` must outlive the tree.
|
||||||
|
static Node* CreateConstantString(const char* value) {
|
||||||
|
Node* tv = BA_CreateNode(NT_STRING);
|
||||||
|
tv->string = value;
|
||||||
|
return tv;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a map node.
|
||||||
|
static Node* CreateMap() { return BA_CreateNode(NT_MAP); }
|
||||||
|
|
||||||
|
// Adds an array node.
|
||||||
|
static Node* CreateArray() { return BA_CreateNode(NT_ARRAY); }
|
||||||
|
|
||||||
|
// Adds a formatted string node.
|
||||||
|
static Node* CreatePrintfString(const char* format, ...) {
|
||||||
|
va_list arglist;
|
||||||
|
va_start(arglist, format);
|
||||||
|
char* const ptr = gBumpAllocator.ptr;
|
||||||
|
const int written = vsnprintf(ptr, gBumpAllocator.size, format, arglist);
|
||||||
|
va_end(arglist);
|
||||||
|
if (written < 0 || written >= (int)gBumpAllocator.size) internal_error();
|
||||||
|
return CreateConstantString((char*)BA_Bump(written));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a string node.
|
||||||
|
static Node* CreateString(const char* value) {
|
||||||
|
return CreatePrintfString("%s", value);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a map entry node.
|
||||||
|
static void AddMapEntry(Node* map, const char* key, Node* value) {
|
||||||
|
assert(map && map->type == NT_MAP);
|
||||||
|
Node* current = map;
|
||||||
|
while (current->next) current = current->next;
|
||||||
|
current->next = (Node*)BA_Bump(sizeof(Node));
|
||||||
|
*current->next = (Node){.type = NT_MAP_ENTRY, .string = key, .value = value};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds an array element node.
|
||||||
|
static void AddArrayElement(Node* array, Node* value) {
|
||||||
|
assert(array && array->type == NT_ARRAY);
|
||||||
|
Node* current = array;
|
||||||
|
while (current->next) current = current->next;
|
||||||
|
current->next = (Node*)BA_Bump(sizeof(Node));
|
||||||
|
*current->next = (Node){.type = NT_ARRAY_ELEMENT, .value = value};
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cmp(const void* p1, const void* p2) {
|
||||||
|
return strcmp(*(const char* const*)p1, *(const char* const*)p2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define DEFINE_ADD_FLAGS(HasFeature, FeatureName, FeatureType, LastEnum) \
|
||||||
|
static void AddFlags(Node* map, const FeatureType* features) { \
|
||||||
|
size_t i; \
|
||||||
|
const char* ptrs[LastEnum] = {0}; \
|
||||||
|
size_t count = 0; \
|
||||||
|
for (i = 0; i < LastEnum; ++i) { \
|
||||||
|
if (HasFeature(features, i)) { \
|
||||||
|
ptrs[count] = FeatureName(i); \
|
||||||
|
++count; \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
qsort((void*)ptrs, count, sizeof(char*), cmp); \
|
||||||
|
Node* const array = CreateArray(); \
|
||||||
|
for (i = 0; i < count; ++i) \
|
||||||
|
AddArrayElement(array, CreateConstantString(ptrs[i])); \
|
||||||
|
AddMapEntry(map, "flags", array); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
DEFINE_ADD_FLAGS(GetX86FeaturesEnumValue, GetX86FeaturesEnumName, X86Features,
|
||||||
|
X86_LAST_)
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
DEFINE_ADD_FLAGS(GetArmFeaturesEnumValue, GetArmFeaturesEnumName, ArmFeatures,
|
||||||
|
ARM_LAST_)
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
DEFINE_ADD_FLAGS(GetAarch64FeaturesEnumValue, GetAarch64FeaturesEnumName,
|
||||||
|
Aarch64Features, AARCH64_LAST_)
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
DEFINE_ADD_FLAGS(GetMipsFeaturesEnumValue, GetMipsFeaturesEnumName,
|
||||||
|
MipsFeatures, MIPS_LAST_)
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
DEFINE_ADD_FLAGS(GetPPCFeaturesEnumValue, GetPPCFeaturesEnumName, PPCFeatures,
|
||||||
|
PPC_LAST_)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Prints a json string with characters escaping.
|
||||||
|
static void printJsonString(const char* str) {
|
||||||
|
putchar('"');
|
||||||
|
for (; str && *str; ++str) {
|
||||||
|
switch (*str) {
|
||||||
|
case '\"':
|
||||||
|
case '\\':
|
||||||
|
case '/':
|
||||||
|
case '\b':
|
||||||
|
case '\f':
|
||||||
|
case '\n':
|
||||||
|
case '\r':
|
||||||
|
case '\t':
|
||||||
|
putchar('\\');
|
||||||
|
}
|
||||||
|
putchar(*str);
|
||||||
|
}
|
||||||
|
putchar('"');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walks a Node and print it as json.
|
||||||
|
static void printJson(const Node* current) {
|
||||||
|
assert(current);
|
||||||
|
switch (current->type) {
|
||||||
|
case NT_INVALID:
|
||||||
|
break;
|
||||||
|
case NT_INT:
|
||||||
|
printf("%d", current->integer);
|
||||||
|
break;
|
||||||
|
case NT_STRING:
|
||||||
|
printJsonString(current->string);
|
||||||
|
break;
|
||||||
|
case NT_ARRAY:
|
||||||
|
putchar('[');
|
||||||
|
if (current->next) printJson(current->next);
|
||||||
|
putchar(']');
|
||||||
|
break;
|
||||||
|
case NT_MAP:
|
||||||
|
putchar('{');
|
||||||
|
if (current->next) printJson(current->next);
|
||||||
|
putchar('}');
|
||||||
|
break;
|
||||||
|
case NT_MAP_ENTRY:
|
||||||
|
printf("\"%s\":", current->string);
|
||||||
|
printJson(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar(',');
|
||||||
|
printJson(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_ARRAY_ELEMENT:
|
||||||
|
printJson(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar(',');
|
||||||
|
printJson(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Walks a Node and print it as text.
|
||||||
|
static void printTextField(const Node* current) {
|
||||||
|
switch (current->type) {
|
||||||
|
case NT_INVALID:
|
||||||
|
break;
|
||||||
|
case NT_INT:
|
||||||
|
printf("%3d (0x%02X)", current->integer, current->integer);
|
||||||
|
break;
|
||||||
|
case NT_STRING:
|
||||||
|
fputs(current->string, stdout);
|
||||||
|
break;
|
||||||
|
case NT_ARRAY:
|
||||||
|
if (current->next) printTextField(current->next);
|
||||||
|
break;
|
||||||
|
case NT_MAP:
|
||||||
|
if (current->next) {
|
||||||
|
printf("{");
|
||||||
|
printJson(current->next);
|
||||||
|
printf("}");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_MAP_ENTRY:
|
||||||
|
printf("%-15s : ", current->string);
|
||||||
|
printTextField(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar('\n');
|
||||||
|
printTextField(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case NT_ARRAY_ELEMENT:
|
||||||
|
printTextField(current->value);
|
||||||
|
if (current->next) {
|
||||||
|
putchar(',');
|
||||||
|
printTextField(current->next);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printTextRoot(const Node* current) {
|
||||||
|
if (current->type == NT_MAP && current->next) printTextField(current->next);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void showUsage(const char* name) {
|
||||||
|
printf(
|
||||||
|
"\n"
|
||||||
|
"Usage: %s [options]\n"
|
||||||
|
" Options:\n"
|
||||||
|
" -h | --help Show help message.\n"
|
||||||
|
" -j | --json Format output as json instead of plain text.\n"
|
||||||
|
"\n",
|
||||||
|
name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node* GetCacheTypeString(CacheType cache_type) {
|
||||||
|
switch (cache_type) {
|
||||||
|
case CPU_FEATURE_CACHE_NULL:
|
||||||
|
return CreateConstantString("null");
|
||||||
|
case CPU_FEATURE_CACHE_DATA:
|
||||||
|
return CreateConstantString("data");
|
||||||
|
case CPU_FEATURE_CACHE_INSTRUCTION:
|
||||||
|
return CreateConstantString("instruction");
|
||||||
|
case CPU_FEATURE_CACHE_UNIFIED:
|
||||||
|
return CreateConstantString("unified");
|
||||||
|
case CPU_FEATURE_CACHE_TLB:
|
||||||
|
return CreateConstantString("tlb");
|
||||||
|
case CPU_FEATURE_CACHE_DTLB:
|
||||||
|
return CreateConstantString("dtlb");
|
||||||
|
case CPU_FEATURE_CACHE_STLB:
|
||||||
|
return CreateConstantString("stlb");
|
||||||
|
case CPU_FEATURE_CACHE_PREFETCH:
|
||||||
|
return CreateConstantString("prefetch");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void AddCacheInfo(Node* root, const CacheInfo* cache_info) {
|
||||||
|
Node* array = CreateArray();
|
||||||
|
for (int i = 0; i < cache_info->size; ++i) {
|
||||||
|
CacheLevelInfo info = cache_info->levels[i];
|
||||||
|
Node* map = CreateMap();
|
||||||
|
AddMapEntry(map, "level", CreateInt(info.level));
|
||||||
|
AddMapEntry(map, "cache_type", GetCacheTypeString(info.cache_type));
|
||||||
|
AddMapEntry(map, "cache_size", CreateInt(info.cache_size));
|
||||||
|
AddMapEntry(map, "ways", CreateInt(info.ways));
|
||||||
|
AddMapEntry(map, "line_size", CreateInt(info.line_size));
|
||||||
|
AddMapEntry(map, "tlb_entries", CreateInt(info.tlb_entries));
|
||||||
|
AddMapEntry(map, "partitioning", CreateInt(info.partitioning));
|
||||||
|
AddArrayElement(array, map);
|
||||||
|
}
|
||||||
|
AddMapEntry(root, "cache_info", array);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Node* CreateTree() {
|
||||||
|
Node* root = CreateMap();
|
||||||
|
#if defined(CPU_FEATURES_ARCH_X86)
|
||||||
|
char brand_string[49];
|
||||||
|
const X86Info info = GetX86Info();
|
||||||
|
const CacheInfo cache_info = GetX86CacheInfo();
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
AddMapEntry(root, "arch", CreateString("x86"));
|
||||||
|
AddMapEntry(root, "brand", CreateString(brand_string));
|
||||||
|
AddMapEntry(root, "family", CreateInt(info.family));
|
||||||
|
AddMapEntry(root, "model", CreateInt(info.model));
|
||||||
|
AddMapEntry(root, "stepping", CreateInt(info.stepping));
|
||||||
|
AddMapEntry(root, "uarch",
|
||||||
|
CreateString(
|
||||||
|
GetX86MicroarchitectureName(GetX86Microarchitecture(&info))));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
AddCacheInfo(root, &cache_info);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_ARM)
|
||||||
|
const ArmInfo info = GetArmInfo();
|
||||||
|
AddMapEntry(root, "arch", CreateString("ARM"));
|
||||||
|
AddMapEntry(root, "implementer", CreateInt(info.implementer));
|
||||||
|
AddMapEntry(root, "architecture", CreateInt(info.architecture));
|
||||||
|
AddMapEntry(root, "variant", CreateInt(info.variant));
|
||||||
|
AddMapEntry(root, "part", CreateInt(info.part));
|
||||||
|
AddMapEntry(root, "revision", CreateInt(info.revision));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_AARCH64)
|
||||||
|
const Aarch64Info info = GetAarch64Info();
|
||||||
|
AddMapEntry(root, "arch", CreateString("aarch64"));
|
||||||
|
AddMapEntry(root, "implementer", CreateInt(info.implementer));
|
||||||
|
AddMapEntry(root, "variant", CreateInt(info.variant));
|
||||||
|
AddMapEntry(root, "part", CreateInt(info.part));
|
||||||
|
AddMapEntry(root, "revision", CreateInt(info.revision));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_MIPS)
|
||||||
|
const MipsInfo info = GetMipsInfo();
|
||||||
|
AddMapEntry(root, "arch", CreateString("mips"));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
#elif defined(CPU_FEATURES_ARCH_PPC)
|
||||||
|
const PPCInfo info = GetPPCInfo();
|
||||||
|
const PPCPlatformStrings strings = GetPPCPlatformStrings();
|
||||||
|
AddMapEntry(root, "arch", CreateString("ppc"));
|
||||||
|
AddMapEntry(root, "platform", CreateString(strings.platform));
|
||||||
|
AddMapEntry(root, "model", CreateString(strings.model));
|
||||||
|
AddMapEntry(root, "machine", CreateString(strings.machine));
|
||||||
|
AddMapEntry(root, "cpu", CreateString(strings.cpu));
|
||||||
|
AddMapEntry(root, "instruction", CreateString(strings.type.platform));
|
||||||
|
AddMapEntry(root, "microarchitecture",
|
||||||
|
CreateString(strings.type.base_platform));
|
||||||
|
AddFlags(root, &info.features);
|
||||||
|
#endif
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char** argv) {
|
||||||
|
BA_Align();
|
||||||
|
const Node* const root = CreateTree();
|
||||||
|
bool outputJson = false;
|
||||||
|
int i = 1;
|
||||||
|
for (; i < argc; ++i) {
|
||||||
|
const char* arg = argv[i];
|
||||||
|
if (strcmp(arg, "-j") == 0 || strcmp(arg, "--json") == 0) {
|
||||||
|
outputJson = true;
|
||||||
|
} else {
|
||||||
|
showUsage(argv[0]);
|
||||||
|
if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0)
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (outputJson)
|
||||||
|
printJson(root);
|
||||||
|
else
|
||||||
|
printTextRoot(root);
|
||||||
|
putchar('\n');
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,85 @@
|
||||||
|
#
|
||||||
|
# libraries for tests
|
||||||
|
#
|
||||||
|
|
||||||
|
include_directories(../include)
|
||||||
|
add_definitions(-DCPU_FEATURES_TEST)
|
||||||
|
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(string_view ../src/string_view.c)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(filesystem_for_testing filesystem_for_testing.cc)
|
||||||
|
target_compile_definitions(filesystem_for_testing PUBLIC CPU_FEATURES_MOCK_FILESYSTEM)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(hwcaps_for_testing hwcaps_for_testing.cc)
|
||||||
|
target_link_libraries(hwcaps_for_testing filesystem_for_testing)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(stack_line_reader ../src/stack_line_reader.c)
|
||||||
|
target_compile_definitions(stack_line_reader PUBLIC STACK_LINE_READER_BUFFER_SIZE=1024)
|
||||||
|
target_link_libraries(stack_line_reader string_view)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(stack_line_reader_for_test ../src/stack_line_reader.c)
|
||||||
|
target_compile_definitions(stack_line_reader_for_test PUBLIC STACK_LINE_READER_BUFFER_SIZE=16)
|
||||||
|
target_link_libraries(stack_line_reader_for_test string_view filesystem_for_testing)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
add_library(all_libraries ../src/hwcaps.c ../src/stack_line_reader.c)
|
||||||
|
target_link_libraries(all_libraries hwcaps_for_testing stack_line_reader string_view)
|
||||||
|
|
||||||
|
#
|
||||||
|
# tests
|
||||||
|
#
|
||||||
|
link_libraries(gtest gmock_main)
|
||||||
|
|
||||||
|
## bit_utils_test
|
||||||
|
add_executable(bit_utils_test bit_utils_test.cc)
|
||||||
|
target_link_libraries(bit_utils_test)
|
||||||
|
add_test(NAME bit_utils_test COMMAND bit_utils_test)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## string_view_test
|
||||||
|
add_executable(string_view_test string_view_test.cc ../src/string_view.c)
|
||||||
|
target_link_libraries(string_view_test string_view)
|
||||||
|
add_test(NAME string_view_test COMMAND string_view_test)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## stack_line_reader_test
|
||||||
|
add_executable(stack_line_reader_test stack_line_reader_test.cc)
|
||||||
|
target_link_libraries(stack_line_reader_test stack_line_reader_for_test)
|
||||||
|
add_test(NAME stack_line_reader_test COMMAND stack_line_reader_test)
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_x86_test
|
||||||
|
if(PROCESSOR_IS_X86)
|
||||||
|
add_executable(cpuinfo_x86_test cpuinfo_x86_test.cc ../src/cpuinfo_x86.c)
|
||||||
|
target_compile_definitions(cpuinfo_x86_test PUBLIC CPU_FEATURES_MOCK_CPUID_X86)
|
||||||
|
if(APPLE)
|
||||||
|
target_compile_definitions(cpuinfo_x86_test PRIVATE HAVE_SYSCTLBYNAME)
|
||||||
|
endif()
|
||||||
|
target_link_libraries(cpuinfo_x86_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_x86_test COMMAND cpuinfo_x86_test)
|
||||||
|
endif()
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_arm_test
|
||||||
|
if(PROCESSOR_IS_ARM)
|
||||||
|
add_executable(cpuinfo_arm_test cpuinfo_arm_test.cc ../src/cpuinfo_arm.c)
|
||||||
|
target_link_libraries(cpuinfo_arm_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_arm_test COMMAND cpuinfo_arm_test)
|
||||||
|
endif()
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_aarch64_test
|
||||||
|
if(PROCESSOR_IS_AARCH64)
|
||||||
|
add_executable(cpuinfo_aarch64_test cpuinfo_aarch64_test.cc ../src/cpuinfo_aarch64.c)
|
||||||
|
target_link_libraries(cpuinfo_aarch64_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_aarch64_test COMMAND cpuinfo_aarch64_test)
|
||||||
|
endif()
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_mips_test
|
||||||
|
if(PROCESSOR_IS_MIPS)
|
||||||
|
add_executable(cpuinfo_mips_test cpuinfo_mips_test.cc ../src/cpuinfo_mips.c)
|
||||||
|
target_link_libraries(cpuinfo_mips_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_mips_test COMMAND cpuinfo_mips_test)
|
||||||
|
endif()
|
||||||
|
##------------------------------------------------------------------------------
|
||||||
|
## cpuinfo_ppc_test
|
||||||
|
if(PROCESSOR_IS_POWER)
|
||||||
|
add_executable(cpuinfo_ppc_test cpuinfo_ppc_test.cc ../src/cpuinfo_ppc.c)
|
||||||
|
target_link_libraries(cpuinfo_ppc_test all_libraries)
|
||||||
|
add_test(NAME cpuinfo_ppc_test COMMAND cpuinfo_ppc_test)
|
||||||
|
endif()
|
||||||
|
|
@ -0,0 +1,53 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/bit_utils.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(UtilsTest, IsBitSet) {
|
||||||
|
for (size_t bit_set = 0; bit_set < 32; ++bit_set) {
|
||||||
|
const uint32_t value = 1UL << bit_set;
|
||||||
|
for (uint32_t i = 0; i < 32; ++i) {
|
||||||
|
EXPECT_EQ(IsBitSet(value, i), i == bit_set);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing 0, all bits should be 0.
|
||||||
|
for (uint32_t i = 0; i < 32; ++i) {
|
||||||
|
EXPECT_FALSE(IsBitSet(0, i));
|
||||||
|
}
|
||||||
|
|
||||||
|
// testing ~0, all bits should be 1.
|
||||||
|
for (uint32_t i = 0; i < 32; ++i) {
|
||||||
|
EXPECT_TRUE(IsBitSet(-1, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(UtilsTest, ExtractBitRange) {
|
||||||
|
// Extracting all bits gives the same number.
|
||||||
|
EXPECT_EQ(ExtractBitRange(123, 31, 0), 123);
|
||||||
|
// Extracting 1 bit gives parity.
|
||||||
|
EXPECT_EQ(ExtractBitRange(123, 0, 0), 1);
|
||||||
|
EXPECT_EQ(ExtractBitRange(122, 0, 0), 0);
|
||||||
|
|
||||||
|
EXPECT_EQ(ExtractBitRange(0xF0, 7, 4), 0xF);
|
||||||
|
EXPECT_EQ(ExtractBitRange(0x42 << 2, 10, 2), 0x42);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,171 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_aarch64.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||||
|
|
||||||
|
TEST(CpuinfoAarch64Test, FromHardwareCap) {
|
||||||
|
SetHardwareCapabilities(AARCH64_HWCAP_FP | AARCH64_HWCAP_AES, 0);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetAarch64Info();
|
||||||
|
EXPECT_TRUE(info.features.fp);
|
||||||
|
EXPECT_FALSE(info.features.asimd);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_TRUE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
EXPECT_FALSE(info.features.atomics);
|
||||||
|
EXPECT_FALSE(info.features.fphp);
|
||||||
|
EXPECT_FALSE(info.features.asimdhp);
|
||||||
|
EXPECT_FALSE(info.features.cpuid);
|
||||||
|
EXPECT_FALSE(info.features.asimdrdm);
|
||||||
|
EXPECT_FALSE(info.features.jscvt);
|
||||||
|
EXPECT_FALSE(info.features.fcma);
|
||||||
|
EXPECT_FALSE(info.features.lrcpc);
|
||||||
|
EXPECT_FALSE(info.features.dcpop);
|
||||||
|
EXPECT_FALSE(info.features.sha3);
|
||||||
|
EXPECT_FALSE(info.features.sm3);
|
||||||
|
EXPECT_FALSE(info.features.sm4);
|
||||||
|
EXPECT_FALSE(info.features.asimddp);
|
||||||
|
EXPECT_FALSE(info.features.sha512);
|
||||||
|
EXPECT_FALSE(info.features.sve);
|
||||||
|
EXPECT_FALSE(info.features.asimdfhm);
|
||||||
|
EXPECT_FALSE(info.features.dit);
|
||||||
|
EXPECT_FALSE(info.features.uscat);
|
||||||
|
EXPECT_FALSE(info.features.ilrcpc);
|
||||||
|
EXPECT_FALSE(info.features.flagm);
|
||||||
|
EXPECT_FALSE(info.features.ssbs);
|
||||||
|
EXPECT_FALSE(info.features.sb);
|
||||||
|
EXPECT_FALSE(info.features.paca);
|
||||||
|
EXPECT_FALSE(info.features.pacg);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoAarch64Test, FromHardwareCap2) {
|
||||||
|
SetHardwareCapabilities(AARCH64_HWCAP_FP,
|
||||||
|
AARCH64_HWCAP2_SVE2 | AARCH64_HWCAP2_BTI);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetAarch64Info();
|
||||||
|
EXPECT_TRUE(info.features.fp);
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.sve2);
|
||||||
|
EXPECT_TRUE(info.features.bti);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.dcpodp);
|
||||||
|
EXPECT_FALSE(info.features.sveaes);
|
||||||
|
EXPECT_FALSE(info.features.svepmull);
|
||||||
|
EXPECT_FALSE(info.features.svebitperm);
|
||||||
|
EXPECT_FALSE(info.features.svesha3);
|
||||||
|
EXPECT_FALSE(info.features.svesm4);
|
||||||
|
EXPECT_FALSE(info.features.flagm2);
|
||||||
|
EXPECT_FALSE(info.features.frint);
|
||||||
|
EXPECT_FALSE(info.features.svei8mm);
|
||||||
|
EXPECT_FALSE(info.features.svef32mm);
|
||||||
|
EXPECT_FALSE(info.features.svef64mm);
|
||||||
|
EXPECT_FALSE(info.features.svebf16);
|
||||||
|
EXPECT_FALSE(info.features.i8mm);
|
||||||
|
EXPECT_FALSE(info.features.bf16);
|
||||||
|
EXPECT_FALSE(info.features.dgh);
|
||||||
|
EXPECT_FALSE(info.features.rng);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoAarch64Test, ARMCortexA53) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(Processor : AArch64 Processor rev 3 (aarch64)
|
||||||
|
processor : 0
|
||||||
|
processor : 1
|
||||||
|
processor : 2
|
||||||
|
processor : 3
|
||||||
|
processor : 4
|
||||||
|
processor : 5
|
||||||
|
processor : 6
|
||||||
|
processor : 7
|
||||||
|
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: AArch64
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0xd03
|
||||||
|
CPU revision : 3)");
|
||||||
|
const auto info = GetAarch64Info();
|
||||||
|
EXPECT_EQ(info.implementer, 0x41);
|
||||||
|
EXPECT_EQ(info.variant, 0x0);
|
||||||
|
EXPECT_EQ(info.part, 0xd03);
|
||||||
|
EXPECT_EQ(info.revision, 3);
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.fp);
|
||||||
|
EXPECT_TRUE(info.features.asimd);
|
||||||
|
EXPECT_TRUE(info.features.evtstrm);
|
||||||
|
EXPECT_TRUE(info.features.aes);
|
||||||
|
EXPECT_TRUE(info.features.pmull);
|
||||||
|
EXPECT_TRUE(info.features.sha1);
|
||||||
|
EXPECT_TRUE(info.features.sha2);
|
||||||
|
EXPECT_TRUE(info.features.crc32);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.atomics);
|
||||||
|
EXPECT_FALSE(info.features.fphp);
|
||||||
|
EXPECT_FALSE(info.features.asimdhp);
|
||||||
|
EXPECT_FALSE(info.features.cpuid);
|
||||||
|
EXPECT_FALSE(info.features.asimdrdm);
|
||||||
|
EXPECT_FALSE(info.features.jscvt);
|
||||||
|
EXPECT_FALSE(info.features.fcma);
|
||||||
|
EXPECT_FALSE(info.features.lrcpc);
|
||||||
|
EXPECT_FALSE(info.features.dcpop);
|
||||||
|
EXPECT_FALSE(info.features.sha3);
|
||||||
|
EXPECT_FALSE(info.features.sm3);
|
||||||
|
EXPECT_FALSE(info.features.sm4);
|
||||||
|
EXPECT_FALSE(info.features.asimddp);
|
||||||
|
EXPECT_FALSE(info.features.sha512);
|
||||||
|
EXPECT_FALSE(info.features.sve);
|
||||||
|
EXPECT_FALSE(info.features.asimdfhm);
|
||||||
|
EXPECT_FALSE(info.features.dit);
|
||||||
|
EXPECT_FALSE(info.features.uscat);
|
||||||
|
EXPECT_FALSE(info.features.ilrcpc);
|
||||||
|
EXPECT_FALSE(info.features.flagm);
|
||||||
|
EXPECT_FALSE(info.features.ssbs);
|
||||||
|
EXPECT_FALSE(info.features.sb);
|
||||||
|
EXPECT_FALSE(info.features.paca);
|
||||||
|
EXPECT_FALSE(info.features.pacg);
|
||||||
|
EXPECT_FALSE(info.features.dcpodp);
|
||||||
|
EXPECT_FALSE(info.features.sve2);
|
||||||
|
EXPECT_FALSE(info.features.sveaes);
|
||||||
|
EXPECT_FALSE(info.features.svepmull);
|
||||||
|
EXPECT_FALSE(info.features.svebitperm);
|
||||||
|
EXPECT_FALSE(info.features.svesha3);
|
||||||
|
EXPECT_FALSE(info.features.svesm4);
|
||||||
|
EXPECT_FALSE(info.features.flagm2);
|
||||||
|
EXPECT_FALSE(info.features.frint);
|
||||||
|
EXPECT_FALSE(info.features.svei8mm);
|
||||||
|
EXPECT_FALSE(info.features.svef32mm);
|
||||||
|
EXPECT_FALSE(info.features.svef64mm);
|
||||||
|
EXPECT_FALSE(info.features.svebf16);
|
||||||
|
EXPECT_FALSE(info.features.i8mm);
|
||||||
|
EXPECT_FALSE(info.features.bf16);
|
||||||
|
EXPECT_FALSE(info.features.dgh);
|
||||||
|
EXPECT_FALSE(info.features.rng);
|
||||||
|
EXPECT_FALSE(info.features.bti);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,354 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_arm.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||||
|
|
||||||
|
TEST(CpuinfoArmTest, FromHardwareCap) {
|
||||||
|
SetHardwareCapabilities(ARM_HWCAP_NEON, ARM_HWCAP2_AES | ARM_HWCAP2_CRC32);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.vfp); // triggered by vfpv3
|
||||||
|
EXPECT_TRUE(info.features.vfpv3); // triggered by neon
|
||||||
|
EXPECT_TRUE(info.features.neon);
|
||||||
|
EXPECT_TRUE(info.features.aes);
|
||||||
|
EXPECT_TRUE(info.features.crc32);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.vfpv4);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_FALSE(info.features.idiva);
|
||||||
|
EXPECT_FALSE(info.features.idivt);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
|
||||||
|
// check some random features with EnumValue():
|
||||||
|
EXPECT_TRUE(GetArmFeaturesEnumValue(&info.features, ARM_VFP));
|
||||||
|
EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, ARM_VFPV4));
|
||||||
|
// out of bound EnumValue() check
|
||||||
|
EXPECT_FALSE(GetArmFeaturesEnumValue(&info.features, (ArmFeaturesEnum)~0x0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoArmTest, ODroidFromCpuInfo) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
|
||||||
|
model name : ARMv7 Processor rev 3 (v71)
|
||||||
|
BogoMIPS : 120.00
|
||||||
|
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x2
|
||||||
|
CPU part : 0xc0f
|
||||||
|
CPU revision : 3)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_EQ(info.implementer, 0x41);
|
||||||
|
EXPECT_EQ(info.variant, 0x2);
|
||||||
|
EXPECT_EQ(info.part, 0xc0f);
|
||||||
|
EXPECT_EQ(info.revision, 3);
|
||||||
|
EXPECT_EQ(info.architecture, 7);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.swp);
|
||||||
|
EXPECT_TRUE(info.features.half);
|
||||||
|
EXPECT_TRUE(info.features.thumb);
|
||||||
|
EXPECT_FALSE(info.features._26bit);
|
||||||
|
EXPECT_TRUE(info.features.fastmult);
|
||||||
|
EXPECT_FALSE(info.features.fpa);
|
||||||
|
EXPECT_TRUE(info.features.vfp);
|
||||||
|
EXPECT_TRUE(info.features.edsp);
|
||||||
|
EXPECT_FALSE(info.features.java);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_TRUE(info.features.neon);
|
||||||
|
EXPECT_TRUE(info.features.vfpv3);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_TRUE(info.features.tls);
|
||||||
|
EXPECT_TRUE(info.features.vfpv4);
|
||||||
|
EXPECT_TRUE(info.features.idiva);
|
||||||
|
EXPECT_TRUE(info.features.idivt);
|
||||||
|
EXPECT_TRUE(info.features.vfpd32);
|
||||||
|
EXPECT_TRUE(info.features.lpae);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_FALSE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Linux test-case
|
||||||
|
TEST(CpuinfoArmTest, RaspberryPiZeroFromCpuInfo) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
|
||||||
|
model name : ARMv6-compatible processor rev 7 (v6l)
|
||||||
|
BogoMIPS : 697.95
|
||||||
|
Features : half thumb fastmult vfp edsp java tls
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0xb76
|
||||||
|
CPU revision : 7
|
||||||
|
|
||||||
|
Hardware : BCM2835
|
||||||
|
Revision : 9000c1
|
||||||
|
Serial : 000000006cd946f3)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_EQ(info.implementer, 0x41);
|
||||||
|
EXPECT_EQ(info.variant, 0x0);
|
||||||
|
EXPECT_EQ(info.part, 0xb76);
|
||||||
|
EXPECT_EQ(info.revision, 7);
|
||||||
|
EXPECT_EQ(info.architecture, 6);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.swp);
|
||||||
|
EXPECT_TRUE(info.features.half);
|
||||||
|
EXPECT_TRUE(info.features.thumb);
|
||||||
|
EXPECT_FALSE(info.features._26bit);
|
||||||
|
EXPECT_TRUE(info.features.fastmult);
|
||||||
|
EXPECT_FALSE(info.features.fpa);
|
||||||
|
EXPECT_TRUE(info.features.vfp);
|
||||||
|
EXPECT_TRUE(info.features.edsp);
|
||||||
|
EXPECT_TRUE(info.features.java);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_FALSE(info.features.neon);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_TRUE(info.features.tls);
|
||||||
|
EXPECT_FALSE(info.features.vfpv4);
|
||||||
|
EXPECT_FALSE(info.features.idiva);
|
||||||
|
EXPECT_FALSE(info.features.idivt);
|
||||||
|
EXPECT_FALSE(info.features.vfpd32);
|
||||||
|
EXPECT_FALSE(info.features.lpae);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_FALSE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoArmTest, MarvellArmadaFromCpuInfo) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(processor : 0
|
||||||
|
model name : ARMv7 Processor rev 1 (v7l)
|
||||||
|
BogoMIPS : 50.00
|
||||||
|
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x4
|
||||||
|
CPU part : 0xc09
|
||||||
|
CPU revision : 1
|
||||||
|
|
||||||
|
processor : 1
|
||||||
|
model name : ARMv7 Processor rev 1 (v7l)
|
||||||
|
BogoMIPS : 50.00
|
||||||
|
Features : half thumb fastmult vfp edsp neon vfpv3 tls vfpd32
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x4
|
||||||
|
CPU part : 0xc09
|
||||||
|
CPU revision : 1
|
||||||
|
|
||||||
|
Hardware : Marvell Armada 380/385 (Device Tree)
|
||||||
|
Revision : 0000
|
||||||
|
Serial : 0000000000000000)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_EQ(info.implementer, 0x41);
|
||||||
|
EXPECT_EQ(info.variant, 0x4);
|
||||||
|
EXPECT_EQ(info.part, 0xc09);
|
||||||
|
EXPECT_EQ(info.revision, 1);
|
||||||
|
EXPECT_EQ(info.architecture, 7);
|
||||||
|
|
||||||
|
EXPECT_FALSE(info.features.swp);
|
||||||
|
EXPECT_TRUE(info.features.half);
|
||||||
|
EXPECT_TRUE(info.features.thumb);
|
||||||
|
EXPECT_FALSE(info.features._26bit);
|
||||||
|
EXPECT_TRUE(info.features.fastmult);
|
||||||
|
EXPECT_FALSE(info.features.fpa);
|
||||||
|
EXPECT_TRUE(info.features.vfp);
|
||||||
|
EXPECT_TRUE(info.features.edsp);
|
||||||
|
EXPECT_FALSE(info.features.java);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_TRUE(info.features.neon);
|
||||||
|
EXPECT_TRUE(info.features.vfpv3);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_TRUE(info.features.tls);
|
||||||
|
EXPECT_FALSE(info.features.vfpv4);
|
||||||
|
EXPECT_FALSE(info.features.idiva);
|
||||||
|
EXPECT_FALSE(info.features.idivt);
|
||||||
|
EXPECT_TRUE(info.features.vfpd32);
|
||||||
|
EXPECT_FALSE(info.features.lpae);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_FALSE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android test-case
|
||||||
|
// http://code.google.com/p/android/issues/detail?id=10812
|
||||||
|
TEST(CpuinfoArmTest, InvalidArmv7) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(Processor : ARMv6-compatible processor rev 6 (v6l)
|
||||||
|
BogoMIPS : 199.47
|
||||||
|
Features : swp half thumb fastmult vfp edsp java
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0xb76
|
||||||
|
CPU revision : 6
|
||||||
|
|
||||||
|
Hardware : SPICA
|
||||||
|
Revision : 0020
|
||||||
|
Serial : 33323613546d00ec )");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_EQ(info.architecture, 6);
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.swp);
|
||||||
|
EXPECT_TRUE(info.features.half);
|
||||||
|
EXPECT_TRUE(info.features.thumb);
|
||||||
|
EXPECT_FALSE(info.features._26bit);
|
||||||
|
EXPECT_TRUE(info.features.fastmult);
|
||||||
|
EXPECT_FALSE(info.features.fpa);
|
||||||
|
EXPECT_TRUE(info.features.vfp);
|
||||||
|
EXPECT_TRUE(info.features.edsp);
|
||||||
|
EXPECT_TRUE(info.features.java);
|
||||||
|
EXPECT_FALSE(info.features.iwmmxt);
|
||||||
|
EXPECT_FALSE(info.features.crunch);
|
||||||
|
EXPECT_FALSE(info.features.thumbee);
|
||||||
|
EXPECT_FALSE(info.features.neon);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3);
|
||||||
|
EXPECT_FALSE(info.features.vfpv3d16);
|
||||||
|
EXPECT_FALSE(info.features.tls);
|
||||||
|
EXPECT_FALSE(info.features.vfpv4);
|
||||||
|
EXPECT_FALSE(info.features.idiva);
|
||||||
|
EXPECT_FALSE(info.features.idivt);
|
||||||
|
EXPECT_FALSE(info.features.vfpd32);
|
||||||
|
EXPECT_FALSE(info.features.lpae);
|
||||||
|
EXPECT_FALSE(info.features.evtstrm);
|
||||||
|
EXPECT_FALSE(info.features.aes);
|
||||||
|
EXPECT_FALSE(info.features.pmull);
|
||||||
|
EXPECT_FALSE(info.features.sha1);
|
||||||
|
EXPECT_FALSE(info.features.sha2);
|
||||||
|
EXPECT_FALSE(info.features.crc32);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android test-case
|
||||||
|
// https://crbug.com/341598.
|
||||||
|
TEST(CpuinfoArmTest, InvalidNeon) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(Processor: ARMv7 Processory rev 0 (v71)
|
||||||
|
processor: 0
|
||||||
|
BogoMIPS: 13.50
|
||||||
|
|
||||||
|
Processor: 1
|
||||||
|
BogoMIPS: 13.50
|
||||||
|
|
||||||
|
Features: swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
|
||||||
|
CPU implementer : 0x51
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant: 0x1
|
||||||
|
CPU part: 0x04d
|
||||||
|
CPU revision: 0
|
||||||
|
|
||||||
|
Hardware: SAMSUNG M2
|
||||||
|
Revision: 0010
|
||||||
|
Serial: 00001e030000354e)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.swp);
|
||||||
|
EXPECT_FALSE(info.features.neon);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
|
||||||
|
// support.
|
||||||
|
TEST(CpuinfoArmTest, Nexus4_0x510006f2) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(CPU implementer : 0x51
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0x6f
|
||||||
|
CPU revision : 2)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.idiva);
|
||||||
|
EXPECT_TRUE(info.features.idivt);
|
||||||
|
|
||||||
|
EXPECT_EQ(GetArmCpuId(&info), 0x510006f2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The Nexus 4 (Qualcomm Krait) kernel configuration forgets to report IDIV
|
||||||
|
// support.
|
||||||
|
TEST(CpuinfoArmTest, Nexus4_0x510006f3) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(CPU implementer : 0x51
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0x6f
|
||||||
|
CPU revision : 3)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.idiva);
|
||||||
|
EXPECT_TRUE(info.features.idivt);
|
||||||
|
|
||||||
|
EXPECT_EQ(GetArmCpuId(&info), 0x510006f3);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The emulator-specific Android 4.2 kernel fails to report support for the
|
||||||
|
// 32-bit ARM IDIV instruction. Technically, this is a feature of the virtual
|
||||||
|
// CPU implemented by the emulator.
|
||||||
|
TEST(CpuinfoArmTest, EmulatorSpecificIdiv) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(Processor : ARMv7 Processor rev 0 (v7l)
|
||||||
|
BogoMIPS : 629.14
|
||||||
|
Features : swp half thumb fastmult vfp edsp neon vfpv3
|
||||||
|
CPU implementer : 0x41
|
||||||
|
CPU architecture: 7
|
||||||
|
CPU variant : 0x0
|
||||||
|
CPU part : 0xc08
|
||||||
|
CPU revision : 0
|
||||||
|
|
||||||
|
Hardware : Goldfish
|
||||||
|
Revision : 0000
|
||||||
|
Serial : 0000000000000000)");
|
||||||
|
const auto info = GetArmInfo();
|
||||||
|
EXPECT_TRUE(info.features.idiva);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,126 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_mips.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, FromHardwareCapBoth) {
|
||||||
|
SetHardwareCapabilities(MIPS_HWCAP_MSA | MIPS_HWCAP_R6, 0);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_TRUE(info.features.msa);
|
||||||
|
EXPECT_FALSE(info.features.eva);
|
||||||
|
EXPECT_TRUE(info.features.r6);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, FromHardwareCapOnlyOne) {
|
||||||
|
SetHardwareCapabilities(MIPS_HWCAP_MSA, 0);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_TRUE(info.features.msa);
|
||||||
|
EXPECT_FALSE(info.features.eva);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, Ci40) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(system type : IMG Pistachio SoC (B0)
|
||||||
|
machine : IMG Marduk – Ci40 with cc2520
|
||||||
|
processor : 0
|
||||||
|
cpu model : MIPS interAptiv (multi) V2.0 FPU V0.0
|
||||||
|
BogoMIPS : 363.72
|
||||||
|
wait instruction : yes
|
||||||
|
microsecond timers : yes
|
||||||
|
tlb_entries : 64
|
||||||
|
extra interrupt vector : yes
|
||||||
|
hardware watchpoint : yes, count: 4, address/irw mask: [0x0ffc, 0x0ffc, 0x0ffb, 0x0ffb]
|
||||||
|
isa : mips1 mips2 mips32r1 mips32r2
|
||||||
|
ASEs implemented : mips16 dsp mt eva
|
||||||
|
shadow register sets : 1
|
||||||
|
kscratch registers : 0
|
||||||
|
package : 0
|
||||||
|
core : 0
|
||||||
|
VCED exceptions : not available
|
||||||
|
VCEI exceptions : not available
|
||||||
|
VPE : 0
|
||||||
|
)");
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_FALSE(info.features.msa);
|
||||||
|
EXPECT_TRUE(info.features.eva);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, AR7161) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(system type : Atheros AR7161 rev 2
|
||||||
|
machine : NETGEAR WNDR3700/WNDR3800/WNDRMAC
|
||||||
|
processor : 0
|
||||||
|
cpu model : MIPS 24Kc V7.4
|
||||||
|
BogoMIPS : 452.19
|
||||||
|
wait instruction : yes
|
||||||
|
microsecond timers : yes
|
||||||
|
tlb_entries : 16
|
||||||
|
extra interrupt vector : yes
|
||||||
|
hardware watchpoint : yes, count: 4, address/irw mask: [0x0000, 0x0f98, 0x0f78, 0x0df8]
|
||||||
|
ASEs implemented : mips16
|
||||||
|
shadow register sets : 1
|
||||||
|
kscratch registers : 0
|
||||||
|
core : 0
|
||||||
|
VCED exceptions : not available
|
||||||
|
VCEI exceptions : not available
|
||||||
|
)");
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_FALSE(info.features.msa);
|
||||||
|
EXPECT_FALSE(info.features.eva);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpuinfoMipsTest, Goldfish) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(system type : MIPS-Goldfish
|
||||||
|
Hardware : goldfish
|
||||||
|
Revison : 1
|
||||||
|
processor : 0
|
||||||
|
cpu model : MIPS 24Kc V0.0 FPU V0.0
|
||||||
|
BogoMIPS : 1042.02
|
||||||
|
wait instruction : yes
|
||||||
|
microsecond timers : yes
|
||||||
|
tlb_entries : 16
|
||||||
|
extra interrupt vector : yes
|
||||||
|
hardware watchpoint : yes, count: 1, address/irw mask: [0x0ff8]
|
||||||
|
ASEs implemented :
|
||||||
|
shadow register sets : 1
|
||||||
|
core : 0
|
||||||
|
VCED exceptions : not available
|
||||||
|
VCEI exceptions : not available
|
||||||
|
)");
|
||||||
|
const auto info = GetMipsInfo();
|
||||||
|
EXPECT_FALSE(info.features.msa);
|
||||||
|
EXPECT_FALSE(info.features.eva);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,119 @@
|
||||||
|
// Copyright 2018 IBM.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_ppc.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
void DisableHardwareCapabilities() { SetHardwareCapabilities(0, 0); }
|
||||||
|
|
||||||
|
TEST(CpustringsPPCTest, FromHardwareCap) {
|
||||||
|
SetHardwareCapabilities(PPC_FEATURE_HAS_FPU | PPC_FEATURE_HAS_VSX,
|
||||||
|
PPC_FEATURE2_ARCH_3_00);
|
||||||
|
GetEmptyFilesystem(); // disabling /proc/cpuinfo
|
||||||
|
const auto info = GetPPCInfo();
|
||||||
|
EXPECT_TRUE(info.features.fpu);
|
||||||
|
EXPECT_FALSE(info.features.mmu);
|
||||||
|
EXPECT_TRUE(info.features.vsx);
|
||||||
|
EXPECT_TRUE(info.features.arch300);
|
||||||
|
EXPECT_FALSE(info.features.power4);
|
||||||
|
EXPECT_FALSE(info.features.altivec);
|
||||||
|
EXPECT_FALSE(info.features.vcrypto);
|
||||||
|
EXPECT_FALSE(info.features.htm);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpustringsPPCTest, Blade) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(processor : 14
|
||||||
|
cpu : POWER7 (architected), altivec supported
|
||||||
|
clock : 3000.000000MHz
|
||||||
|
revision : 2.1 (pvr 003f 0201)
|
||||||
|
|
||||||
|
processor : 15
|
||||||
|
cpu : POWER7 (architected), altivec supported
|
||||||
|
clock : 3000.000000MHz
|
||||||
|
revision : 2.1 (pvr 003f 0201)
|
||||||
|
|
||||||
|
timebase : 512000000
|
||||||
|
platform : pSeries
|
||||||
|
model : IBM,8406-70Y
|
||||||
|
machine : CHRP IBM,8406-70Y)");
|
||||||
|
SetPlatformTypes("power7", "power8");
|
||||||
|
const auto strings = GetPPCPlatformStrings();
|
||||||
|
ASSERT_STREQ(strings.platform, "pSeries");
|
||||||
|
ASSERT_STREQ(strings.model, "IBM,8406-70Y");
|
||||||
|
ASSERT_STREQ(strings.machine, "CHRP IBM,8406-70Y");
|
||||||
|
ASSERT_STREQ(strings.cpu, "POWER7 (architected), altivec supported");
|
||||||
|
ASSERT_STREQ(strings.type.platform, "power7");
|
||||||
|
ASSERT_STREQ(strings.type.base_platform, "power8");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpustringsPPCTest, Firestone) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(processor : 126
|
||||||
|
cpu : POWER8 (raw), altivec supported
|
||||||
|
clock : 2061.000000MHz
|
||||||
|
revision : 2.0 (pvr 004d 0200)
|
||||||
|
|
||||||
|
processor : 127
|
||||||
|
cpu : POWER8 (raw), altivec supported
|
||||||
|
clock : 2061.000000MHz
|
||||||
|
revision : 2.0 (pvr 004d 0200)
|
||||||
|
|
||||||
|
timebase : 512000000
|
||||||
|
platform : PowerNV
|
||||||
|
model : 8335-GTA
|
||||||
|
machine : PowerNV 8335-GTA
|
||||||
|
firmware : OPAL v3)");
|
||||||
|
const auto strings = GetPPCPlatformStrings();
|
||||||
|
ASSERT_STREQ(strings.platform, "PowerNV");
|
||||||
|
ASSERT_STREQ(strings.model, "8335-GTA");
|
||||||
|
ASSERT_STREQ(strings.machine, "PowerNV 8335-GTA");
|
||||||
|
ASSERT_STREQ(strings.cpu, "POWER8 (raw), altivec supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(CpustringsPPCTest, w8) {
|
||||||
|
DisableHardwareCapabilities();
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo",
|
||||||
|
R"(processor : 143
|
||||||
|
cpu : POWER9, altivec supported
|
||||||
|
clock : 2300.000000MHz
|
||||||
|
revision : 2.2 (pvr 004e 1202)
|
||||||
|
|
||||||
|
timebase : 512000000
|
||||||
|
platform : PowerNV
|
||||||
|
model : 0000000000000000
|
||||||
|
machine : PowerNV 0000000000000000
|
||||||
|
firmware : OPAL
|
||||||
|
MMU : Radix)");
|
||||||
|
const auto strings = GetPPCPlatformStrings();
|
||||||
|
ASSERT_STREQ(strings.platform, "PowerNV");
|
||||||
|
ASSERT_STREQ(strings.model, "0000000000000000");
|
||||||
|
ASSERT_STREQ(strings.machine, "PowerNV 0000000000000000");
|
||||||
|
ASSERT_STREQ(strings.cpu, "POWER9, altivec supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,533 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "cpuinfo_x86.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <map>
|
||||||
|
#include <set>
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
#include <windows.h> // IsProcessorFeaturePresent
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
#include "internal/cpuid_x86.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
class FakeCpu {
|
||||||
|
public:
|
||||||
|
Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) const {
|
||||||
|
const auto itr = cpuid_leaves_.find(std::make_pair(leaf_id, ecx));
|
||||||
|
if (itr != cpuid_leaves_.end()) {
|
||||||
|
return itr->second;
|
||||||
|
}
|
||||||
|
return {0, 0, 0, 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t GetXCR0Eax() const { return xcr0_eax_; }
|
||||||
|
|
||||||
|
void SetLeaves(std::map<std::pair<uint32_t, int>, Leaf> configuration) {
|
||||||
|
cpuid_leaves_ = std::move(configuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetOsBackupsExtendedRegisters(bool os_backups_extended_registers) {
|
||||||
|
xcr0_eax_ = os_backups_extended_registers ? -1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
bool GetDarwinSysCtlByName(std::string name) const {
|
||||||
|
return darwin_sysctlbyname_.count(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetDarwinSysCtlByName(std::string name) {
|
||||||
|
darwin_sysctlbyname_.insert(name);
|
||||||
|
}
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
|
||||||
|
return windows_isprocessorfeaturepresent_.count(ProcessorFeature);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
|
||||||
|
windows_isprocessorfeaturepresent_.insert(ProcessorFeature);
|
||||||
|
}
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::map<std::pair<uint32_t, int>, Leaf> cpuid_leaves_;
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
std::set<std::string> darwin_sysctlbyname_;
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
std::set<DWORD> windows_isprocessorfeaturepresent_;
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
uint32_t xcr0_eax_;
|
||||||
|
};
|
||||||
|
|
||||||
|
FakeCpu* g_fake_cpu = nullptr;
|
||||||
|
|
||||||
|
extern "C" Leaf GetCpuidLeaf(uint32_t leaf_id, int ecx) {
|
||||||
|
return g_fake_cpu->GetCpuidLeaf(leaf_id, ecx);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" uint32_t GetXCR0Eax(void) { return g_fake_cpu->GetXCR0Eax(); }
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
extern "C" bool GetDarwinSysCtlByName(const char* name) {
|
||||||
|
return g_fake_cpu->GetDarwinSysCtlByName(name);
|
||||||
|
}
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
extern "C" bool GetWindowsIsProcessorFeaturePresent(DWORD ProcessorFeature) {
|
||||||
|
return g_fake_cpu->GetWindowsIsProcessorFeaturePresent(ProcessorFeature);
|
||||||
|
}
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
class CpuidX86Test : public ::testing::Test {
|
||||||
|
protected:
|
||||||
|
void SetUp() override { g_fake_cpu = new FakeCpu(); }
|
||||||
|
void TearDown() override { delete g_fake_cpu; }
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, SandyBridge) {
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x02A);
|
||||||
|
EXPECT_EQ(info.stepping, 0x06);
|
||||||
|
// Leaf 7 is zeroed out so none of the Leaf 7 flags are set.
|
||||||
|
const auto features = info.features;
|
||||||
|
EXPECT_FALSE(features.erms);
|
||||||
|
EXPECT_FALSE(features.avx2);
|
||||||
|
EXPECT_FALSE(features.avx512f);
|
||||||
|
EXPECT_FALSE(features.avx512cd);
|
||||||
|
EXPECT_FALSE(features.avx512er);
|
||||||
|
EXPECT_FALSE(features.avx512pf);
|
||||||
|
EXPECT_FALSE(features.avx512bw);
|
||||||
|
EXPECT_FALSE(features.avx512dq);
|
||||||
|
EXPECT_FALSE(features.avx512vl);
|
||||||
|
EXPECT_FALSE(features.avx512ifma);
|
||||||
|
EXPECT_FALSE(features.avx512vbmi);
|
||||||
|
EXPECT_FALSE(features.avx512vbmi2);
|
||||||
|
EXPECT_FALSE(features.avx512vnni);
|
||||||
|
EXPECT_FALSE(features.avx512bitalg);
|
||||||
|
EXPECT_FALSE(features.avx512vpopcntdq);
|
||||||
|
EXPECT_FALSE(features.avx512_4vnniw);
|
||||||
|
EXPECT_FALSE(features.avx512_4fmaps);
|
||||||
|
// All old cpu features should be set.
|
||||||
|
EXPECT_TRUE(features.aes);
|
||||||
|
EXPECT_TRUE(features.ssse3);
|
||||||
|
EXPECT_TRUE(features.sse4_1);
|
||||||
|
EXPECT_TRUE(features.sse4_2);
|
||||||
|
EXPECT_TRUE(features.avx);
|
||||||
|
EXPECT_FALSE(features.sha);
|
||||||
|
EXPECT_TRUE(features.popcnt);
|
||||||
|
EXPECT_FALSE(features.movbe);
|
||||||
|
EXPECT_FALSE(features.rdrnd);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int KiB = 1024;
|
||||||
|
const int MiB = 1024 * KiB;
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, SandyBridgeTestOsSupport) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000D, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000206A6, 0x00100800, 0x1F9AE3BF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
// avx is disabled if os does not support backing up ymm registers.
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||||
|
EXPECT_FALSE(GetX86Info().features.avx);
|
||||||
|
// avx is disabled if os does not support backing up ymm registers.
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||||
|
EXPECT_TRUE(GetX86Info().features.avx);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, SkyLake) {
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(true);
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x04E);
|
||||||
|
EXPECT_EQ(info.stepping, 0x03);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_SKL);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, Branding) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
|
||||||
|
{{0x80000004, 0}, Leaf{0x352E3220, 0x7A484730, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, "Intel(R) Core(TM) i7-6500U CPU @ 2.50GHz");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, KabyLakeCache) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 2}, Leaf{0x1C004143, 0x00C0003F, 0x000003FF, 0x00000000}},
|
||||||
|
{{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000002}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86CacheInfo();
|
||||||
|
EXPECT_EQ(info.size, 4);
|
||||||
|
EXPECT_EQ(info.levels[0].level, 1);
|
||||||
|
EXPECT_EQ(info.levels[0].cache_type, 1);
|
||||||
|
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[0].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[0].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||||
|
EXPECT_EQ(info.levels[0].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[1].level, 1);
|
||||||
|
EXPECT_EQ(info.levels[1].cache_type, 2);
|
||||||
|
EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[1].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[1].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[1].tlb_entries, 64);
|
||||||
|
EXPECT_EQ(info.levels[1].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[2].level, 2);
|
||||||
|
EXPECT_EQ(info.levels[2].cache_type, 3);
|
||||||
|
EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[2].ways, 4);
|
||||||
|
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[2].tlb_entries, 1024);
|
||||||
|
EXPECT_EQ(info.levels[2].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[3].level, 3);
|
||||||
|
EXPECT_EQ(info.levels[3].cache_type, 3);
|
||||||
|
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
|
||||||
|
EXPECT_EQ(info.levels[3].ways, 12);
|
||||||
|
EXPECT_EQ(info.levels[3].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
|
||||||
|
EXPECT_EQ(info.levels[3].partitioning, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(CpuidX86Test, HSWCache) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000016, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000406E3, 0x00100800, 0x7FFAFBBF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 1}, Leaf{0x1C004122, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 2}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}},
|
||||||
|
{{0x00000004, 3}, Leaf{0x1C03C163, 0x02C0003F, 0x00001FFF, 0x00000006}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x029C67AF, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000121, 0x2C100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x65746E49, 0x2952286C, 0x726F4320, 0x4D542865}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x37692029, 0x3035362D, 0x43205530, 0x40205550}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86CacheInfo();
|
||||||
|
EXPECT_EQ(info.size, 4);
|
||||||
|
EXPECT_EQ(info.levels[0].level, 1);
|
||||||
|
EXPECT_EQ(info.levels[0].cache_type, 1);
|
||||||
|
EXPECT_EQ(info.levels[0].cache_size, 32 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[0].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[0].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[0].tlb_entries, 64);
|
||||||
|
EXPECT_EQ(info.levels[0].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[1].level, 1);
|
||||||
|
EXPECT_EQ(info.levels[1].cache_type, 2);
|
||||||
|
EXPECT_EQ(info.levels[1].cache_size, 32 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[1].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[1].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[1].tlb_entries, 64);
|
||||||
|
EXPECT_EQ(info.levels[1].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[2].level, 2);
|
||||||
|
EXPECT_EQ(info.levels[2].cache_type, 3);
|
||||||
|
EXPECT_EQ(info.levels[2].cache_size, 256 * KiB);
|
||||||
|
EXPECT_EQ(info.levels[2].ways, 8);
|
||||||
|
EXPECT_EQ(info.levels[2].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[2].tlb_entries, 512);
|
||||||
|
EXPECT_EQ(info.levels[2].partitioning, 1);
|
||||||
|
|
||||||
|
EXPECT_EQ(info.levels[3].level, 3);
|
||||||
|
EXPECT_EQ(info.levels[3].cache_type, 3);
|
||||||
|
EXPECT_EQ(info.levels[3].cache_size, 6 * MiB);
|
||||||
|
EXPECT_EQ(info.levels[3].ways, 12);
|
||||||
|
EXPECT_EQ(info.levels[3].line_size, 64);
|
||||||
|
EXPECT_EQ(info.levels[3].tlb_entries, 8192);
|
||||||
|
EXPECT_EQ(info.levels[3].partitioning, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://users.atw.hu/instlatx64/AuthenticAMD0630F81_K15_Godavari_CPUID.txt
|
||||||
|
TEST_F(CpuidX86Test, AMD_K15) {
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000D, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x00630F81, 0x00040800, 0x3E98320B, 0x178BFBFF}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x8000001E, 0x68747541, 0x444D4163, 0x69746E65}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00630F81, 0x10000000, 0x0FEBBFFF, 0x2FD3FBFF}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x20444D41, 0x372D3841, 0x4B303736, 0x64615220}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x206E6F65, 0x202C3752, 0x43203031, 0x75706D6F}},
|
||||||
|
{{0x80000004, 0}, Leaf{0x43206574, 0x7365726F, 0x2B433420, 0x00204736}},
|
||||||
|
{{0x80000005, 0}, Leaf{0xFF40FF18, 0xFF40FF30, 0x10040140, 0x60030140}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
|
||||||
|
EXPECT_STREQ(info.vendor, "AuthenticAMD");
|
||||||
|
EXPECT_EQ(info.family, 0x15);
|
||||||
|
EXPECT_EQ(info.model, 0x38);
|
||||||
|
EXPECT_EQ(info.stepping, 0x01);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info),
|
||||||
|
X86Microarchitecture::AMD_BULLDOZER);
|
||||||
|
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, "AMD A8-7670K Radeon R7, 10 Compute Cores 4C+6G ");
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel00106A1_Nehalem_CPUID.txt
|
||||||
|
TEST_F(CpuidX86Test, Nehalem) {
|
||||||
|
// Pre AVX cpus don't have xsave
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(processor :
|
||||||
|
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||||
|
)");
|
||||||
|
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x000106A2, 0x00100800, 0x00BCE3BD, 0xBFEBFBFF}},
|
||||||
|
{{0x00000002, 0}, Leaf{0x55035A01, 0x00F0B0E3, 0x00000000, 0x09CA212C}},
|
||||||
|
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004121, 0x01C0003F, 0x0000003F, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004122, 0x00C0003F, 0x0000007F, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C004143, 0x01C0003F, 0x000001FF, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C03C163, 0x03C0003F, 0x00000FFF, 0x00000002}},
|
||||||
|
{{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x00021120}},
|
||||||
|
{{0x00000006, 0}, Leaf{0x00000001, 0x00000002, 0x00000001, 0x00000000}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x0000000A, 0}, Leaf{0x07300403, 0x00000000, 0x00000000, 0x00000603}},
|
||||||
|
{{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}},
|
||||||
|
{{0x0000000B, 0}, Leaf{0x00000004, 0x00000002, 0x00000201, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000001, 0x28100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x756E6547, 0x20656E69, 0x65746E49, 0x2952286C}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x55504320, 0x20202020, 0x20202020, 0x40202020}},
|
||||||
|
{{0x80000004, 0}, Leaf{0x30303020, 0x20402030, 0x37382E31, 0x007A4847}},
|
||||||
|
{{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x01006040, 0x00000000}},
|
||||||
|
{{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}},
|
||||||
|
{{0x80000008, 0}, Leaf{0x00003028, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x1A);
|
||||||
|
EXPECT_EQ(info.stepping, 0x02);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::INTEL_NHM);
|
||||||
|
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, "Genuine Intel(R) CPU @ 0000 @ 1.87GHz");
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.sse);
|
||||||
|
EXPECT_TRUE(info.features.sse2);
|
||||||
|
EXPECT_TRUE(info.features.sse3);
|
||||||
|
#ifndef CPU_FEATURES_OS_WINDOWS
|
||||||
|
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
|
||||||
|
// feature detection > sse3.
|
||||||
|
EXPECT_TRUE(info.features.ssse3);
|
||||||
|
EXPECT_TRUE(info.features.sse4_1);
|
||||||
|
EXPECT_TRUE(info.features.sse4_2);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0030673_Silvermont3_CPUID.txt
|
||||||
|
TEST_F(CpuidX86Test, Atom) {
|
||||||
|
// Pre AVX cpus don't have xsave
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI64_INSTRUCTIONS_AVAILABLE);
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_SSE3_INSTRUCTIONS_AVAILABLE);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse2");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse3");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.supplementalsse3");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_1");
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse4_2");
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(
|
||||||
|
flags : fpu mmx sse sse2 sse3 ssse3 sse4_1 sse4_2
|
||||||
|
)");
|
||||||
|
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x0000000B, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x00030673, 0x00100800, 0x41D8E3BF, 0xBFEBFBFF}},
|
||||||
|
{{0x00000002, 0}, Leaf{0x61B3A001, 0x0000FFC2, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000004, 0}, Leaf{0x1C000121, 0x0140003F, 0x0000003F, 0x00000001}},
|
||||||
|
{{0x00000004, 1}, Leaf{0x1C000122, 0x01C0003F, 0x0000003F, 0x00000001}},
|
||||||
|
{{0x00000004, 2}, Leaf{0x1C00C143, 0x03C0003F, 0x000003FF, 0x00000001}},
|
||||||
|
{{0x00000005, 0}, Leaf{0x00000040, 0x00000040, 0x00000003, 0x33000020}},
|
||||||
|
{{0x00000006, 0}, Leaf{0x00000005, 0x00000002, 0x00000009, 0x00000000}},
|
||||||
|
{{0x00000007, 0}, Leaf{0x00000000, 0x00002282, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000008, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x00000009, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x0000000A, 0}, Leaf{0x07280203, 0x00000000, 0x00000000, 0x00004503}},
|
||||||
|
{{0x0000000B, 0}, Leaf{0x00000001, 0x00000001, 0x00000100, 0x00000000}},
|
||||||
|
{{0x0000000B, 1}, Leaf{0x00000004, 0x00000004, 0x00000201, 0x00000000}},
|
||||||
|
{{0x80000000, 0}, Leaf{0x80000008, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000001, 0}, Leaf{0x00000000, 0x00000000, 0x00000101, 0x28100000}},
|
||||||
|
{{0x80000002, 0}, Leaf{0x20202020, 0x6E492020, 0x286C6574, 0x43202952}},
|
||||||
|
{{0x80000003, 0}, Leaf{0x72656C65, 0x52286E6F, 0x50432029, 0x4A202055}},
|
||||||
|
{{0x80000004, 0}, Leaf{0x30303931, 0x20402020, 0x39392E31, 0x007A4847}},
|
||||||
|
{{0x80000005, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
{{0x80000006, 0}, Leaf{0x00000000, 0x00000000, 0x04008040, 0x00000000}},
|
||||||
|
{{0x80000007, 0}, Leaf{0x00000000, 0x00000000, 0x00000000, 0x00000100}},
|
||||||
|
{{0x80000008, 0}, Leaf{0x00003024, 0x00000000, 0x00000000, 0x00000000}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x37);
|
||||||
|
EXPECT_EQ(info.stepping, 0x03);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info),
|
||||||
|
X86Microarchitecture::INTEL_ATOM_SMT);
|
||||||
|
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, " Intel(R) Celeron(R) CPU J1900 @ 1.99GHz");
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.sse);
|
||||||
|
EXPECT_TRUE(info.features.sse2);
|
||||||
|
EXPECT_TRUE(info.features.sse3);
|
||||||
|
#ifndef CPU_FEATURES_OS_WINDOWS
|
||||||
|
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
|
||||||
|
// feature detection > sse3.
|
||||||
|
EXPECT_TRUE(info.features.ssse3);
|
||||||
|
EXPECT_TRUE(info.features.sse4_1);
|
||||||
|
EXPECT_TRUE(info.features.sse4_2);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://github.com/InstLatx64/InstLatx64/blob/master/GenuineIntel/GenuineIntel0000673_P3_KatmaiDP_CPUID.txt
|
||||||
|
TEST_F(CpuidX86Test, P3) {
|
||||||
|
// Pre AVX cpus don't have xsave
|
||||||
|
g_fake_cpu->SetOsBackupsExtendedRegisters(false);
|
||||||
|
#if defined(CPU_FEATURES_OS_WINDOWS)
|
||||||
|
g_fake_cpu->SetWindowsIsProcessorFeaturePresent(
|
||||||
|
PF_XMMI_INSTRUCTIONS_AVAILABLE);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
#if defined(CPU_FEATURES_OS_DARWIN)
|
||||||
|
g_fake_cpu->SetDarwinSysCtlByName("hw.optional.sse");
|
||||||
|
#endif // CPU_FEATURES_OS_DARWIN
|
||||||
|
#if defined(CPU_FEATURES_OS_LINUX_OR_ANDROID)
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
fs.CreateFile("/proc/cpuinfo", R"(
|
||||||
|
flags : fpu mmx sse
|
||||||
|
)");
|
||||||
|
#endif // CPU_FEATURES_OS_LINUX_OR_ANDROID
|
||||||
|
g_fake_cpu->SetLeaves({
|
||||||
|
{{0x00000000, 0}, Leaf{0x00000003, 0x756E6547, 0x6C65746E, 0x49656E69}},
|
||||||
|
{{0x00000001, 0}, Leaf{0x00000673, 0x00000000, 0x00000000, 0x0387FBFF}},
|
||||||
|
{{0x00000002, 0}, Leaf{0x03020101, 0x00000000, 0x00000000, 0x0C040843}},
|
||||||
|
{{0x00000003, 0}, Leaf{0x00000000, 0x00000000, 0x4CECC782, 0x00006778}},
|
||||||
|
});
|
||||||
|
const auto info = GetX86Info();
|
||||||
|
|
||||||
|
EXPECT_STREQ(info.vendor, "GenuineIntel");
|
||||||
|
EXPECT_EQ(info.family, 0x06);
|
||||||
|
EXPECT_EQ(info.model, 0x07);
|
||||||
|
EXPECT_EQ(info.stepping, 0x03);
|
||||||
|
EXPECT_EQ(GetX86Microarchitecture(&info), X86Microarchitecture::X86_UNKNOWN);
|
||||||
|
|
||||||
|
char brand_string[49];
|
||||||
|
FillX86BrandString(brand_string);
|
||||||
|
EXPECT_STREQ(brand_string, "");
|
||||||
|
|
||||||
|
EXPECT_TRUE(info.features.mmx);
|
||||||
|
EXPECT_TRUE(info.features.sse);
|
||||||
|
EXPECT_FALSE(info.features.sse2);
|
||||||
|
EXPECT_FALSE(info.features.sse3);
|
||||||
|
#ifndef CPU_FEATURES_OS_WINDOWS
|
||||||
|
// Currently disabled on Windows as IsProcessorFeaturePresent do not support
|
||||||
|
// feature detection > sse3.
|
||||||
|
EXPECT_FALSE(info.features.ssse3);
|
||||||
|
EXPECT_FALSE(info.features.sse4_1);
|
||||||
|
EXPECT_FALSE(info.features.sse4_2);
|
||||||
|
#endif // CPU_FEATURES_OS_WINDOWS
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(user): test what happens when xsave/osxsave are not present.
|
||||||
|
// TODO(user): test what happens when xmm/ymm/zmm os support are not
|
||||||
|
// present.
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,103 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <climits>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
FakeFile::FakeFile(int file_descriptor, const char* content)
|
||||||
|
: file_descriptor_(file_descriptor), content_(content) {}
|
||||||
|
|
||||||
|
FakeFile::~FakeFile() { assert(!opened_); }
|
||||||
|
|
||||||
|
void FakeFile::Open() {
|
||||||
|
assert(!opened_);
|
||||||
|
opened_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeFile::Close() {
|
||||||
|
assert(opened_);
|
||||||
|
opened_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int FakeFile::Read(int fd, void* buf, size_t count) {
|
||||||
|
assert(count < INT_MAX);
|
||||||
|
assert(fd == file_descriptor_);
|
||||||
|
const size_t remainder = content_.size() - head_index_;
|
||||||
|
const size_t read = count > remainder ? remainder : count;
|
||||||
|
memcpy(buf, content_.data() + head_index_, read);
|
||||||
|
head_index_ += read;
|
||||||
|
assert(read < INT_MAX);
|
||||||
|
return (int)read;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FakeFilesystem::Reset() { files_.clear(); }
|
||||||
|
|
||||||
|
FakeFile* FakeFilesystem::CreateFile(const std::string& filename,
|
||||||
|
const char* content) {
|
||||||
|
auto& file = files_[filename];
|
||||||
|
file =
|
||||||
|
std::unique_ptr<FakeFile>(new FakeFile(next_file_descriptor_++, content));
|
||||||
|
return file.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
FakeFile* FakeFilesystem::FindFileOrNull(const std::string& filename) const {
|
||||||
|
const auto itr = files_.find(filename);
|
||||||
|
return itr == files_.end() ? nullptr : itr->second.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
FakeFile* FakeFilesystem::FindFileOrDie(const int file_descriptor) const {
|
||||||
|
for (const auto& filename_file_pair : files_) {
|
||||||
|
FakeFile* const file_ptr = filename_file_pair.second.get();
|
||||||
|
if (file_ptr->GetFileDescriptor() == file_descriptor) {
|
||||||
|
return file_ptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static FakeFilesystem* kFilesystem = new FakeFilesystem();
|
||||||
|
|
||||||
|
FakeFilesystem& GetEmptyFilesystem() {
|
||||||
|
kFilesystem->Reset();
|
||||||
|
return *kFilesystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int CpuFeatures_OpenFile(const char* filename) {
|
||||||
|
auto* const file = kFilesystem->FindFileOrNull(filename);
|
||||||
|
if (file) {
|
||||||
|
file->Open();
|
||||||
|
return file->GetFileDescriptor();
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" void CpuFeatures_CloseFile(int file_descriptor) {
|
||||||
|
kFilesystem->FindFileOrDie(file_descriptor)->Close();
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" int CpuFeatures_ReadFile(int file_descriptor, void* buffer,
|
||||||
|
size_t buffer_size) {
|
||||||
|
return kFilesystem->FindFileOrDie(file_descriptor)
|
||||||
|
->Read(file_descriptor, buffer, buffer_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Implements a fake filesystem, useful for tests.
|
||||||
|
#ifndef CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
||||||
|
#define CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
#include "internal/filesystem.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
class FakeFile {
|
||||||
|
public:
|
||||||
|
explicit FakeFile(int file_descriptor, const char* content);
|
||||||
|
~FakeFile();
|
||||||
|
|
||||||
|
void Open();
|
||||||
|
void Close();
|
||||||
|
int Read(int fd, void* buf, size_t count);
|
||||||
|
|
||||||
|
int GetFileDescriptor() const { return file_descriptor_; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const int file_descriptor_;
|
||||||
|
const std::string content_;
|
||||||
|
bool opened_ = false;
|
||||||
|
size_t head_index_ = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class FakeFilesystem {
|
||||||
|
public:
|
||||||
|
void Reset();
|
||||||
|
FakeFile* CreateFile(const std::string& filename, const char* content);
|
||||||
|
FakeFile* FindFileOrDie(const int file_descriptor) const;
|
||||||
|
FakeFile* FindFileOrNull(const std::string& filename) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int next_file_descriptor_ = 0;
|
||||||
|
std::unordered_map<std::string, std::unique_ptr<FakeFile>> files_;
|
||||||
|
};
|
||||||
|
|
||||||
|
FakeFilesystem& GetEmptyFilesystem();
|
||||||
|
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_TEST_FILESYSTEM_FOR_TESTING_H_
|
||||||
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "hwcaps_for_testing.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
static auto* const g_hardware_capabilities = new HardwareCapabilities();
|
||||||
|
static auto* const g_platform_types = new PlatformType();
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2) {
|
||||||
|
g_hardware_capabilities->hwcaps = hwcaps;
|
||||||
|
g_hardware_capabilities->hwcaps2 = hwcaps2;
|
||||||
|
}
|
||||||
|
|
||||||
|
HardwareCapabilities CpuFeatures_GetHardwareCapabilities(void) {
|
||||||
|
return *g_hardware_capabilities;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetPlatformTypes(const char* platform, const char* base_platform) {
|
||||||
|
CpuFeatures_StringView_CopyString(str(platform), g_platform_types->platform,
|
||||||
|
sizeof(g_platform_types->platform));
|
||||||
|
CpuFeatures_StringView_CopyString(str(base_platform),
|
||||||
|
g_platform_types->base_platform,
|
||||||
|
sizeof(g_platform_types->base_platform));
|
||||||
|
}
|
||||||
|
|
||||||
|
PlatformType CpuFeatures_GetPlatformType(void) { return *g_platform_types; }
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#ifndef CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
||||||
|
#define CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
||||||
|
|
||||||
|
#include "internal/hwcaps.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
void SetHardwareCapabilities(uint32_t hwcaps, uint32_t hwcaps2);
|
||||||
|
void SetPlatformTypes(const char *platform, const char *base_platform);
|
||||||
|
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
||||||
|
#endif // CPU_FEATURES_TEST_HWCAPS_FOR_TESTING_H_
|
||||||
|
|
@ -0,0 +1,132 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/stack_line_reader.h"
|
||||||
|
|
||||||
|
#include "filesystem_for_testing.h"
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
bool operator==(const StringView& a, const StringView& b) {
|
||||||
|
return CpuFeatures_StringView_IsEquals(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
std::string ToString(StringView view) { return {view.ptr, view.size}; }
|
||||||
|
|
||||||
|
TEST(StackLineReaderTest, Empty) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
auto* file = fs.CreateFile("/proc/cpuinfo", "");
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_TRUE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackLineReaderTest, ManySmallLines) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
auto* file = fs.CreateFile("/proc/cpuinfo", "a\nb\nc");
|
||||||
|
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("a"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("b"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_TRUE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("c"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackLineReaderTest, TruncatedLine) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
auto* file = fs.CreateFile("/proc/cpuinfo", R"(First
|
||||||
|
Second
|
||||||
|
More than 16 characters, this will be truncated.
|
||||||
|
last)");
|
||||||
|
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("First"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("Second"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_FALSE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("More than 16 cha"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_TRUE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("last"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StackLineReaderTest, TruncatedLines) {
|
||||||
|
auto& fs = GetEmptyFilesystem();
|
||||||
|
auto* file = fs.CreateFile("/proc/cpuinfo", R"(More than 16 characters
|
||||||
|
Another line that is too long)");
|
||||||
|
|
||||||
|
StackLineReader reader;
|
||||||
|
StackLineReader_Initialize(&reader, file->GetFileDescriptor());
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_FALSE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("More than 16 cha"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_FALSE(result.eof);
|
||||||
|
EXPECT_FALSE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str("Another line tha"));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const auto result = StackLineReader_NextLine(&reader);
|
||||||
|
EXPECT_TRUE(result.eof);
|
||||||
|
EXPECT_TRUE(result.full_line);
|
||||||
|
EXPECT_EQ(result.line, str(""));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
|
|
@ -0,0 +1,192 @@
|
||||||
|
// Copyright 2017 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#include "internal/string_view.h"
|
||||||
|
|
||||||
|
#include "gtest/gtest.h"
|
||||||
|
|
||||||
|
namespace cpu_features {
|
||||||
|
|
||||||
|
bool operator==(const StringView& a, const StringView& b) {
|
||||||
|
return CpuFeatures_StringView_IsEquals(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
TEST(StringViewTest, Empty) {
|
||||||
|
EXPECT_EQ(kEmptyStringView.ptr, nullptr);
|
||||||
|
EXPECT_EQ(kEmptyStringView.size, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, Build) {
|
||||||
|
const auto view = str("test");
|
||||||
|
EXPECT_EQ(view.ptr[0], 't');
|
||||||
|
EXPECT_EQ(view.size, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_IndexOfChar) {
|
||||||
|
// Found.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'e'), 1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 't'), 0);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("beef"), 'e'), 1);
|
||||||
|
// Not found.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(str("test"), 'z'), -1);
|
||||||
|
// Empty.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOfChar(kEmptyStringView, 'z'), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_IndexOf) {
|
||||||
|
// Found.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("es")), 1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("test")), 0);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("tesstest"), str("test")), 4);
|
||||||
|
// Not found.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("test"), str("aa")), -1);
|
||||||
|
// Empty.
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(kEmptyStringView, str("aa")), -1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_IndexOf(str("aa"), kEmptyStringView), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_StartsWith) {
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("te")));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_StartsWith(str("test"), str("test")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("st")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("est")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_StartsWith(str("test"), str("")));
|
||||||
|
EXPECT_FALSE(
|
||||||
|
CpuFeatures_StringView_StartsWith(str("test"), kEmptyStringView));
|
||||||
|
EXPECT_FALSE(
|
||||||
|
CpuFeatures_StringView_StartsWith(kEmptyStringView, str("test")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_IsEquals) {
|
||||||
|
EXPECT_TRUE(
|
||||||
|
CpuFeatures_StringView_IsEquals(kEmptyStringView, kEmptyStringView));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("")));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str(""), kEmptyStringView));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("test"), str("test")));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_IsEquals(str("a"), str("a")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("b")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("aa"), str("a")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), str("aa")));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(str("a"), kEmptyStringView));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_IsEquals(kEmptyStringView, str("a")));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_PopFront) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 2), str("st"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 0), str("test"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 4), str(""));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopFront(str("test"), 100), str(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_PopBack) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 2), str("te"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 0), str("test"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 4), str(""));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_PopBack(str("test"), 100), str(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_KeepFront) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 2), str("te"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 0), str(""));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 4), str("test"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_KeepFront(str("test"), 6), str("test"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_Front) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_Front(str("apple")), 'a');
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_Front(str("a")), 'a');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_Back) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_Back(str("apple")), 'e');
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_Back(str("a")), 'a');
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_TrimWhitespace) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last ")),
|
||||||
|
str("first middle last"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last ")),
|
||||||
|
str("first middle last"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str(" first middle last")),
|
||||||
|
str("first middle last"));
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_TrimWhitespace(str("first middle last")),
|
||||||
|
str("first middle last"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_ParsePositiveNumber) {
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("42")), 42);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a")), 42);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A")), 42);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2A2a")), 10794);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("0x2a2A")), 10794);
|
||||||
|
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-10")), -1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("-0x2A")), -1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("abc")), -1);
|
||||||
|
EXPECT_EQ(CpuFeatures_StringView_ParsePositiveNumber(str("")), -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_CopyString) {
|
||||||
|
char buf[4];
|
||||||
|
buf[0] = 'X';
|
||||||
|
|
||||||
|
// Empty
|
||||||
|
CpuFeatures_StringView_CopyString(str(""), buf, sizeof(buf));
|
||||||
|
EXPECT_STREQ(buf, "");
|
||||||
|
|
||||||
|
// Less
|
||||||
|
CpuFeatures_StringView_CopyString(str("a"), buf, sizeof(buf));
|
||||||
|
EXPECT_STREQ(buf, "a");
|
||||||
|
|
||||||
|
// exact
|
||||||
|
CpuFeatures_StringView_CopyString(str("abc"), buf, sizeof(buf));
|
||||||
|
EXPECT_STREQ(buf, "abc");
|
||||||
|
|
||||||
|
// More
|
||||||
|
CpuFeatures_StringView_CopyString(str("abcd"), buf, sizeof(buf));
|
||||||
|
EXPECT_STREQ(buf, "abc");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_HasWord) {
|
||||||
|
// Find flags at beginning, middle and end.
|
||||||
|
EXPECT_TRUE(
|
||||||
|
CpuFeatures_StringView_HasWord(str("first middle last"), "first"));
|
||||||
|
EXPECT_TRUE(
|
||||||
|
CpuFeatures_StringView_HasWord(str("first middle last"), "middle"));
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_HasWord(str("first middle last"), "last"));
|
||||||
|
// Do not match partial flags
|
||||||
|
EXPECT_FALSE(
|
||||||
|
CpuFeatures_StringView_HasWord(str("first middle last"), "irst"));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "mid"));
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_HasWord(str("first middle last"), "las"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, CpuFeatures_StringView_GetAttributeKeyValue) {
|
||||||
|
const StringView line = str(" key : first middle last ");
|
||||||
|
StringView key, value;
|
||||||
|
EXPECT_TRUE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
|
||||||
|
EXPECT_EQ(key, str("key"));
|
||||||
|
EXPECT_EQ(value, str("first middle last"));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(StringViewTest, FailingGetAttributeKeyValue) {
|
||||||
|
const StringView line = str("key first middle last");
|
||||||
|
StringView key, value;
|
||||||
|
EXPECT_FALSE(CpuFeatures_StringView_GetAttributeKeyValue(line, &key, &value));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
} // namespace cpu_features
|
||||||
51
crc.c
51
crc.c
|
|
@ -4,17 +4,17 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
//
|
//
|
||||||
// This file is free software: you may copy, redistribute and/or modify it
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
// under the terms of the GNU General Public License as published by the
|
// under the terms of the GNU General Public License as published by the
|
||||||
// Free Software Foundation, either version 2 of the License, or (at your
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
// option) any later version.
|
// option) any later version.
|
||||||
//
|
//
|
||||||
// This file is distributed in the hope that it will be useful, but
|
// This file is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#include "dump1090.h"
|
#include "dump1090.h"
|
||||||
|
|
@ -40,7 +40,7 @@ static void initLookupTables()
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
uint8_t msg[112/8];
|
uint8_t msg[112/8];
|
||||||
|
|
||||||
for (i = 0; i < 256; ++i) {
|
for (i = 0; i < 256; ++i) {
|
||||||
uint32_t c = i << 16;
|
uint32_t c = i << 16;
|
||||||
int j;
|
int j;
|
||||||
|
|
@ -62,7 +62,7 @@ static void initLookupTables()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t modesChecksum(uint8_t *message, int bits)
|
uint32_t modesChecksum(const uint8_t *message, int bits)
|
||||||
{
|
{
|
||||||
uint32_t rem = 0;
|
uint32_t rem = 0;
|
||||||
int i;
|
int i;
|
||||||
|
|
@ -141,7 +141,7 @@ static int prepareSubtable(struct errorinfo *table, int n, int maxsize, int offs
|
||||||
table[n].syndrome ^= single_bit_syndrome[i + offset];
|
table[n].syndrome ^= single_bit_syndrome[i + offset];
|
||||||
table[n].errors = error_bit+1;
|
table[n].errors = error_bit+1;
|
||||||
table[n].bit[error_bit] = i;
|
table[n].bit[error_bit] = i;
|
||||||
|
|
||||||
++n;
|
++n;
|
||||||
n = prepareSubtable(table, n, maxsize, offset, i + 1, endbit, &table[n-1], error_bit + 1, max_errors);
|
n = prepareSubtable(table, n, maxsize, offset, i + 1, endbit, &table[n-1], error_bit + 1, max_errors);
|
||||||
}
|
}
|
||||||
|
|
@ -197,10 +197,10 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
|
|
||||||
maxsize = 0;
|
maxsize = 0;
|
||||||
for (i = 1; i <= max_correct; ++i) {
|
for (i = 1; i <= max_correct; ++i) {
|
||||||
maxsize += combinations(bits - 5, i); // space needed for all i-bit errors
|
maxsize += combinations(bits, i); // space needed for all i-bit errors
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
fprintf(stderr, "Preparing syndrome table to correct up to %d-bit errors (detecting %d-bit errors) in a %d-bit message (max %d entries)\n", max_correct, max_detect, bits, maxsize);
|
fprintf(stderr, "Preparing syndrome table to correct up to %d-bit errors (detecting %d-bit errors) in a %d-bit message (max %d entries)\n", max_correct, max_detect, bits, maxsize);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
@ -210,9 +210,8 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
for (i = 0; i < MODES_MAX_BITERRORS; ++i)
|
for (i = 0; i < MODES_MAX_BITERRORS; ++i)
|
||||||
base_entry.bit[i] = -1;
|
base_entry.bit[i] = -1;
|
||||||
|
|
||||||
// ignore the first 5 bits (DF type)
|
usedsize = prepareSubtable(table, 0, maxsize, 112 - bits, 0, bits, &base_entry, 0, max_correct);
|
||||||
usedsize = prepareSubtable(table, 0, maxsize, 112 - bits, 5, bits, &base_entry, 0, max_correct);
|
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
fprintf(stderr, "%d syndromes (expected %d).\n", usedsize, maxsize);
|
fprintf(stderr, "%d syndromes (expected %d).\n", usedsize, maxsize);
|
||||||
fprintf(stderr, "Sorting syndromes..\n");
|
fprintf(stderr, "Sorting syndromes..\n");
|
||||||
|
|
@ -220,15 +219,15 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
|
|
||||||
qsort(table, usedsize, sizeof(struct errorinfo), syndrome_compare);
|
qsort(table, usedsize, sizeof(struct errorinfo), syndrome_compare);
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
{
|
{
|
||||||
// Show the table stats
|
// Show the table stats
|
||||||
fprintf(stderr, "Undetectable errors:\n");
|
fprintf(stderr, "Undetectable errors:\n");
|
||||||
for (i = 1; i <= max_correct; ++i) {
|
for (i = 1; i <= max_correct; ++i) {
|
||||||
int j, count;
|
int j, count;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
for (j = 0; j < usedsize; ++j)
|
for (j = 0; j < usedsize; ++j)
|
||||||
if (table[j].errors == i && table[j].syndrome == 0)
|
if (table[j].errors == i && table[j].syndrome == 0)
|
||||||
++count;
|
++count;
|
||||||
|
|
||||||
|
|
@ -240,7 +239,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
// Handle ambiguous cases, where there is more than one possible error pattern
|
// Handle ambiguous cases, where there is more than one possible error pattern
|
||||||
// that produces a given syndrome (this happens with >2 bit errors).
|
// that produces a given syndrome (this happens with >2 bit errors).
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
fprintf(stderr, "Finding collisions..\n");
|
fprintf(stderr, "Finding collisions..\n");
|
||||||
#endif
|
#endif
|
||||||
for (i = 0, j = 0; i < usedsize; ++i) {
|
for (i = 0, j = 0; i < usedsize; ++i) {
|
||||||
|
|
@ -264,7 +263,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
#endif
|
#endif
|
||||||
usedsize = j;
|
usedsize = j;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flag collisions we want to detect but not correct
|
// Flag collisions we want to detect but not correct
|
||||||
if (max_detect > max_correct) {
|
if (max_detect > max_correct) {
|
||||||
int flagged;
|
int flagged;
|
||||||
|
|
@ -273,7 +272,7 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
fprintf(stderr, "Flagging collisions between %d - %d bits..\n", max_correct+1, max_detect);
|
fprintf(stderr, "Flagging collisions between %d - %d bits..\n", max_correct+1, max_detect);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
flagged = flagCollisions(table, usedsize, 112 - bits, 5, bits, 0, 1, max_correct+1, max_detect);
|
flagged = flagCollisions(table, usedsize, 112 - bits, 0, bits, 0, 1, max_correct+1, max_detect);
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
fprintf(stderr, "Flagged %d collisions for removal.\n", flagged);
|
fprintf(stderr, "Flagged %d collisions for removal.\n", flagged);
|
||||||
|
|
@ -302,9 +301,9 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
table = realloc(table, usedsize * sizeof(struct errorinfo));
|
table = realloc(table, usedsize * sizeof(struct errorinfo));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
*size_out = usedsize;
|
*size_out = usedsize;
|
||||||
|
|
||||||
#ifdef CRCDEBUG
|
#ifdef CRCDEBUG
|
||||||
{
|
{
|
||||||
// Check the table.
|
// Check the table.
|
||||||
|
|
@ -335,13 +334,13 @@ static struct errorinfo *prepareErrorTable(int bits, int max_correct, int max_de
|
||||||
fprintf(stderr, "Syndrome table summary:\n");
|
fprintf(stderr, "Syndrome table summary:\n");
|
||||||
for (i = 1; i <= max_correct; ++i) {
|
for (i = 1; i <= max_correct; ++i) {
|
||||||
int j, count, possible;
|
int j, count, possible;
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
for (j = 0; j < usedsize; ++j)
|
for (j = 0; j < usedsize; ++j)
|
||||||
if (table[j].errors == i)
|
if (table[j].errors == i)
|
||||||
++count;
|
++count;
|
||||||
|
|
||||||
possible = combinations(bits-5, i);
|
possible = combinations(bits, i);
|
||||||
fprintf(stderr, " %d entries for %d-bit errors (%d possible, %d%% coverage)\n", count, i, possible, 100 * count / possible);
|
fprintf(stderr, " %d entries for %d-bit errors (%d possible, %d%% coverage)\n", count, i, possible, 100 * count / possible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
16
crc.h
16
crc.h
|
|
@ -4,17 +4,17 @@
|
||||||
//
|
//
|
||||||
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
// Copyright (c) 2014,2015 Oliver Jowett <oliver@mutability.co.uk>
|
||||||
//
|
//
|
||||||
// This file is free software: you may copy, redistribute and/or modify it
|
// This file is free software: you may copy, redistribute and/or modify it
|
||||||
// under the terms of the GNU General Public License as published by the
|
// under the terms of the GNU General Public License as published by the
|
||||||
// Free Software Foundation, either version 2 of the License, or (at your
|
// Free Software Foundation, either version 2 of the License, or (at your
|
||||||
// option) any later version.
|
// option) any later version.
|
||||||
//
|
//
|
||||||
// This file is distributed in the hope that it will be useful, but
|
// This file is distributed in the hope that it will be useful, but
|
||||||
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
// General Public License for more details.
|
// General Public License for more details.
|
||||||
//
|
//
|
||||||
// You should have received a copy of the GNU General Public License
|
// You should have received a copy of the GNU General Public License
|
||||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
#ifndef DUMP1090_CRC_H
|
#ifndef DUMP1090_CRC_H
|
||||||
|
|
@ -32,7 +32,7 @@ struct errorinfo {
|
||||||
};
|
};
|
||||||
|
|
||||||
void modesChecksumInit(int fixBits);
|
void modesChecksumInit(int fixBits);
|
||||||
uint32_t modesChecksum(uint8_t *msg, int bitlen);
|
uint32_t modesChecksum(const uint8_t *msg, int bitlen);
|
||||||
struct errorinfo *modesChecksumDiagnose(uint32_t syndrome, int bitlen);
|
struct errorinfo *modesChecksumDiagnose(uint32_t syndrome, int bitlen);
|
||||||
void modesChecksumFix(uint8_t *msg, struct errorinfo *info);
|
void modesChecksumFix(uint8_t *msg, struct errorinfo *info);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,11 @@
|
||||||
Source: dump1090-fa
|
Source: dump1090-fa
|
||||||
Section: embedded
|
Section: embedded
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: Oliver Jowett <oliver@mutability.co.uk>
|
Maintainer: Oliver Jowett <oliver.jowett@flightaware.com>
|
||||||
Build-Depends: debhelper(>=9), libusb-1.0-0-dev, pkg-config, cmake, libncurses5-dev
|
Build-Depends: debhelper(>=10), librtlsdr-dev, libusb-1.0-0-dev, pkg-config, libncurses5-dev, libbladerf-dev
|
||||||
Standards-Version: 3.9.3
|
Standards-Version: 3.9.3
|
||||||
Homepage: https://github.com/mutability/dump1090
|
Homepage: http://www.flightaware.com/
|
||||||
Vcs-Git: https://github.com/mutability/dump1090.git
|
Vcs-Git: https://github.com/flightaware/dump1090.git
|
||||||
|
|
||||||
Package: dump1090
|
Package: dump1090
|
||||||
Architecture: all
|
Architecture: all
|
||||||
|
|
@ -19,12 +19,12 @@ Description: transitional dummy package for dump1090
|
||||||
|
|
||||||
Package: dump1090-fa
|
Package: dump1090-fa
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lighttpd
|
Depends: ${shlibs:Depends}, ${misc:Depends}, libbladerf1 (>= 0.2016.06), adduser, lighttpd
|
||||||
Replaces: dump1090 (<< 3.0)
|
Replaces: dump1090 (<< 3.0)
|
||||||
Breaks: dump1090 (<< 3.0)
|
Breaks: dump1090 (<< 3.0)
|
||||||
Description: ADS-B Ground Station System for RTL-SDR
|
Description: ADS-B Ground Station System for RTL-SDR
|
||||||
Networked Aviation Mode S / ADS-B decoder/translator with RTL-SDR software
|
Networked Aviation Mode S / ADS-B decoder/translator with RTL-SDR software
|
||||||
defined radio USB device support.
|
defined radio USB device support.
|
||||||
.
|
.
|
||||||
This is FlightAware's packaging of dump1090-mutability, customized for use
|
This is FlightAware's fork of dump1090-mutability, customized for use
|
||||||
in the PiAware sdcard images.
|
in the PiAware sdcard images.
|
||||||
|
|
@ -12,20 +12,12 @@ export DH_VERBOSE=1
|
||||||
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
||||||
|
|
||||||
DPKG_EXPORT_BUILDFLAGS = 1
|
DPKG_EXPORT_BUILDFLAGS = 1
|
||||||
include /usr/share/dpkg/buildflags.mk
|
include /usr/share/dpkg/default.mk
|
||||||
|
|
||||||
export DUMP1090_VERSION=$(shell dpkg-parsechangelog | sed -n 's/^Version: /v/p')
|
override_dh_auto_build:
|
||||||
SRCNAME=$(shell dpkg-parsechangelog | sed -n 's/^Source: //p')
|
# starch's gcc doesn't support the compiler flags needed for ARM-specific starch flavors;
|
||||||
|
# turn off runtime CPU detection
|
||||||
install_rtlsdr:
|
dh_auto_build -- RTLSDR=yes BLADERF=yes HACKRF=no LIMESDR=no DUMP1090_VERSION=$(DEB_VERSION) CPUFEATURES=no
|
||||||
mkdir rtl-sdr-build
|
|
||||||
cd rtl-sdr-build && cmake ../rtl-sdr -DCMAKE_INSTALL_PREFIX=./install && make install
|
|
||||||
|
|
||||||
override_dh_auto_build: install_rtlsdr
|
|
||||||
dh_auto_build -- RTLSDR=yes BLADERF=no DIALECT=-std=gnu1x HTMLPATH=/usr/share/$(SRCNAME)/html DUMP1090_VERSION=$(DUMP1090_VERSION) STATIC=yes RTLSDR_PREFIX=rtl-sdr-build/install
|
|
||||||
|
|
||||||
override_dh_auto_test:
|
|
||||||
dh_auto_test -- DIALECT=-std=gnu1x
|
|
||||||
|
|
||||||
override_dh_install:
|
override_dh_install:
|
||||||
dh_install
|
dh_install
|
||||||
|
|
@ -33,9 +25,11 @@ override_dh_install:
|
||||||
cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa
|
cp -a dump1090 debian/dump1090-fa/usr/bin/dump1090-fa
|
||||||
cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa
|
cp -a view1090 debian/dump1090-fa/usr/bin/view1090-fa
|
||||||
|
|
||||||
override_dh_clean:
|
override_dh_installinit:
|
||||||
dh_clean
|
dh_installinit --no-stop-on-upgrade --no-restart-after-upgrade
|
||||||
rm -fr rtl-sdr-build
|
|
||||||
|
override_dh_systemd_start:
|
||||||
|
dh_systemd_start --no-stop-on-upgrade --no-restart-after-upgrade --name=dump1090-fa.service
|
||||||
|
|
||||||
%:
|
%:
|
||||||
dh $@
|
dh $@ --with=systemd
|
||||||
|
|
@ -1,78 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
### BEGIN INIT INFO
|
|
||||||
#
|
|
||||||
# Provides: dump1090-fa
|
|
||||||
# Required-Start: $remote_fs
|
|
||||||
# Required-Stop: $remote_fs
|
|
||||||
# Default-Start: 2 3 4 5
|
|
||||||
# Default-Stop: 0 1 6
|
|
||||||
# Short-Description: dump1090-fa initscript
|
|
||||||
#
|
|
||||||
### END INIT INFO
|
|
||||||
|
|
||||||
. /lib/lsb/init-functions
|
|
||||||
|
|
||||||
DAEMON=/usr/bin/dump1090-fa
|
|
||||||
PIDFILE=/run/dump1090-fa.pid
|
|
||||||
WORKDIR=/run/dump1090-fa
|
|
||||||
RUNAS=dump1090
|
|
||||||
|
|
||||||
test -x $DAEMON || exit 5
|
|
||||||
|
|
||||||
. /etc/default/dump1090-fa
|
|
||||||
|
|
||||||
if [ -f /var/cache/piaware/location.env ]
|
|
||||||
then
|
|
||||||
. /var/cache/piaware/location.env
|
|
||||||
fi
|
|
||||||
|
|
||||||
PROG_ARGS="$RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS $PIAWARE_DUMP1090_LOCATION_OPTIONS \
|
|
||||||
--write-json /run/dump1090-fa --quiet"
|
|
||||||
|
|
||||||
start() {
|
|
||||||
log_daemon_msg "Starting dump1090-fa server" "dump1090-fa"
|
|
||||||
mkdir -p $WORKDIR
|
|
||||||
chown $RUNAS $WORKDIR
|
|
||||||
/sbin/start-stop-daemon --start --oknodo --background --make-pidfile --pidfile $PIDFILE --user $RUNAS --chuid $RUNAS --exec $DAEMON -- $PROG_ARGS
|
|
||||||
status=$?
|
|
||||||
log_begin_msg $status
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
|
||||||
log_daemon_msg "Stopping dump1090-fa server" "dump1090-fa"
|
|
||||||
/sbin/start-stop-daemon --stop --quiet --oknodo --pidfile $PIDFILE --user $RUNAS
|
|
||||||
log_end_msg $?
|
|
||||||
rm -f $PIDFILE
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
status() {
|
|
||||||
echo "no status yet"
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
case "$1" in
|
|
||||||
start)
|
|
||||||
start
|
|
||||||
;;
|
|
||||||
stop)
|
|
||||||
stop
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status
|
|
||||||
;;
|
|
||||||
restart|force-reload)
|
|
||||||
stop && sleep 2 && start
|
|
||||||
;;
|
|
||||||
reload)
|
|
||||||
exit 3
|
|
||||||
;;
|
|
||||||
status)
|
|
||||||
status_of_proc $DAEMON "dump1090-fa server"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: $0 {start|stop|restart|try-restart|force-reload|status}"
|
|
||||||
exit 2
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
# This system has dump1090-fa installed, which wants to use RTL2832-based
|
|
||||||
# digital video dongles in SDR mode via librtlsdr. This file prevents the kernel
|
|
||||||
# video4linux drivers from loading.
|
|
||||||
blacklist dvb_usb_rtl28xxu
|
|
||||||
blacklist rtl2832
|
|
||||||
|
|
@ -1,142 +0,0 @@
|
||||||
# Extracted from the librtlsdr0 package
|
|
||||||
# because we statically link and don't want the package dependency.
|
|
||||||
|
|
||||||
#
|
|
||||||
# Copyright 2012-2013 Osmocom rtl-sdr project
|
|
||||||
#
|
|
||||||
# This program is free software: you can redistribute it and/or modify
|
|
||||||
# it under the terms of the GNU General Public License as published by
|
|
||||||
# the Free Software Foundation, either version 3 of the License, or
|
|
||||||
# (at your option) any later version.
|
|
||||||
#
|
|
||||||
# This program is distributed in the hope that it will be useful,
|
|
||||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
# GNU General Public License for more details.
|
|
||||||
#
|
|
||||||
# You should have received a copy of the GNU General Public License
|
|
||||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
#
|
|
||||||
|
|
||||||
# original RTL2832U vid/pid (hama nano, for example)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2832", MODE:="0666"
|
|
||||||
|
|
||||||
# RTL2832U OEM vid/pid, e.g. ezcap EzTV668 (E4000), Newsky TV28T (E4000/R820T) etc.
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bda", ATTRS{idProduct}=="2838", MODE:="0666"
|
|
||||||
|
|
||||||
# DigitalNow Quad DVB-T PCI-E card (4x FC0012?)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0413", ATTRS{idProduct}=="6680", MODE:="0666"
|
|
||||||
|
|
||||||
# Leadtek WinFast DTV Dongle mini D (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0413", ATTRS{idProduct}=="6f0f", MODE:="0666"
|
|
||||||
|
|
||||||
# Genius TVGo DVB-T03 USB dongle (Ver. B)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0458", ATTRS{idProduct}=="707f", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec Cinergy T Stick Black (rev 1) (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00a9", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec NOXON rev 1 (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b3", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec Deutschlandradio DAB Stick (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b4", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec NOXON DAB Stick - Radio Energy (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b5", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec Media Broadcast DAB Stick (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b7", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec BR DAB Stick (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b8", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec WDR DAB Stick (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00b9", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec MuellerVerlag DAB Stick (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00c0", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec Fraunhofer DAB Stick (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00c6", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec Cinergy T Stick RC (Rev.3) (E4000)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00d3", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec T Stick PLUS (E4000)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00d7", MODE:="0666"
|
|
||||||
|
|
||||||
# Terratec NOXON rev 2 (E4000)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0ccd", ATTRS{idProduct}=="00e0", MODE:="0666"
|
|
||||||
|
|
||||||
# PixelView PV-DT235U(RN) (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1554", ATTRS{idProduct}=="5020", MODE:="0666"
|
|
||||||
|
|
||||||
# Astrometa DVB-T/DVB-T2 (R828D)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="15f4", ATTRS{idProduct}=="0131", MODE:="0666"
|
|
||||||
|
|
||||||
# Compro Videomate U620F (E4000)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0620", MODE:="0666"
|
|
||||||
|
|
||||||
# Compro Videomate U650F (E4000)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0650", MODE:="0666"
|
|
||||||
|
|
||||||
# Compro Videomate U680F (E4000)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="185b", ATTRS{idProduct}=="0680", MODE:="0666"
|
|
||||||
|
|
||||||
# GIGABYTE GT-U7300 (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d393", MODE:="0666"
|
|
||||||
|
|
||||||
# DIKOM USB-DVBT HD
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d394", MODE:="0666"
|
|
||||||
|
|
||||||
# Peak 102569AGPK (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d395", MODE:="0666"
|
|
||||||
|
|
||||||
# KWorld KW-UB450-T USB DVB-T Pico TV (TUA9001)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d397", MODE:="0666"
|
|
||||||
|
|
||||||
# Zaapa ZT-MINDVBZP (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d398", MODE:="0666"
|
|
||||||
|
|
||||||
# SVEON STV20 DVB-T USB & FM (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d39d", MODE:="0666"
|
|
||||||
|
|
||||||
# Twintech UT-40 (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a4", MODE:="0666"
|
|
||||||
|
|
||||||
# ASUS U3100MINI_PLUS_V2 (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3a8", MODE:="0666"
|
|
||||||
|
|
||||||
# SVEON STV27 DVB-T USB & FM (FC0013)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3af", MODE:="0666"
|
|
||||||
|
|
||||||
# SVEON STV21 DVB-T USB & FM
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1b80", ATTRS{idProduct}=="d3b0", MODE:="0666"
|
|
||||||
|
|
||||||
# Dexatek DK DVB-T Dongle (Logilink VG0002A) (FC2580)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1101", MODE:="0666"
|
|
||||||
|
|
||||||
# Dexatek DK DVB-T Dongle (MSI DigiVox mini II V3.0)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1102", MODE:="0666"
|
|
||||||
|
|
||||||
# Dexatek DK 5217 DVB-T Dongle (FC2580)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1103", MODE:="0666"
|
|
||||||
|
|
||||||
# MSI DigiVox Micro HD (FC2580)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1d19", ATTRS{idProduct}=="1104", MODE:="0666"
|
|
||||||
|
|
||||||
# Sweex DVB-T USB (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="a803", MODE:="0666"
|
|
||||||
|
|
||||||
# GTek T803 (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="b803", MODE:="0666"
|
|
||||||
|
|
||||||
# Lifeview LV5TDeluxe (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="c803", MODE:="0666"
|
|
||||||
|
|
||||||
# MyGica TD312 (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="d286", MODE:="0666"
|
|
||||||
|
|
||||||
# PROlectrix DV107669 (FC0012)
|
|
||||||
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1f4d", ATTRS{idProduct}=="d803", MODE:="0666"
|
|
||||||
|
|
@ -1,8 +1,323 @@
|
||||||
dump1090-fa (3.4.0~dev) UNRELEASED; urgency=medium
|
dump1090-fa (7.2) stable; urgency=medium
|
||||||
|
|
||||||
* In development
|
* dump1090: Fix Makefile syntax error for Darwin OS build (courtesy @CodyCodeman, PR #170)
|
||||||
|
* dump1090: set _POSIX_C_SOURCE to fix build failure with uclibc-ng (courtesy @ffontaine, PR #169)
|
||||||
|
* SkyAware: Remove obselete map interface at /dump1090-fa
|
||||||
|
* SkyAware: Remove OSM Black & White layer which is no longer in service
|
||||||
|
|
||||||
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 30 Jan 2017 21:55:42 +0000
|
-- Eric Tran <eric.tran@flightaware.com> Wed, 09 Mar 2022 20:09:55 -0600
|
||||||
|
|
||||||
|
dump1090-fa (7.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Preserve start/upgrade postinst logic for pre 7.1 updates until we support compat 10 behavior
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Wed, 12 Jan 2022 11:37:20 -0600
|
||||||
|
|
||||||
|
dump1090-fa (7.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* dump1090: Allow env vars (not only command line overrdies) to set CPU_FEATURES_{ARCH,UNAME}
|
||||||
|
* dump1090: Treat ARCH=arm64 like ARCH=aarch64
|
||||||
|
* dump1090: Try to respect CFLAGS/CPPFLAGS as far as possible; move required extra flags into a separate var
|
||||||
|
* dump1090: Adaptive gain - more aggressively re-probe for higher gain after a decrease in gain due to increased noise floor
|
||||||
|
* dump1090: Cleanup AVR parsing
|
||||||
|
* SkyAware: Update aircraft db to 20211210
|
||||||
|
* SkyAware: Cleanup unused Openlayers files
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Mon, 20 Dec 2021 11:00:00 -0600
|
||||||
|
|
||||||
|
dump1090-fa (6.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* No-change 6.1 release for PiAware 6.1
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver.jowett@flightaware.com> Mon, 06 Sep 2021 16:06:00 +0800
|
||||||
|
|
||||||
|
dump1090-fa (6.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* dump1090: Adaptive gain feature with associated dump1090-fa config parameters
|
||||||
|
* dump1090: Add support for decoding BDS 4,4 - Meteorological Routine Air Report (MRAR) Comm-B messages
|
||||||
|
* dump1090: Stratux output: include current receiver gain (courtesy @b3nn0, PR #144)
|
||||||
|
* dump1090: Enable rtlsdr bounce buffers on aarch64 (courtesy @wiedehopf for suggestion)
|
||||||
|
* dump1090: New default dump1090-fa config file format
|
||||||
|
* dump1090: Use compat/compat.h for endian-swapping functions in DSP code
|
||||||
|
* dump1090: Report json write errors, with some rate limiting (fixes issue #129)
|
||||||
|
* starch: Update starch to upstream commit 0c8249fa4bc523345c156885542e9192e8bf68fd
|
||||||
|
* SkyAware: restrict overlay rendering to covered areas (reduce source load) (courtesy @wiedehopf, PR #137)
|
||||||
|
* SkyAware: Fix ignored DisplayUnits in config.js (courtesy @paulyc, PR #76)
|
||||||
|
* SkyAware: Update aircraft db to 20210817 with better Australian aircraft & types
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Tue, 31 Aug 2021 12:41:06 -0600
|
||||||
|
|
||||||
|
dump1090-fa (5.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* SkyAware: New Altitude, Speed, Aircraft Ident, and Aircraft Type filters to fine tune the select aircraft you want see
|
||||||
|
* SkyAware: Ability to toggle visibility of ADS-B, MLAT, UAT, TIS-B, and Other aircraft on SkyAware using the check boxes under the aircraft table
|
||||||
|
* SkyAware: Ability to show Aircraft Ident labels for all aircraft on your display (found in the View Toggles list in the settings menu)
|
||||||
|
* SkyAware: A merged SkyAware map of 1090 and UAT aircraft for those with dual 1090/978 setups.
|
||||||
|
* SkyAware: Direct link on the SkyAware map to go to your My ADS-B statistics page on FlightAware.com or a direct link to claim your receiver if it has not been claimed
|
||||||
|
* SkyAware: Bold aircraft Idents are used to indicate tail numbers in the aircraft table rather than using the previous prepended underscore syntax
|
||||||
|
* SkyAware: Default SkyAware link now at <local ip>/skyaware
|
||||||
|
|
||||||
|
* dump1090: limesdr: use --gain value if --limesdr-gain is not specified
|
||||||
|
* dump1090: Switch sample-conversion DSP code to use starch. Provide NEON implementations for ARM when the
|
||||||
|
hardware supports it. Update 8-bit unsigned zero offset to reflect actual rtlsdr behavior. This gives a
|
||||||
|
substantial speedup to sample processing for the 12/16-bit case, and a small speedup for the 8-bit case.
|
||||||
|
Default wisdom provided for arm, aarch64, and x86; see the README for details on generating hardware-
|
||||||
|
specific wisdom files.
|
||||||
|
* dump1090: Make console stats display fixed-width (courtesy @gtjoseph)
|
||||||
|
* dump1090: Add `--json-stats-every` option to control the update cycle of `stats.json`
|
||||||
|
* dump1090: Don't expire data when reading a capture at full speed via `--ifile`
|
||||||
|
* dump1090: Count received messages for each DF type, emit in console stats / `stats.json`
|
||||||
|
* dump1090: Write final stats.json on process exit (mostly useful for `--ifile`)
|
||||||
|
* dump1090: Attempt to correct DF11/17/18 messages where the DF field itself is damaged. This requires
|
||||||
|
a lot more CRC checks when receiving messages off-the-air, but slightly increases the decode rate for
|
||||||
|
DF11/17/18.
|
||||||
|
* dump1090: Add a `--no-df-fix` option to disable the extra DF field correction, for cases where the extra
|
||||||
|
messages are not worth the extra CPU
|
||||||
|
* dump1090: Track recently-seen DF18 addresses, but only count them as recently-seen for DF18 decoding,
|
||||||
|
not for Mode S / DF17
|
||||||
|
|
||||||
|
* dump1090: Support `--stats-every` intervals of less than 1 minute correctly
|
||||||
|
* dump1090: Don't erroneously consider ICAO 000000 as "recently seen" when decoding
|
||||||
|
* dump1090: Fix rare hang (1 in 1e9) in FIFO code due to an off-by-one error in normalize_timespec
|
||||||
|
* dump1090: Correctly expire stale emergency, nac_v data (courtesy @wiedehopf, issue #96)
|
||||||
|
* dump1090: Fix FIFO bounded memory leak / effective reduction in size of the FIFO, triggered if the
|
||||||
|
demodulator couldn't keep up with the input rate
|
||||||
|
* dump1090: Set at least airground = AG_UNCERTAIN for airborne position messages with valid altitudes (issue #113)
|
||||||
|
|
||||||
|
* view1090: Interactive mode enhancements to show min/max RSSI, distances (courtesy @gtjoseph, PR #81)
|
||||||
|
* view1090: Fix table alignment with `--interactive-ttl` > 99 (courtesy @MavEtJu, PR #99)
|
||||||
|
* view1090: Tweak Mode column to display more data-source info
|
||||||
|
* view1090: Fix librtlsdr output interfering with interactive mode display (courtesy @VasiliyTurchenko, PR #116)
|
||||||
|
|
||||||
|
* general: Fix linking against NetBSD curses library (courtesy @jvanwouw, PR #111)
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Thu, 11 Mar 2021 19:26:07 -6000
|
||||||
|
|
||||||
|
dump1090-fa (4.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* dump1090: Build support for OS X, FreeBSD, OpenBSD [courtesy @mikenor / @apparentorder on Github, PRs #33 / #38]
|
||||||
|
* dump1090: Overhaul of SDR / ring buffer / demodulator interface to make it easier to add new SDR types
|
||||||
|
* dump1090: LimeSDR support [courtesy @Glutton on Github, PR #75]
|
||||||
|
* dump1090: HackRF support [courtesy @kr105 on Github, PR #57]
|
||||||
|
* dump1090: Stratux-compatible network output [courtesy @Determinant on Github, PR #61]
|
||||||
|
* dump1090: Change option syntax for 2-bit correction from --fix --fix (introduced in 3.8.0) to --fix-2bit. Any number of --fix options now yields 1-bit correction.
|
||||||
|
* dump1090: Support building under GCC 10 (github issue #65)
|
||||||
|
* dump1090: Include a (disabled by default) example HTTPS configuration [courtesy @jwbernin on Github, PR #66)
|
||||||
|
* dump1090: For manual builds, if no explicit SDR choice is made, autodetect available libraries via pkg-config
|
||||||
|
* dump1090: Add a --version command-line option that shows just the version without needing to show the full help screen
|
||||||
|
* dump1090: Only emit verbose command-line option help if --help is requested, not on any error
|
||||||
|
* dump1090: List supported device types if --device-type is given without a device type
|
||||||
|
* dump1090: Removed Debian Wheezy support (distribution is no longer supported upstream)
|
||||||
|
* dump1090: Remove the "dump1090" Debian metapackage that exists only to provide an upgrade path from very very old installs
|
||||||
|
* dump1090: Add package profiles to selectively build packages with reduced SDR library dependencies. See the README for details.
|
||||||
|
* dump1090: If a network port option (--net-bo-port et al) is given on the command line, implicitly enable networking, but don't enable the default port assignments
|
||||||
|
* dump1090: Provide Mode A / Mode C hit count in aircraft.json
|
||||||
|
* SkyAware: Update aircraft registry to 20200924
|
||||||
|
* SkyAware: Update to OpenLayers6
|
||||||
|
* SkyAware: New basemap layers added/enabled
|
||||||
|
* SkyAware: Added customizable aircraft table columns
|
||||||
|
* SkyAware: Added URL query parameter feature to customize display [courtesy @sigwx on Github, PR #58)
|
||||||
|
* SkyAware: Display registration number in aircraft table if ident is not present
|
||||||
|
* SkyAware: Fix duplicated Access-Control-Allow-Origin header [courtesy @ianrenton on Github, PR #74)
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Thu, 24 Sep 2020 10:21:00 -6000
|
||||||
|
|
||||||
|
dump1090-fa (3.8.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* SkyAware: Fixed SkyAware banner aspect ratio
|
||||||
|
* SkyAware: Fixed issue with "Group By Data Type" and "All Aircraft Trails" checkboxes
|
||||||
|
not saving across browser refreshes
|
||||||
|
* SkyAware: Fixed bug with ShowFlags=False config.js setting
|
||||||
|
* SkyAware: Added position age to aircraft detail pane
|
||||||
|
* SkyAware: Added ability to customize range ring distances in SkyAware
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Thu, 19 Mar 2020 09:20:00 -6000
|
||||||
|
|
||||||
|
dump1090-fa (3.8.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* general: Added support for building on Buster.
|
||||||
|
* general: Replace use of usleep with nanosleep (PR #53)
|
||||||
|
|
||||||
|
* dump1090: When applying CRC correction to a DF11 message, assume that the interrogator
|
||||||
|
overlay value was 0 (e.g. as in an acquisiton squitter) and use the full 24-bit syndrome
|
||||||
|
to correct errors; do not zero out the low 7 bits of the syndrome.
|
||||||
|
* dump1090: Changes in aircraft tracking to try to reduce the number of bogus aircraft seen
|
||||||
|
due to noise; this replaces the crude "require 2 messages" metric used previously.
|
||||||
|
* dump1090: Added a new statistic for "unreliable tracks", aircraft that were tracked but
|
||||||
|
which never passed the threshold for being considered a real aircraft.
|
||||||
|
* dump1090: Added support for per-connection verbatim mode. "--net-verbatim" now controls the
|
||||||
|
default connection setting, and the per-connection mode can be changed by a Beast settings
|
||||||
|
command.
|
||||||
|
* dump1090: Replaced "--aggressive" with "--fix --fix" for 2-bit CRC correction; include
|
||||||
|
support for this in the standard build. 2-bit corrected messages are only emitted on
|
||||||
|
verbatim connections.
|
||||||
|
* dump1090: Update package default options: include "--fix", increase "--net-ro-size",
|
||||||
|
decrease "--net-ro-interval", remove a duplicated "--net-bo-port" option.
|
||||||
|
* dump1090: Fixes to CPR decoding when multiple position sources (e.g. ADS-B and MLAT) are
|
||||||
|
being simultaneously received (PR #55)
|
||||||
|
* dump1090: Track ADS-B, ADS-R, and TIS-B versions independently; use the appropriate version
|
||||||
|
when decoding version-dependent messages.
|
||||||
|
|
||||||
|
* view1090: Include ADS-B version in interactive display
|
||||||
|
* view1090: Display a warning in the header in interactive mode if the dump1090 connection
|
||||||
|
has been lost
|
||||||
|
* view1090: Request verbatim mode when connecting to dump1090
|
||||||
|
* view1090: Exit on connection loss in --no-interactive mode
|
||||||
|
|
||||||
|
* SkyAware: Corrected icon selection for some aircraft types
|
||||||
|
* SkyAware: Fixed display of settings checkboxes on high-DPI displays (PR #54)
|
||||||
|
* SkyAware: Fixes to info box display (PR #51)
|
||||||
|
* SkyAware: Hide scroll bar when not needed (PR #22)
|
||||||
|
* SkyAware: Update aircraft registry to 20191216
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver.jowett@flightaware.com> Mon, 30 Dec 2019 22:11:52 +0800
|
||||||
|
|
||||||
|
dump1090-fa (3.7.2) stable; urgency=medium
|
||||||
|
|
||||||
|
* dump1090: Fix reversed sense of Track Angle/Heading bit in surface opstatus messages
|
||||||
|
* dump1090: Have filter-regs emit a special value "-COMPUTED-" for filtered data
|
||||||
|
values, rather than blanking them out entirely
|
||||||
|
* Fix registration side mappings with a non-zero offset
|
||||||
|
* dump1090: Update aircraft DB to 20190816
|
||||||
|
* dump1090: Reject outright libbladerf that's too old
|
||||||
|
* dump1090: Trigger build after bladeRF build; turn off build durability; turn
|
||||||
|
off concurrent builds
|
||||||
|
* SkyAware: SkyAware Renaming
|
||||||
|
* SkyAware: Fix some display errors for ground vehicles
|
||||||
|
* SkyAware: Fix aircraft trail handling
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Mon, 09 Sep 2019 09:25:00 -6000
|
||||||
|
|
||||||
|
dump1090-fa (3.7.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* dump1090: TSV buffer overflow fix/increase max TSV packet size
|
||||||
|
* dump1090: Fix incorrect mode_s bit number usage
|
||||||
|
* dump1090: Rework use of pkg-config to work around librtlsdr packaging bugs
|
||||||
|
in Ubuntu distro
|
||||||
|
* dump1090: Minimal polyfill to support building older bladeRF libs
|
||||||
|
* dump1090: Add COMMB_AMBIGUOUS enum type for Comm-B messages we're unsure of
|
||||||
|
* dump1090: Comm-b message decoding updates
|
||||||
|
* dump1090: Require more fields to be populated in BDS5,0/BDS6,0 before accepting
|
||||||
|
* dump1090: Update aircraft DB to 20190502
|
||||||
|
* dump1090: Doc/README updates
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Fri, 03 May 2019 12:35:00 -6000
|
||||||
|
|
||||||
|
dump1090-fa (3.7.0.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* dump1090: Fix piaware lat/lon variable
|
||||||
|
|
||||||
|
-- Eric Tran <eric.tran@flightaware.com> Fri, 29 Mar 2019 7:04:00 -6000
|
||||||
|
|
||||||
|
dump1090-fa (3.7.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* dump1090: Fix Rc decoding errors
|
||||||
|
* dump1090: Compute ADS-B v0 NACp/SIL
|
||||||
|
* dump1090: When generating aircraft.json, leave space for the final line;
|
||||||
|
otherwise the generated json may have trailing garbage
|
||||||
|
* dump1090: Don't update the known-address-set from DF18 messages
|
||||||
|
* Skyview: use heading data for icon orientation if track data is unavailable
|
||||||
|
* Skyview: don't spin forever if there's no history to load / receiver.json
|
||||||
|
is missing
|
||||||
|
* dump1090: Bail out if rtlsdr_read_async() returns early; it probably means we lost
|
||||||
|
the USB device. There was a workaround for this (originally implemented
|
||||||
|
in dump1090-mutability) that got lost in the refactoring needed to support
|
||||||
|
different SDRs. librtlsdr can still be flaky under disconnect conditions, so
|
||||||
|
this won't catch everything.
|
||||||
|
* dump1090: add ENABLED to /etc/default/dump1090-fa
|
||||||
|
* dump1090: track FMS and MCP selected altitudes separately
|
||||||
|
* skyview: use whichever selected altitude is available
|
||||||
|
* faup1090: updates to support PiAware 3.7.0
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 22 Mar 2019 15:58:04 +0000
|
||||||
|
|
||||||
|
dump1090-fa (3.6.3) stable; urgency=medium
|
||||||
|
|
||||||
|
* Fix port 30003 output (Basestation) timestamp formatting broken in 3.6.0
|
||||||
|
* Ignore altitudes in DF17 "airborne" positions with airGround = ground
|
||||||
|
* SkyView layout change and proper support for extended data fields
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Tue, 11 Sep 2018 14:52:20 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.6.2) stable; urgency=medium
|
||||||
|
|
||||||
|
* Update SkyView flags for Libya, Serbia, Montenegro
|
||||||
|
* Improve handling of bad callsigns in ADS-B messages
|
||||||
|
* Update FlightAware aircraft static data export
|
||||||
|
* Add --direct option to enable rtlsdr direct sampling mode
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 27 Jul 2018 18:32:30 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.6.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Fix tracking of NICbaro
|
||||||
|
* Don't translate 7x00 to emergency status, it obscures the source of the
|
||||||
|
data (squawk vs ADS-B v2)
|
||||||
|
* Support for building on stretch
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 16 Jul 2018 14:58:59 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.6.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* dump1090: implement speculative decoding for Comm-B messages, capturing
|
||||||
|
most of the Mode S EHS data:
|
||||||
|
BDS 1,0 (datalink capabilities); BDS 1,7 (GICB capabilities);
|
||||||
|
BDS 2,0 (aircraft identification); BDS 3,0 (ACAS RA);
|
||||||
|
BDS 4,0 (vertical intention); BDS 5,0 (track and turn);
|
||||||
|
BDS 6,0 (heading and speed)
|
||||||
|
* dump1090: implement decoding of most of DO-260A/DO-260B including
|
||||||
|
ADS-B version, autopilot settings, NIC/Rc, NAC, SIL, GVA, etc.
|
||||||
|
* dump1090: aircraft state tracking overhaul; track data age in milliseconds
|
||||||
|
* dump1090: emit newly decoded fields in aircraft.json
|
||||||
|
* Skyview: experimental display of new fields, disabled by default; to
|
||||||
|
enable, set ExtendedData = true in config.js or add #extended to the URL
|
||||||
|
* Skyview: Remove obsolete chartbundle WAC layer, add heli layer
|
||||||
|
* Skyview: Remove Mapzen layer as Mapzen is shutting down
|
||||||
|
* faup1090: Restructure emitted data to include data age and source
|
||||||
|
* faup1090: Include newly decoded fields in reports
|
||||||
|
* dump1090, faup1090: fix use of snprintf to correctly handle buffer overruns
|
||||||
|
* dump1090: don't bother tracking ICAO 000000
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Wed, 09 May 2018 22:34:24 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.5.3) stable; urgency=medium
|
||||||
|
|
||||||
|
* Skip 3.5.2 to align with piaware versioning
|
||||||
|
* Skyview: Update OpenLayers to fix performance problems on some browsers
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Fri, 03 Nov 2017 22:44:40 +0000
|
||||||
|
|
||||||
|
dump1090-fa (3.5.1) stable; urgency=medium
|
||||||
|
|
||||||
|
* Skyview: fix font mappings
|
||||||
|
* Skyview: mark tisb_icao and tisb_other addresses as TIS-B
|
||||||
|
* Skyview: fix unit selection on Firefox
|
||||||
|
* Skyview: report data source correctly in popup
|
||||||
|
* Skyview: change default color for grounded aircraft to brown
|
||||||
|
* Skyview: initial history load speedups (Steven Davies)
|
||||||
|
* Skyview: fix L2T/L2P icon selection
|
||||||
|
* Makefile cleanups (Michael Tatarinov)
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 31 Jul 2017 13:43:32 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.5.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* SkyView map UI added.
|
||||||
|
* Only enable lighttpd config once, not on every package upgrade in case the
|
||||||
|
user has deliberately disabled it.
|
||||||
|
* Fix AGC gain setting.
|
||||||
|
* Updated the FlightAware aircraft data export.
|
||||||
|
* Minor bugfixes.
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Mon, 03 Apr 2017 17:53:48 +0100
|
||||||
|
|
||||||
|
dump1090-fa (3.4.0) stable; urgency=medium
|
||||||
|
|
||||||
|
* Add bladeRF support.
|
||||||
|
* Clean up the FlightAware photos link so it works for registrations containing
|
||||||
|
non-alphanumeric characters.
|
||||||
|
|
||||||
|
-- Oliver Jowett <oliver@mutability.co.uk> Thu, 09 Feb 2017 17:41:43 +0000
|
||||||
|
|
||||||
dump1090-fa (3.3.0) stable; urgency=medium
|
dump1090-fa (3.3.0) stable; urgency=medium
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
9
|
10
|
||||||
|
|
|
||||||
|
|
@ -1,30 +1,22 @@
|
||||||
Source: dump1090-fa
|
Source: dump1090-fa
|
||||||
Section: embedded
|
Section: embedded
|
||||||
Priority: extra
|
Priority: extra
|
||||||
Maintainer: Oliver Jowett <oliver@mutability.co.uk>
|
Maintainer: Oliver Jowett <oliver.jowett@flightaware.com>
|
||||||
Build-Depends: debhelper(>=9), librtlsdr-dev, libusb-1.0-0-dev, pkg-config, dh-systemd, libncurses5-dev, libbladerf-dev
|
Build-Depends: debhelper(>=10),
|
||||||
|
librtlsdr-dev <!custom> <rtlsdr>,
|
||||||
|
libbladerf-dev <!custom> <bladerf>,
|
||||||
|
libhackrf-dev <!custom> <hackrf>,
|
||||||
|
liblimesuite-dev <!custom> <limesdr>,
|
||||||
|
libusb-1.0-0-dev <!custom> <rtlsdr> <bladerf> <hackrf> <limesdr>,
|
||||||
|
pkg-config, libncurses5-dev
|
||||||
Standards-Version: 3.9.3
|
Standards-Version: 3.9.3
|
||||||
Homepage: https://github.com/mutability/dump1090
|
Homepage: http://www.flightaware.com/
|
||||||
Vcs-Git: https://github.com/mutability/dump1090.git
|
Vcs-Git: https://github.com/flightaware/dump1090.git
|
||||||
|
|
||||||
Package: dump1090
|
|
||||||
Architecture: all
|
|
||||||
Depends: dump1090-fa, ${misc:Depends}
|
|
||||||
Priority: extra
|
|
||||||
Section: oldlibs
|
|
||||||
Description: transitional dummy package for dump1090
|
|
||||||
This is a transitional dummy package to handle upgrades from
|
|
||||||
the old package name of "dump1090" to the new package name of
|
|
||||||
"dump1090-fa". It can safely be removed.
|
|
||||||
|
|
||||||
Package: dump1090-fa
|
Package: dump1090-fa
|
||||||
Architecture: any
|
Architecture: any
|
||||||
Depends: ${shlibs:Depends}, ${misc:Depends}, libbladerf1(>=2016.06), libbladerf-udev, adduser, lighttpd
|
Depends: ${shlibs:Depends}, ${misc:Depends}, adduser, lighttpd
|
||||||
Replaces: dump1090 (<< 3.0)
|
Description: FlightAware ADS-B Ground Station System for SDRs
|
||||||
Breaks: dump1090 (<< 3.0)
|
Networked Aviation Mode S / ADS-B decoder/translator with support
|
||||||
Description: ADS-B Ground Station System for RTL-SDR
|
for RTL-SDR, BladeRF, HackRF, and LimeSDR software defined radio USB
|
||||||
Networked Aviation Mode S / ADS-B decoder/translator with RTL-SDR software
|
device support.
|
||||||
defined radio USB device support.
|
|
||||||
.
|
|
||||||
This is FlightAware's packaging of dump1090-mutability, customized for use
|
|
||||||
in the PiAware sdcard images.
|
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,62 @@
|
||||||
# dump1090-fa configuration
|
# dump1090-fa configuration
|
||||||
# This is read by the systemd service file as an environment file,
|
# This is sourced by /usr/share/dump1090-fa/start-dump1090-fa as a
|
||||||
# and evaluated by some scripts as a POSIX shell fragment.
|
# shellscript fragment.
|
||||||
|
|
||||||
# If you are using a PiAware sdcard image, this config file is regenerated
|
# dump1090-fa won't automatically start unless ENABLED=yes
|
||||||
# on boot based on the contents of piaware-config.txt; any changes made to this
|
ENABLED=yes
|
||||||
# file will be lost.
|
|
||||||
|
|
||||||
RECEIVER_OPTIONS="--device-index 0 --gain -10 --ppm 0 --net-bo-port 30005"
|
# SDR device type. Use "none" for a net-only configuration
|
||||||
DECODER_OPTIONS="--max-range 360"
|
RECEIVER=rtlsdr
|
||||||
NET_OPTIONS="--net --net-heartbeat 60 --net-ro-size 1000 --net-ro-interval 1 --net-ri-port 0 --net-ro-port 30002 --net-sbs-port 30003 --net-bi-port 30004,30104 --net-bo-port 30005"
|
# serial number or device index of device to use (only needed if there is more than one SDR connected)
|
||||||
JSON_OPTIONS="--json-location-accuracy 1"
|
RECEIVER_SERIAL=
|
||||||
|
# Initial receiver gain, in dB. If adaptive gain is enabled (see below) the actual gain
|
||||||
|
# may change over time
|
||||||
|
RECEIVER_GAIN=60
|
||||||
|
|
||||||
|
# Adjust gain to try to achieve optimal dynamic range / noise floor?
|
||||||
|
ADAPTIVE_DYNAMIC_RANGE=yes
|
||||||
|
# Target dynamic range in dB (leave blank to autoselect based on SDR type)
|
||||||
|
ADAPTIVE_DYNAMIC_RANGE_TARGET=
|
||||||
|
# Reduce gain when loud message bursts from nearby aircraft are seen?
|
||||||
|
ADAPTIVE_BURST=no
|
||||||
|
# Gain range to allow when changing gain, in dB (empty = no limit)
|
||||||
|
ADAPTIVE_MIN_GAIN=
|
||||||
|
ADAPTIVE_MAX_GAIN=
|
||||||
|
|
||||||
|
# Turn on options to reduce load on slower CPUs, at the expense of slightly worse decoder performance.
|
||||||
|
# Setting "auto" will enable these options only if the CPU appears to be a slow CPU (currently this
|
||||||
|
# means armv6 only, e.g. Pi Zero)
|
||||||
|
SLOW_CPU=auto
|
||||||
|
# Local wisdom file used to select DSP implementations; uses built-in ranking if the file is missing
|
||||||
|
WISDOM=/etc/dump1090-fa/wisdom.local
|
||||||
|
|
||||||
|
# Correct CRC errors where possible
|
||||||
|
ERROR_CORRECTION=yes
|
||||||
|
|
||||||
|
# Receiver location, used for some types of position decoding. Provide the location as
|
||||||
|
# signed decimal degrees. If not given here, dump1090 will also try to read a receiver
|
||||||
|
# location from /var/cache/piaware/location.env (written automatically by PiAware, if installed)
|
||||||
|
RECEIVER_LAT=
|
||||||
|
RECEIVER_LON=
|
||||||
|
# Maximum range, in NM. Positions more distant than this are ignored. No limit if not set.
|
||||||
|
MAX_RANGE=360
|
||||||
|
|
||||||
|
# Network ports to listen on for connections
|
||||||
|
NET_RAW_INPUT_PORTS=
|
||||||
|
NET_RAW_OUTPUT_PORTS=30002
|
||||||
|
NET_SBS_OUTPUT_PORTS=30003
|
||||||
|
NET_BEAST_INPUT_PORTS=30004,30104
|
||||||
|
NET_BEAST_OUTPUT_PORTS=30005
|
||||||
|
|
||||||
|
# Accuracy of location written to JSON output
|
||||||
|
JSON_LOCATION_ACCURACY=1
|
||||||
|
|
||||||
|
# Additional options can be added here:
|
||||||
|
EXTRA_OPTIONS=""
|
||||||
|
|
||||||
|
# If OVERRIDE_OPTIONS is set, only those options are used; all other options
|
||||||
|
# in this config file are ignored.
|
||||||
|
OVERRIDE_OPTIONS=""
|
||||||
|
|
||||||
|
# This is a marker to make it easier for scripts to identify a v6-style config file
|
||||||
|
CONFIG_STYLE=6
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,8 @@
|
||||||
public_html/* usr/share/dump1090-fa/html
|
public_html/* usr/share/skyaware/html
|
||||||
debian/lighttpd/* etc/lighttpd/conf-available
|
debian/lighttpd/* etc/lighttpd/conf-available
|
||||||
bladerf/* /usr/share/dump1090-fa/bladerf
|
bladerf/* usr/share/dump1090-fa/bladerf
|
||||||
|
debian/start-dump1090-fa usr/share/dump1090-fa/
|
||||||
|
debian/generate-wisdom usr/share/dump1090-fa/
|
||||||
|
debian/upgrade-config usr/share/dump1090-fa/
|
||||||
|
debian/dump1090-fa.default usr/share/dump1090-fa/
|
||||||
|
starch-benchmark /usr/lib/dump1090-fa/
|
||||||
|
|
|
||||||
|
|
@ -35,17 +35,62 @@ case "$1" in
|
||||||
adduser "$RUNAS" plugdev
|
adduser "$RUNAS" plugdev
|
||||||
|
|
||||||
# set up lighttpd
|
# set up lighttpd
|
||||||
echo "Enabling lighttpd integration.." >&2
|
if dpkg --compare-versions "$2" lt "3.1.0"
|
||||||
lighty-enable-mod dump1090-fa || true
|
|
||||||
|
|
||||||
# only enable the statcache config if there is nothing else around that already
|
|
||||||
# configures it, because lighttpd fails if it's configured twice
|
|
||||||
if ! grep -q -E '^\S*server.stat-cache-engine' /etc/lighttpd/conf-enabled/*.conf
|
|
||||||
then
|
then
|
||||||
echo "Enabling lighttpd integration (stat cache).." >&2
|
echo "Enabling lighttpd integration.." >&2
|
||||||
lighty-enable-mod dump1090-fa-statcache || true
|
lighty-enable-mod dump1090-fa || true
|
||||||
|
|
||||||
|
# only enable the statcache config if there is nothing else around that already
|
||||||
|
# configures it, because lighttpd fails if it's configured twice
|
||||||
|
if ! grep -q -E '^\S*server.stat-cache-engine' /etc/lighttpd/conf-enabled/*.conf
|
||||||
|
then
|
||||||
|
echo "Enabling lighttpd integration (stat cache).." >&2
|
||||||
|
lighty-enable-mod dump1090-fa-statcache || true
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# on upgrade, add an ENABLED line if it's not already present
|
||||||
|
if dpkg --compare-versions "$2" lt-nl "3.7.0"
|
||||||
|
then
|
||||||
|
if [ -f /etc/default/dump1090-fa ]
|
||||||
|
then
|
||||||
|
if ! grep -q -E '^ENABLED=' /etc/default/dump1090-fa
|
||||||
|
then
|
||||||
|
echo "Setting ENABLED=yes in /etc/default/dump1090-fa.." >&2
|
||||||
|
echo "# Automatically added by upgrade from $2" >>/etc/default/dump1090-fa
|
||||||
|
echo "ENABLED=yes" >>/etc/default/dump1090-fa
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# on upgrade from pre-6.0, update the defaults file to the new syntax
|
||||||
|
if dpkg --compare-versions "$2" lt-nl "6.0"
|
||||||
|
then
|
||||||
|
if [ -f /etc/default/dump1090-fa ]
|
||||||
|
then
|
||||||
|
echo "Trying to upgrade existing config to new syntax.." >&2
|
||||||
|
/usr/share/dump1090-fa/upgrade-config /etc/default/dump1090-fa /usr/share/dump1090-fa/dump1090-fa.default \
|
||||||
|
|| echo "Something went wrong upgrading the config; your config may be broken. Sorry!" >&1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
if dpkg --compare-versions "$2" le "5.0"
|
||||||
|
then
|
||||||
|
echo "Enabling lighttpd skyaware module.." >&2
|
||||||
|
lighty-enable-mod skyaware || true
|
||||||
|
|
||||||
|
fi
|
||||||
|
|
||||||
|
# dump1090-fa lighttpd module deprecated in 7.2
|
||||||
|
if dpkg --compare-versions "$2" lt "7.2"
|
||||||
|
then
|
||||||
|
if [ -e /etc/lighttpd/conf-enabled/89-dump1090-fa.conf ]
|
||||||
|
then
|
||||||
|
echo "Disabling deprecated lighttpd dump1090-fa module..." >&2
|
||||||
|
lighty-disable-mod dump1090-fa || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Restarting lighttpd.." >&2
|
echo "Restarting lighttpd.." >&2
|
||||||
invoke-rc.d lighttpd restart || true
|
invoke-rc.d lighttpd restart || true
|
||||||
;;
|
;;
|
||||||
|
|
|
||||||
|
|
@ -7,17 +7,15 @@ Wants=network.target
|
||||||
After=network.target
|
After=network.target
|
||||||
|
|
||||||
[Service]
|
[Service]
|
||||||
EnvironmentFile=/etc/default/dump1090-fa
|
|
||||||
EnvironmentFile=-/var/cache/piaware/location.env
|
|
||||||
User=dump1090
|
User=dump1090
|
||||||
RuntimeDirectory=dump1090-fa
|
RuntimeDirectory=dump1090-fa
|
||||||
RuntimeDirectoryMode=0755
|
RuntimeDirectoryMode=0755
|
||||||
ExecStart=/usr/bin/dump1090-fa \
|
ExecStart=/usr/share/dump1090-fa/start-dump1090-fa --write-json %t/dump1090-fa
|
||||||
$RECEIVER_OPTIONS $DECODER_OPTIONS $NET_OPTIONS $JSON_OPTIONS $PIAWARE_DUMP1090_LOCATION_OPTIONS \
|
SyslogIdentifier=dump1090-fa
|
||||||
--write-json /run/dump1090-fa --quiet
|
|
||||||
Type=simple
|
Type=simple
|
||||||
Restart=on-failure
|
Restart=on-failure
|
||||||
RestartSec=30
|
RestartSec=30
|
||||||
|
RestartPreventExitStatus=64
|
||||||
Nice=-5
|
Nice=-5
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
# This script generates a machine-specific wisdom file for dump1090-fa
|
||||||
|
# (containing information about which DSP implementations are fastest)
|
||||||
|
|
||||||
|
WORKDIR=$(mktemp -t -d wisdom.XXXXXX)
|
||||||
|
|
||||||
|
echo "Benchmarking .. this will take a while." >&2
|
||||||
|
|
||||||
|
# generate initial wisdom so that twopass implementations have something to work with
|
||||||
|
echo "First pass: generating $WORKDIR/wisdom.initial" >&2
|
||||||
|
/usr/lib/dump1090-fa/starch-benchmark -i 5 -o $WORKDIR/wisdom.initial magnitude_uc8 magnitude_uc8_aligned mean_power_u16 mean_power_u16_aligned
|
||||||
|
|
||||||
|
# generate the real wisdom
|
||||||
|
echo "Second pass: generating $WORKDIR/wisdom.local" >&2
|
||||||
|
/usr/lib/dump1090-fa/starch-benchmark -i 5 -r $WORKDIR/wisdom.initial -o $WORKDIR/wisdom.local
|
||||||
|
|
||||||
|
echo "Wisdom written to $WORKDIR/wisdom.local" >&2
|
||||||
|
echo "Copy this file to /etc/dump1090-fa/wisdom.local" >&2
|
||||||
|
echo "(and restart dump1090-fa) to start using it." >&2
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
# Allows access to the static files that provide the dump1090 map view,
|
|
||||||
# and also to the dynamically-generated json parts that contain aircraft
|
|
||||||
# data and are periodically written by the dump1090 daemon.
|
|
||||||
|
|
||||||
alias.url += (
|
|
||||||
"/dump1090-fa/data/" => "/run/dump1090-fa/",
|
|
||||||
"/dump1090-fa/" => "/usr/share/dump1090-fa/html/"
|
|
||||||
)
|
|
||||||
|
|
||||||
# redirect the slash-less URL
|
|
||||||
url.redirect += (
|
|
||||||
"^/dump1090-fa$" => "/dump1090-fa/"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Listen on port 8080 and serve the map there, too.
|
|
||||||
$SERVER["socket"] == ":8080" {
|
|
||||||
alias.url += (
|
|
||||||
"/data/" => "/run/dump1090-fa/",
|
|
||||||
"/" => "/usr/share/dump1090-fa/html/"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
# Add CORS header
|
|
||||||
server.modules += ( "mod_setenv" )
|
|
||||||
$HTTP["url"] =~ "^/dump1090-fa/data/.*\.json$" {
|
|
||||||
setenv.add-response-header = ( "Access-Control-Allow-Origin" => "*" )
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue