mirror of
https://github.com/gbdev/rgbds.git
synced 2026-08-25 08:14:31 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
76c1995559 | ||
|
|
ae84570f04 | ||
|
|
094a31ef8c | ||
|
|
291dcf3b6c | ||
|
|
a890bd072b | ||
|
|
2f6c808ccb | ||
|
|
e80907abd0 | ||
|
|
25d39155d3 | ||
|
|
77021d229b | ||
|
|
1b250b90b2 | ||
|
|
e2b4723489 | ||
|
|
2507413162 | ||
|
|
e023a84d04 | ||
|
|
34c127d9c3 | ||
|
|
9a930988c2 | ||
|
|
8c4204c542 | ||
|
|
663c1930ec | ||
|
|
30ccf43f44 | ||
|
|
fdc17adbcb | ||
|
|
cc196954f3 | ||
|
|
55b6cfff84 | ||
|
|
1fc73b04eb | ||
|
|
d05703c692 | ||
|
|
5dbfafcc55 | ||
|
|
a265b85d9d | ||
|
|
28abf03c0a | ||
|
|
7e7f92f18c | ||
|
|
7461170956 | ||
|
|
57d966d6e0 | ||
|
|
17752d7094 | ||
|
|
4216f0a9b0 | ||
|
|
e3fde986ad | ||
|
|
aa99ed056c | ||
|
|
46d6652df1 | ||
|
|
5406674cdd | ||
|
|
5d2e2e2182 | ||
|
|
a929f36bc5 | ||
|
|
bdb84a901f | ||
|
|
093631ca0b | ||
|
|
7e127a4e52 | ||
|
|
b8093847dc | ||
|
|
8d1b56bcf5 | ||
|
|
5fb7fcf461 | ||
|
|
ee900ae7a3 | ||
|
|
3ca58e13dc | ||
|
|
aaa4e17454 | ||
|
|
a81d383f75 | ||
|
|
60019cf476 | ||
|
|
5a6a44cbc1 | ||
|
|
b61a187b19 | ||
|
|
6382f13647 | ||
|
|
714d39c86f | ||
|
|
f11241c2ae | ||
|
|
cb47ac8b97 | ||
|
|
028e7af7d1 | ||
|
|
e141da1d94 | ||
|
|
35367282e4 | ||
|
|
4c0fa6732e | ||
|
|
e9d9a44687 | ||
|
|
611bd46e0b | ||
|
|
e67254093e | ||
|
|
3ce3d2f662 | ||
|
|
3da9d81071 | ||
|
|
88646093ca | ||
|
|
0a0427afbb | ||
|
|
88048cdcd7 | ||
|
|
c878ff8775 | ||
|
|
a4049a3f1b | ||
|
|
8a75cc5051 | ||
|
|
b674c5fcaa | ||
|
|
a6d3df7ac9 | ||
|
|
365484ef18 | ||
|
|
5e2bd35239 | ||
|
|
6655e04ef0 | ||
|
|
40c6b840f8 | ||
|
|
5d6e0677d9 | ||
|
|
56071599e7 | ||
|
|
c637447d5d | ||
|
|
ac2cefdd87 | ||
|
|
0774f5eb9d | ||
|
|
76d8862900 | ||
|
|
1dafc1c762 | ||
|
|
63d15ac8c9 | ||
|
|
1f579deaff | ||
|
|
fad48326f8 | ||
|
|
e7d6ddf593 | ||
|
|
953f79c0d9 | ||
|
|
3c5e1caa7c | ||
|
|
d4028fff10 | ||
|
|
dd892d61d8 | ||
|
|
a09f2d4115 | ||
|
|
dafef5a953 | ||
|
|
929e2a4490 | ||
|
|
cc1129093d | ||
|
|
72911ada2d | ||
|
|
037bc7abb3 | ||
|
|
5fd636ac4b | ||
|
|
a6d844a9a5 | ||
|
|
bee62076c6 | ||
|
|
cd072d5e6a | ||
|
|
6ef3ee1391 | ||
|
|
c29b616f93 | ||
|
|
39c179aa32 | ||
|
|
5c1ae4ce22 | ||
|
|
efbfeca292 | ||
|
|
7dd34f1572 | ||
|
|
748e7dd4c7 | ||
|
|
d049ffc0f0 | ||
|
|
8c0275480c | ||
|
|
76d6ef8695 | ||
|
|
c67a696a87 | ||
|
|
ee20d9010e | ||
|
|
2bc12447e2 | ||
|
|
cb61da8842 | ||
|
|
122ba6eba5 | ||
|
|
dddff0f450 | ||
|
|
a919f922a1 | ||
|
|
8f20620c16 | ||
|
|
96bce05be2 | ||
|
|
fc2bf3d11d | ||
|
|
8415ce3ed0 | ||
|
|
ebb5aab6db | ||
|
|
464a3a4892 | ||
|
|
88e1cc7302 | ||
|
|
b3c0db218d | ||
|
|
76446e6d00 | ||
|
|
6623b1dc45 | ||
|
|
70bbb098d3 | ||
|
|
1926065377 | ||
|
|
e3d355d976 | ||
|
|
a679e02246 | ||
|
|
592e9b3725 | ||
|
|
effc58241d | ||
|
|
3697065afc | ||
|
|
fa0fa4d5ac | ||
|
|
5acc48fa54 | ||
|
|
1487eebe79 | ||
|
|
993c034039 | ||
|
|
09f16bda4a | ||
|
|
41d544a4eb | ||
|
|
f28b4abafc | ||
|
|
ca1c934629 | ||
|
|
d5a00cf634 | ||
|
|
fb39c3a70e | ||
|
|
15ec6efc28 | ||
|
|
93d83e17dc | ||
|
|
df16e64fc6 | ||
|
|
a4ebb87858 | ||
|
|
5ef8e0a1f6 | ||
|
|
eb4952c188 | ||
|
|
57b734a7df | ||
|
|
5be1c0da62 | ||
|
|
b598911e96 | ||
|
|
cab9cb06a3 | ||
|
|
62bea23c49 | ||
|
|
7ce5cf1595 | ||
|
|
7e3fc1db03 | ||
|
|
77279984a5 | ||
|
|
669a392fcd | ||
|
|
51ce0b038a | ||
|
|
bd244e6865 | ||
|
|
a70ecba06f | ||
|
|
9d2d5cfcfe | ||
|
|
18f3c8ff9a | ||
|
|
895ec5564d | ||
|
|
7bb6f71f0b | ||
|
|
10e3f1a02b | ||
|
|
2a9d52871b | ||
|
|
c4fb5591ee | ||
|
|
c0ce1da4c3 | ||
|
|
aa27e714d4 | ||
|
|
6874f694e5 | ||
|
|
3690546795 | ||
|
|
7bc42d468b | ||
|
|
097999cad3 | ||
|
|
f82edaa7ec | ||
|
|
d8e8b796e7 | ||
|
|
900fd8cabc | ||
|
|
c20ac35074 | ||
|
|
255b8bf9ba | ||
|
|
ad6f17cd93 | ||
|
|
063a22ddf9 | ||
|
|
1d9cc01ae1 | ||
|
|
f31deb5010 | ||
|
|
0956d300c4 | ||
|
|
4ef490f3cb | ||
|
|
8f2a894b88 | ||
|
|
0e40543757 | ||
|
|
ce58f6d6be | ||
|
|
5aabb915ec | ||
|
|
0d9de01f9d | ||
|
|
f5b0eae9cd | ||
|
|
e6552064bf | ||
|
|
861cb552c4 | ||
|
|
417cceb0de | ||
|
|
165bd8cb71 | ||
|
|
e54e02dc77 | ||
|
|
2bf3b08d76 | ||
|
|
21b58b08b8 | ||
|
|
af530859f0 | ||
|
|
58739b0bf2 | ||
|
|
3e4c2fe712 | ||
|
|
bdfce25db0 | ||
|
|
2b6d9cd1e0 | ||
|
|
bf789dd7b3 | ||
|
|
9b6f01047c | ||
|
|
3fe2fa43bb | ||
|
|
ede982b50a | ||
|
|
319d775c13 | ||
|
|
44124319a6 | ||
|
|
462fd7539c | ||
|
|
f16e34b804 | ||
|
|
c3ccdc548e | ||
|
|
fd721ca480 | ||
|
|
eac365aef0 | ||
|
|
4de6266442 | ||
|
|
213d985e17 | ||
|
|
de76dcb8fb | ||
|
|
30fb6bde5e | ||
|
|
4f842a1248 | ||
|
|
cc4d455b8a | ||
|
|
0bb5efebfd | ||
|
|
b6bf7ae620 | ||
|
|
dc96cc6d1e | ||
|
|
642daf1a76 | ||
|
|
84edfb3d88 | ||
|
|
7e620bff81 | ||
|
|
0c55703438 | ||
|
|
6c57ad2226 | ||
|
|
9028fb5391 | ||
|
|
12dc49b60a | ||
|
|
7e1d20acdf | ||
|
|
5230104852 | ||
|
|
55be77be69 | ||
|
|
42b3a17356 | ||
|
|
4e1d79081c | ||
|
|
4ce4fdec71 | ||
|
|
05256946ac | ||
|
|
73396166aa | ||
|
|
4c5d5c7085 | ||
|
|
045a9e8b93 | ||
|
|
4419f0d54f | ||
|
|
b07aa00d5c | ||
|
|
e4f5df1306 | ||
|
|
dc62d60e9b | ||
|
|
71d8aeb4c2 | ||
|
|
0836f67d42 | ||
|
|
176a57a1e9 | ||
|
|
0d02355dbf | ||
|
|
6767d11c23 | ||
|
|
2dd9015dc6 | ||
|
|
217c10ddac | ||
|
|
822e4e7c44 | ||
|
|
0b1d01792d | ||
|
|
01637768cf | ||
|
|
6a8ae643d5 | ||
|
|
fd83d46ba0 | ||
|
|
914856342c | ||
|
|
91889fc14a | ||
|
|
7c8ec5a5ed | ||
|
|
effc6788eb | ||
|
|
f9daf27511 | ||
|
|
06f7387466 | ||
|
|
21e50eeff1 | ||
|
|
fd4cec93cd | ||
|
|
92f2055a6c | ||
|
|
be9b1198e9 | ||
|
|
56bea083f9 | ||
|
|
fdfc02ab96 | ||
|
|
fc7f042ad6 | ||
|
|
761c775043 | ||
|
|
b421c983d6 | ||
|
|
3036b58598 | ||
|
|
2eca43cd2d | ||
|
|
c24694233f | ||
|
|
423a7c4899 | ||
|
|
ee9e45b3d4 | ||
|
|
5a65188ca9 | ||
|
|
930080f556 | ||
|
|
8e7afb0ab3 | ||
|
|
138523570e | ||
|
|
82469ac0fd | ||
|
|
96cb5e10ed | ||
|
|
b224cab3e0 | ||
|
|
7381d7b92f | ||
|
|
dbef51ba05 | ||
|
|
c952dd8a6e | ||
|
|
b65ea64a58 | ||
|
|
542b5d18f1 | ||
|
|
71a0a42cfb | ||
|
|
ac011fe69f | ||
|
|
9e3d7a50e6 | ||
|
|
e33c2ad6a2 | ||
|
|
615f1072d9 | ||
|
|
f7b7a97407 | ||
|
|
ece6853e0f | ||
|
|
b7b03ee451 | ||
|
|
f9b48c0cad | ||
|
|
aa76603da9 | ||
|
|
b83b9825f8 | ||
|
|
d641972cde | ||
|
|
4d1333e124 | ||
|
|
35396e6410 | ||
|
|
8d18b39eee | ||
|
|
ae77893021 | ||
|
|
baeb180acd | ||
|
|
fd02ffb7bd | ||
|
|
62ecdce0b0 | ||
|
|
e4f2fad215 | ||
|
|
3f5f9bcaf0 | ||
|
|
08867b3cec | ||
|
|
9081feab51 | ||
|
|
cf992164f7 | ||
|
|
b27b821e7f | ||
|
|
d9ecaabac1 | ||
|
|
cd747d8175 | ||
|
|
df75fd2ec2 | ||
|
|
adcaf4cd46 | ||
|
|
81a77a9b88 | ||
|
|
6e805cd318 | ||
|
|
e11f25024e | ||
|
|
7c895f8a1b | ||
|
|
38bda7e1bb | ||
|
|
149db9a022 | ||
|
|
fed252bc49 | ||
|
|
61b2fd9816 | ||
|
|
5ad7a93750 | ||
|
|
2ec10012b6 | ||
|
|
e56c6cc291 | ||
|
|
4c9a929a14 | ||
|
|
71f8871702 | ||
|
|
6dc4ce6599 | ||
|
|
3a44cc7722 | ||
|
|
4cfed3c98f | ||
|
|
6af57ff026 | ||
|
|
2e3db9d56a | ||
|
|
f8d9fa87ed | ||
|
|
f53ad359a6 | ||
|
|
84de86beb5 | ||
|
|
04e7af2675 | ||
|
|
4f13a336b9 | ||
|
|
03508119e5 | ||
|
|
03e20138d3 | ||
|
|
dfcba36448 | ||
|
|
8e4a9a5c21 | ||
|
|
a1286e6f0e | ||
|
|
c0808246e5 | ||
|
|
ba051e10fb | ||
|
|
9fee0603b1 | ||
|
|
be8ebe6db9 | ||
|
|
548e3dc31c | ||
|
|
9440086d77 | ||
|
|
ec5a1bc71f | ||
|
|
9742fa731c | ||
|
|
91a3c538d9 | ||
|
|
e98485da3f | ||
|
|
6528a955fe | ||
|
|
431f77127e | ||
|
|
2cc58723cb | ||
|
|
268219d74e | ||
|
|
d09ed3e52e | ||
|
|
421d1f5490 | ||
|
|
66784b7122 | ||
|
|
54f2d99ce7 | ||
|
|
557c799ec9 | ||
|
|
d22a667095 | ||
|
|
30085a5342 | ||
|
|
304e6c4279 | ||
|
|
12458aae6f | ||
|
|
7e5d9683b1 | ||
|
|
210a4a957a | ||
|
|
131ad9b315 | ||
|
|
06b4cf57ab | ||
|
|
dbefdc923a | ||
|
|
37e45de9c1 | ||
|
|
5e63527190 | ||
|
|
0cc9026978 | ||
|
|
bb6a5441ed | ||
|
|
0ffda1bf29 | ||
|
|
56b5f77dc8 | ||
|
|
6eb284f99e | ||
|
|
34c2288fd0 | ||
|
|
304bb9f902 | ||
|
|
14be01880d | ||
|
|
12b7cf3cd4 | ||
|
|
0d7914bff7 | ||
|
|
d2285953d7 | ||
|
|
d2801505c3 | ||
|
|
9d62b4b9bb | ||
|
|
b65b723fa6 | ||
|
|
e05321356b | ||
|
|
0778959e98 | ||
|
|
76331d1c4a | ||
|
|
9e378ec5cf | ||
|
|
f57d33b17a | ||
|
|
c389e8dccb | ||
|
|
90c64a94d1 | ||
|
|
df27af6d1c | ||
|
|
c85b48f23e | ||
|
|
5a9f2b7750 | ||
|
|
fcfecc6e82 | ||
|
|
f863a927c1 | ||
|
|
cb4fbdfcd5 | ||
|
|
c6eacde55e | ||
|
|
daf780c7e6 | ||
|
|
613305d234 | ||
|
|
656432301d | ||
|
|
38a80f2816 | ||
|
|
6563133426 | ||
|
|
762474d3ac | ||
|
|
b1adbcc77c | ||
|
|
dda052da20 | ||
|
|
2d6bdbc1b1 | ||
|
|
0600856167 | ||
|
|
ce47b57b03 | ||
|
|
f3c916ab96 | ||
|
|
ca6fa6d1d7 | ||
|
|
fcd37b52b6 | ||
|
|
8c0adb63a1 | ||
|
|
f5b0c701a6 | ||
|
|
874bd92604 | ||
|
|
69a8c62863 | ||
|
|
5481af5093 | ||
|
|
6355d0598b | ||
|
|
1145d10996 | ||
|
|
32231e3f7e | ||
|
|
29314f76f7 | ||
|
|
8e92383fa3 | ||
|
|
e51701acaa | ||
|
|
0793e9effe | ||
|
|
c25b0be085 | ||
|
|
1f2f797cb9 | ||
|
|
aca00e4fce | ||
|
|
cf80293d9b | ||
|
|
6d53753c66 | ||
|
|
79f293c3d7 | ||
|
|
8c765883fb | ||
|
|
83aa456d05 | ||
|
|
819c36943e | ||
|
|
8b60efa149 | ||
|
|
240fca0861 | ||
|
|
f996186fae | ||
|
|
69a41d8ef9 | ||
|
|
b958820bce | ||
|
|
7624bd524c | ||
|
|
663f0ca3b0 | ||
|
|
f88d9e728d | ||
|
|
71fa62c9d1 | ||
|
|
5c6069dbe9 | ||
|
|
d517d2d6b4 | ||
|
|
80218fa109 | ||
|
|
fee8a58b77 | ||
|
|
fd52a6f046 | ||
|
|
89fb372326 | ||
|
|
a828f82414 | ||
|
|
4d0d6664d7 | ||
|
|
5c24de3dc4 | ||
|
|
363458c3bc | ||
|
|
b299f6fb3b | ||
|
|
645473e336 | ||
|
|
bdf397bba7 | ||
|
|
781a65ee49 | ||
|
|
c135e2c6a0 | ||
|
|
12693081c9 | ||
|
|
7c22954fd5 | ||
|
|
8958e352df | ||
|
|
573003113b | ||
|
|
8b1351fc3e | ||
|
|
106ef895ee | ||
|
|
7f9bd12f76 | ||
|
|
5fe3a0adb6 | ||
|
|
cdb4c5f553 | ||
|
|
57639f3765 | ||
|
|
9bec983923 | ||
|
|
2220f19fa7 | ||
|
|
2a734ecba2 | ||
|
|
d21015e34a | ||
|
|
023a3c037f | ||
|
|
828edb7403 | ||
|
|
a034ce0478 | ||
|
|
d6cd5823e3 | ||
|
|
5dd941b311 | ||
|
|
f9f27d6f5a | ||
|
|
5ea8490e2b | ||
|
|
5863cd10b8 | ||
|
|
40f8e33e6c | ||
|
|
0157ba63d3 | ||
|
|
9e3d8b22cb | ||
|
|
665412c073 | ||
|
|
2b0c34ecb5 | ||
|
|
b0ec8468e6 | ||
|
|
e82ad21704 | ||
|
|
e098bf47ba | ||
|
|
190678107b | ||
|
|
9f82fa4cf7 | ||
|
|
562835308b | ||
|
|
927c65e863 | ||
|
|
5b6c1569a4 | ||
|
|
65121e6d5d | ||
|
|
82e0e4ffaf | ||
|
|
ffb199a26a | ||
|
|
175933d2b1 | ||
|
|
c86e6fef0a | ||
|
|
1e3ce2a36f | ||
|
|
153915dc2f | ||
|
|
ced38bc6ee | ||
|
|
4e96cf9875 | ||
|
|
80170eb6eb | ||
|
|
bdad1499fe | ||
|
|
1f5ca39559 | ||
|
|
5013b64f55 | ||
|
|
7eb73d766e | ||
|
|
bcfeb49d6b | ||
|
|
702d9e0542 | ||
|
|
c0aff678e9 | ||
|
|
a3d8836671 | ||
|
|
db1eb8fbcb | ||
|
|
95f347dc6a | ||
|
|
6579120d9e | ||
|
|
84cd9f2db9 | ||
|
|
06fe27c516 | ||
|
|
5039af6af1 | ||
|
|
4df74d44ec | ||
|
|
9113647d41 | ||
|
|
26af2bff5e | ||
|
|
3c304f3acf | ||
|
|
e308130e23 | ||
|
|
713eef9ef2 | ||
|
|
7635a2fc74 | ||
|
|
6889334521 | ||
|
|
d1e82e50cb | ||
|
|
7955447ca4 | ||
|
|
51e225cd75 | ||
|
|
187f88aa50 | ||
|
|
caddd61f17 | ||
|
|
29629245a4 | ||
|
|
666b9f8f7b | ||
|
|
7deb8d3e8a | ||
|
|
cb0a882a31 | ||
|
|
df2c0dc2f9 | ||
|
|
062fa5392b | ||
|
|
baeec2315f | ||
|
|
92134d7684 | ||
|
|
4877bb783c | ||
|
|
275b8e15ff | ||
|
|
e123b6dec7 | ||
|
|
cb52ae0f26 | ||
|
|
46a402f7d7 | ||
|
|
e233c5d256 | ||
|
|
fe824e0068 | ||
|
|
66512ed8d2 | ||
|
|
fb58166e5d | ||
|
|
0759c98d91 | ||
|
|
402ffbf0c5 | ||
|
|
8191e5eb27 | ||
|
|
03967bd623 | ||
|
|
eb445271df | ||
|
|
af22cf182b | ||
|
|
5a0fcda4c8 | ||
|
|
29623c4146 | ||
|
|
ebda8255ff | ||
|
|
deb91f679d | ||
|
|
fb5e768142 | ||
|
|
ecf44c784c | ||
|
|
5bca1172ff | ||
|
|
136446fccb | ||
|
|
49bca8d588 | ||
|
|
7ddbe44b21 | ||
|
|
af60e7f74a | ||
|
|
2f16e82cf7 | ||
|
|
7b54312d97 | ||
|
|
5b98beec8b | ||
|
|
6662c86d5e | ||
|
|
2f466c2939 | ||
|
|
61897d8b52 | ||
|
|
a259f53b52 | ||
|
|
ffdb1fbfe5 | ||
|
|
4b33b4b387 | ||
|
|
8fcdcb1731 | ||
|
|
55b911654c | ||
|
|
7c8eba9fd2 | ||
|
|
23effcc3f0 | ||
|
|
ea0c5581a5 | ||
|
|
2ea329c920 | ||
|
|
3948795d49 | ||
|
|
13e4920122 | ||
|
|
88b1121037 | ||
|
|
d2a97e934b | ||
|
|
cb3997d8c9 | ||
|
|
c7320a49a9 | ||
|
|
8d9a896166 | ||
|
|
81a057416f | ||
|
|
361326e06c | ||
|
|
0d31afaff8 | ||
|
|
48ad3973a9 | ||
|
|
f6f25296a0 | ||
|
|
cb62076f8c | ||
|
|
8034e567f1 | ||
|
|
59546c8980 | ||
|
|
eee0e6adc8 | ||
|
|
fa10ee4356 | ||
|
|
5bc8d51a9e | ||
|
|
361d6cf517 | ||
|
|
6800609fa7 | ||
|
|
dac13ba4bb | ||
|
|
702075eba6 | ||
|
|
3b62bd0bce | ||
|
|
4cc24f4369 | ||
|
|
cfe21876e5 | ||
|
|
ef2bfe4ea0 | ||
|
|
14731c0a1d | ||
|
|
93747af215 | ||
|
|
76efd26da0 | ||
|
|
cf2001de5f | ||
|
|
6d00877231 | ||
|
|
6755a0912b | ||
|
|
b6ac23be3d | ||
|
|
e941cafedb | ||
|
|
03fe077b41 | ||
|
|
12ef879860 | ||
|
|
179e047474 | ||
|
|
d497190aa1 | ||
|
|
e078c1e793 | ||
|
|
7471f46a07 | ||
|
|
8cee3c3c3e | ||
|
|
97bcbf5d84 | ||
|
|
3fce9ed9a4 | ||
|
|
21ffcc74db | ||
|
|
9e99db9a8e | ||
|
|
5fd38c5f67 | ||
|
|
03ed914714 | ||
|
|
42faffe6f3 | ||
|
|
bc80e910ed | ||
|
|
30a95d735a | ||
|
|
f01a227470 | ||
|
|
91b65c9380 | ||
|
|
18c47843f1 | ||
|
|
d5fe377c11 | ||
|
|
ed4a613473 | ||
|
|
112098514d | ||
|
|
31aa1ea474 | ||
|
|
96b6e4a76e | ||
|
|
001b95d12a | ||
|
|
3b2c862320 | ||
|
|
230f849229 | ||
|
|
c37253fe5a | ||
|
|
0ed8d3859d | ||
|
|
6963d77f8a | ||
|
|
02ea52f453 | ||
|
|
cdabc057a0 | ||
|
|
eb0d75711a | ||
|
|
f121119283 | ||
|
|
d9c1b66931 | ||
|
|
2f60e0a59e | ||
|
|
ffe9e92b48 | ||
|
|
aa90a53f34 | ||
|
|
598c923506 | ||
|
|
8c4b473d6f | ||
|
|
a4fe274c25 | ||
|
|
34597ce6a0 | ||
|
|
4a2af807b2 | ||
|
|
d0ec35628f | ||
|
|
bfdbd00092 | ||
|
|
d0278d8663 | ||
|
|
632bc2aaec | ||
|
|
1ca59f25d0 | ||
|
|
1d0c8fa113 | ||
|
|
1d70c989be | ||
|
|
818a0d0296 | ||
|
|
ab1eb146c9 | ||
|
|
63054ae0fd | ||
|
|
155040240d | ||
|
|
d466cab1e8 | ||
|
|
4e8b34f42e | ||
|
|
5014f55c48 | ||
|
|
1d78cd0f03 | ||
|
|
52d62c6b21 | ||
|
|
b4a73f33ce | ||
|
|
f9c25608e9 | ||
|
|
9fb9e63554 | ||
|
|
9ce8a9f5f0 | ||
|
|
cc59730c5b | ||
|
|
0a04904b75 | ||
|
|
9ed6e9af65 | ||
|
|
c424a9bf5a | ||
|
|
9d811e1267 | ||
|
|
af6f62701c | ||
|
|
299574221e | ||
|
|
fe0c269382 | ||
|
|
579a324ce7 | ||
|
|
7903c14993 | ||
|
|
b42a04c24e | ||
|
|
ea52e45335 | ||
|
|
9687e6e1dd | ||
|
|
ee34200e5f | ||
|
|
295fc6c619 | ||
|
|
28473d314a | ||
|
|
35f7340dc9 | ||
|
|
b76567e7d1 | ||
|
|
652db60ad6 | ||
|
|
a7cb0a166a | ||
|
|
f363541611 | ||
|
|
fa1fba7fd9 | ||
|
|
d73fa09774 | ||
|
|
b1cd730db2 | ||
|
|
359a048b6e | ||
|
|
f2be601a13 | ||
|
|
4d2379b3df | ||
|
|
fd32b2252f | ||
|
|
d15915ef14 | ||
|
|
877e0e0b91 | ||
|
|
da1d9f68c7 | ||
|
|
24f41ef897 | ||
|
|
09dff85d5b | ||
|
|
20e5685c1a | ||
|
|
ac6232bc87 | ||
|
|
b16ec83a33 | ||
|
|
ed72baca2a | ||
|
|
edb562d2e5 | ||
|
|
6d4b128611 | ||
|
|
e2e01e84fa | ||
|
|
93ee417567 | ||
|
|
44cdcd12c3 | ||
|
|
ed06981f57 | ||
|
|
ec6c42e9d6 | ||
|
|
b11d121c48 | ||
|
|
cdf6000618 | ||
|
|
2e8094b712 | ||
|
|
a9cb4f8245 | ||
|
|
1bd41bf79a | ||
|
|
08ab34cf57 | ||
|
|
7bb55469fe | ||
|
|
a29dd738f2 | ||
|
|
4a98b41d57 | ||
|
|
6fc5097278 | ||
|
|
12f2f654dd | ||
|
|
0649b360fb | ||
|
|
f1f314270d | ||
|
|
1fb9f90f0f | ||
|
|
bfa8da78a6 | ||
|
|
fb81733b2b | ||
|
|
e7eac583da | ||
|
|
cd107855e7 | ||
|
|
ab9307ac61 | ||
|
|
e3ef194b4f | ||
|
|
ab4ca9ad8c | ||
|
|
3fb5648880 | ||
|
|
a7c0616cd8 | ||
|
|
51d5ff0567 | ||
|
|
0665146dcd | ||
|
|
1f8422575e | ||
|
|
61c381a62c | ||
|
|
56d5f1588a | ||
|
|
c05334dfc1 | ||
|
|
09d6c7a54f | ||
|
|
4fe44447a2 | ||
|
|
23c600eef5 | ||
|
|
50f091ab7c | ||
|
|
7437f7eb85 | ||
|
|
d6a99981d6 | ||
|
|
71fe652556 | ||
|
|
89917ef688 | ||
|
|
097e4c9799 | ||
|
|
2c37a1e971 | ||
|
|
2c52364978 | ||
|
|
10140f74dc | ||
|
|
558e8f46ff | ||
|
|
9ccb71205a | ||
|
|
e50bcaa272 | ||
|
|
86a28e8201 | ||
|
|
95cd0c6e53 | ||
|
|
23ab245cec | ||
|
|
eb82476591 | ||
|
|
f1f70d250a | ||
|
|
98a221d6b6 | ||
|
|
fb22d12b0f | ||
|
|
83249ed69f | ||
|
|
1534df0b3c | ||
|
|
ece9177f5a | ||
|
|
8a90d74340 | ||
|
|
5a06fad31e | ||
|
|
add07259f4 | ||
|
|
36ca18bc7b | ||
|
|
6003be3fae | ||
|
|
6d9399e3a0 | ||
|
|
676800476d | ||
|
|
4dfa3157e5 | ||
|
|
f26cfa2d94 | ||
|
|
d3328406a2 | ||
|
|
3564b3f9ea | ||
|
|
b81faeccfa | ||
|
|
1c4cb2cd2d | ||
|
|
6959b76749 | ||
|
|
8a1e920e23 | ||
|
|
606519c515 | ||
|
|
34618e0294 | ||
|
|
373762dedc | ||
|
|
b30dfb166b | ||
|
|
36db3257f3 | ||
|
|
cad23465a5 | ||
|
|
d23401316e | ||
|
|
b49e025703 | ||
|
|
e4f4706508 | ||
|
|
02fe73d1f3 | ||
|
|
74f43d4e09 | ||
|
|
54ed050ecf | ||
|
|
f262d3b34b | ||
|
|
32f7860a4e | ||
|
|
b62832e94d | ||
|
|
e5820312d4 | ||
|
|
f710f21ad8 | ||
|
|
90fefb468b | ||
|
|
21f4cafef5 | ||
|
|
b1d4be66e4 | ||
|
|
ef43ae0eea | ||
|
|
9976a139de | ||
|
|
5718354500 | ||
|
|
2d7d9eef9f | ||
|
|
a290e19f46 | ||
|
|
92a2be62fe | ||
|
|
5410dba4f4 | ||
|
|
d93ad2e650 | ||
|
|
68410d35d3 | ||
|
|
ceae4a44f3 | ||
|
|
ea003487aa | ||
|
|
401fd8b56b | ||
|
|
191ee4ba1f | ||
|
|
58556f91f7 | ||
|
|
faa7893761 | ||
|
|
648df0dc7d | ||
|
|
44173dbe8b | ||
|
|
7233f568a7 | ||
|
|
197f1e9b7b | ||
|
|
7063f66b2d | ||
|
|
6e59bcb60e | ||
|
|
0649e6d65f | ||
|
|
072c965ba5 | ||
|
|
122f5fe12e | ||
|
|
a40d599cd7 | ||
|
|
babf36e96e | ||
|
|
d6a43f6a53 | ||
|
|
ff8e38fcc6 | ||
|
|
192f2de704 | ||
|
|
c568b3a976 | ||
|
|
9c818ef3e1 | ||
|
|
5aea30f40d | ||
|
|
09c9395ff8 | ||
|
|
81047afb4b | ||
|
|
f1441cc962 | ||
|
|
50804d661a | ||
|
|
9b895e8a0a | ||
|
|
4600f70fef | ||
|
|
9e33cc998f | ||
|
|
5496c2e76f | ||
|
|
bf75971a3a | ||
|
|
8a59994c0d | ||
|
|
f2e1b7d868 | ||
|
|
8c91b31ae6 | ||
|
|
302b210470 | ||
|
|
5bd0076233 | ||
|
|
0e24adcafd | ||
|
|
696feae32e | ||
|
|
323738e7b8 | ||
|
|
a1d132cd35 | ||
|
|
f7c2665e14 | ||
|
|
ae0b95ec6d | ||
|
|
cdd8200936 | ||
|
|
694075e840 | ||
|
|
d76f994318 | ||
|
|
11b7052f94 | ||
|
|
e93d65d736 | ||
|
|
0f4d543aeb | ||
|
|
dab5f59ed9 | ||
|
|
22a6a82642 | ||
|
|
7b592eff8a | ||
|
|
4be81d9ffd | ||
|
|
55fbecee49 | ||
|
|
f36a3d5b2a | ||
|
|
c5e8e4ff83 | ||
|
|
ccc666c1e4 | ||
|
|
89eda89838 | ||
|
|
17b9838c8f | ||
|
|
889dd83798 | ||
|
|
38a372f25f | ||
|
|
2e6f5ac679 | ||
|
|
7a45fc68d9 | ||
|
|
1288737c0d | ||
|
|
5902306271 | ||
|
|
2fe4521a96 | ||
|
|
74673436a1 | ||
|
|
481748c279 | ||
|
|
9faa5c7a9e | ||
|
|
6fbb25c0da | ||
|
|
65fc42cce5 | ||
|
|
736b7727b6 | ||
|
|
fa920f8449 | ||
|
|
01aa56606f | ||
|
|
bddd5bc678 | ||
|
|
f6b7e39ce7 | ||
|
|
1363dd8f34 | ||
|
|
8214f0c09d | ||
|
|
ff7c46f5a6 | ||
|
|
b44f5825a5 | ||
|
|
631910bd67 | ||
|
|
37089ef940 | ||
|
|
4ef27a0d23 | ||
|
|
476ccc9f6b | ||
|
|
89dc14fcaf | ||
|
|
1ca2f12d24 | ||
|
|
20b2f5ee2f | ||
|
|
3cc67c48cf | ||
|
|
f9a04696f2 | ||
|
|
e0e8170fe6 | ||
|
|
9b40663d54 | ||
|
|
a517f900e4 | ||
|
|
350f40300c | ||
|
|
d3db5f0d76 | ||
|
|
7e3af4b3cd | ||
|
|
dfb3072381 | ||
|
|
02191135a0 | ||
|
|
dc2c97fe0c | ||
|
|
6068b565f5 | ||
|
|
a21cef7190 | ||
|
|
461ef6cea5 | ||
|
|
e05199ca1e | ||
|
|
12d82eb768 | ||
|
|
05becf3f4b | ||
|
|
3cc7981c82 | ||
|
|
8f287eeef9 | ||
|
|
ce05cb5683 | ||
|
|
17945a7377 | ||
|
|
3a1b47129e | ||
|
|
6ffa751090 | ||
|
|
c3641321d7 | ||
|
|
446173f0cb | ||
|
|
e27f381842 | ||
|
|
a3ee76dddd | ||
|
|
995265c549 | ||
|
|
03629b74d9 | ||
|
|
b069278e98 | ||
|
|
9738c88f95 | ||
|
|
a21ea30be0 | ||
|
|
64752da42d | ||
|
|
e3e18063c6 | ||
|
|
e400eac42b | ||
|
|
a6bf77718c | ||
|
|
c2787a9ea9 | ||
|
|
e33e6e2413 | ||
|
|
3cb56c5a2e | ||
|
|
91984cb7e7 | ||
|
|
b8d5dd1824 | ||
|
|
88b66f2941 | ||
|
|
3c7e59b9e1 | ||
|
|
c4471e3300 | ||
|
|
16111f46ef | ||
|
|
b019b03946 | ||
|
|
605acd24ba | ||
|
|
c8630eee95 | ||
|
|
4040555532 | ||
|
|
defb221c98 | ||
|
|
e7dc094e56 | ||
|
|
dfdb107105 | ||
|
|
9f598dfdb7 | ||
|
|
38110a833d | ||
|
|
484d15dbb2 | ||
|
|
1decf5d0d4 | ||
|
|
74e9de1b71 | ||
|
|
015d2b0830 | ||
|
|
c75a9539ba | ||
|
|
ca6149abcf | ||
|
|
b3120aea25 | ||
|
|
54e5bf0f0c | ||
|
|
847cae5b95 | ||
|
|
df15c97b6e | ||
|
|
0d97b58265 | ||
|
|
f7bc61e874 | ||
|
|
8d5a53f529 | ||
|
|
20f9492899 | ||
|
|
3cd1d46a1b | ||
|
|
88eceec257 | ||
|
|
d00ec024a2 | ||
|
|
0bcd53778a | ||
|
|
7592eaf42b | ||
|
|
12ed9e044a | ||
|
|
0a3af87aee | ||
|
|
4dee999f68 | ||
|
|
9a4941c794 | ||
|
|
2d0fd71159 | ||
|
|
327582be31 | ||
|
|
21aea281bd | ||
|
|
975f85260d | ||
|
|
f29d768989 | ||
|
|
9bd7ecad4c | ||
|
|
cc458a9693 | ||
|
|
d2bd9a2368 | ||
|
|
b909a5063a | ||
|
|
b2c1f6122e | ||
|
|
a761e98e18 | ||
|
|
e12e7b2acc | ||
|
|
f927c41abb | ||
|
|
249acace08 | ||
|
|
fa37922ca7 | ||
|
|
021990b8e0 | ||
|
|
540564694c | ||
|
|
8da4feb83c | ||
|
|
23f5e9dacc | ||
|
|
6ff9435e0a | ||
|
|
40006c6152 | ||
|
|
b256e4c2e3 | ||
|
|
a37a09c09c | ||
|
|
8ece231d8b | ||
|
|
e7de0745ad | ||
|
|
7af2d5dfe1 | ||
|
|
2f2f14bf80 | ||
|
|
c59cb6a828 | ||
|
|
06aaf5b571 | ||
|
|
65d7909466 | ||
|
|
861192c332 | ||
|
|
c63af05427 | ||
|
|
d07ba6971b | ||
|
|
4b40d63dfd | ||
|
|
a99b7f6902 | ||
|
|
b3391f699f | ||
|
|
5a3c12cc6b | ||
|
|
a05fd9b818 | ||
|
|
6c1ec59a5b | ||
|
|
e25a4b0abc | ||
|
|
a060f135b8 | ||
|
|
f5d3087e9b | ||
|
|
2795404cd7 | ||
|
|
16fac50db4 | ||
|
|
3806eb3139 | ||
|
|
bad66e54fa | ||
|
|
5cb6c4af4b | ||
|
|
69f79f8598 | ||
|
|
573011a99e | ||
|
|
d778b8e71c | ||
|
|
432a7574c9 | ||
|
|
4d2598e7bf | ||
|
|
2e565bcb4e | ||
|
|
62ecb6da0b | ||
|
|
46fcebe2b5 | ||
|
|
ab1901eeac | ||
|
|
29d2fc6ebc | ||
|
|
efe4599bd8 | ||
|
|
4fc1e41b16 | ||
|
|
e771d60ec0 | ||
|
|
e2de106d71 | ||
|
|
adea89f3eb | ||
|
|
361015497c | ||
|
|
5e9c433a24 | ||
|
|
587159448a | ||
|
|
64158cf513 | ||
|
|
a567365d7c | ||
|
|
57bf220e40 | ||
|
|
e6e3cc474d | ||
|
|
33c984e456 | ||
|
|
458f79f44f | ||
|
|
34e04b0327 | ||
|
|
cf7bb9e99f | ||
|
|
1af5343e29 | ||
|
|
a5e3a7cbc9 | ||
|
|
df065dbbcb | ||
|
|
fac7247483 | ||
|
|
60050af186 | ||
|
|
11c47570ce | ||
|
|
f8b4cc52f6 |
+24
-2
@@ -19,12 +19,18 @@
|
|||||||
# Don't expect SPDX tag in the first line of a file
|
# Don't expect SPDX tag in the first line of a file
|
||||||
--ignore SPDX_LICENSE_TAG
|
--ignore SPDX_LICENSE_TAG
|
||||||
|
|
||||||
|
# Don't expect Signed-off-by lines in commit messages
|
||||||
|
--no-signoff
|
||||||
|
|
||||||
# List of ignored rules
|
# List of ignored rules
|
||||||
# ---------------------
|
# ---------------------
|
||||||
|
|
||||||
# There's no BIT macro
|
# There's no BIT macro
|
||||||
--ignore BIT_MACRO
|
--ignore BIT_MACRO
|
||||||
|
|
||||||
|
# Don't complain when bools are used in structs
|
||||||
|
--ignore BOOL_MEMBER
|
||||||
|
|
||||||
# Allow CamelCase
|
# Allow CamelCase
|
||||||
--ignore CAMELCASE
|
--ignore CAMELCASE
|
||||||
|
|
||||||
@@ -37,9 +43,19 @@
|
|||||||
# Don't complain about structs not being const
|
# Don't complain about structs not being const
|
||||||
--ignore CONST_STRUCT
|
--ignore CONST_STRUCT
|
||||||
|
|
||||||
|
# Don't complain about printing "warning:" without the function name, as warning
|
||||||
|
# printing is relevant to the code being parsed, not RGBDS' code
|
||||||
|
--ignore EMBEDDED_FUNCTION_NAME
|
||||||
|
|
||||||
# Do not check the format of commit messages
|
# Do not check the format of commit messages
|
||||||
--ignore GIT_COMMIT_ID
|
--ignore GIT_COMMIT_ID
|
||||||
|
|
||||||
|
# Do not check for global initializers (this is specific to the kernel)
|
||||||
|
--ignore GLOBAL_INITIALISERS
|
||||||
|
|
||||||
|
# Don't complain about initializing statics (this is specific to the kernel)
|
||||||
|
--ignore INITIALISED_STATIC
|
||||||
|
|
||||||
# We don't have a MAINTAINERS file, don't complain about it.
|
# We don't have a MAINTAINERS file, don't complain about it.
|
||||||
--ignore FILE_PATH_CHANGES
|
--ignore FILE_PATH_CHANGES
|
||||||
|
|
||||||
@@ -50,9 +66,15 @@
|
|||||||
# have a really long line that can be found with grep.
|
# have a really long line that can be found with grep.
|
||||||
--ignore LONG_LINE_STRING
|
--ignore LONG_LINE_STRING
|
||||||
|
|
||||||
|
# Don't complain when files are modified in 'include/asm'
|
||||||
|
--ignore MODIFIED_INCLUDE_ASM
|
||||||
|
|
||||||
# Allow new typedefs
|
# Allow new typedefs
|
||||||
--ignore NEW_TYPEDEFS
|
--ignore NEW_TYPEDEFS
|
||||||
|
|
||||||
|
# We allow lines ending with parentheses for the usage prints
|
||||||
|
--ignore OPEN_ENDED_LINE
|
||||||
|
|
||||||
# Prefer stdint.h types over kernel types
|
# Prefer stdint.h types over kernel types
|
||||||
--ignore PREFER_KERNEL_TYPES
|
--ignore PREFER_KERNEL_TYPES
|
||||||
|
|
||||||
@@ -62,5 +84,5 @@
|
|||||||
# Parentheses can make the code clearer
|
# Parentheses can make the code clearer
|
||||||
--ignore UNNECESSARY_PARENTHESES
|
--ignore UNNECESSARY_PARENTHESES
|
||||||
|
|
||||||
# Don't complain when files are modified in 'include/asm'
|
# We don't have `fallthrough;` */
|
||||||
--ignore MODIFIED_INCLUDE_ASM
|
--ignore PREFER_FALLTHROUGH
|
||||||
|
|||||||
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is part of RGBDS.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018-2019, Phil Smith and RGBDS contributors.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
.git
|
||||||
|
docs
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
github: avivace
|
||||||
|
patreon: gbdev01
|
||||||
|
open_collective: gbdev
|
||||||
Executable
+56
@@ -0,0 +1,56 @@
|
|||||||
|
#!/usr/bin/awk -f
|
||||||
|
|
||||||
|
/^\s+<td><b class="Sy">.+<\/b><\/td>$/ {
|
||||||
|
# Assuming that all cells whose contents are bold are heading cells,
|
||||||
|
# use the HTML tag for those
|
||||||
|
sub(/td><b class="Sy"/, "th");
|
||||||
|
sub(/b><\/td/, "th");
|
||||||
|
}
|
||||||
|
|
||||||
|
# The whole page is being generated, so it's not meant to contain any Liquid
|
||||||
|
BEGIN {
|
||||||
|
print "{% raw %}"
|
||||||
|
}
|
||||||
|
END {
|
||||||
|
print "{% endraw %}"
|
||||||
|
}
|
||||||
|
|
||||||
|
BEGIN {
|
||||||
|
in_synopsis = 0
|
||||||
|
}
|
||||||
|
/<table class="Nm">/ {
|
||||||
|
in_synopsis = 1
|
||||||
|
}
|
||||||
|
/<\/table>/ {
|
||||||
|
# Resets synopsis state even when already reset, but whatever
|
||||||
|
in_synopsis = 0
|
||||||
|
}
|
||||||
|
/<code class="Fl">-[a-zA-Z]/ {
|
||||||
|
# Add links to arg descr in synopsis section
|
||||||
|
if (in_synopsis) {
|
||||||
|
while (match($0, /<code class="Fl">-[a-zA-Z]+/)) {
|
||||||
|
# 123456789012345678 -> 18 chars
|
||||||
|
optchars = substr($0, RSTART + 18, RLENGTH - 18)
|
||||||
|
i = length(optchars)
|
||||||
|
while (i) {
|
||||||
|
end = RSTART + 18 + i
|
||||||
|
i -= 1
|
||||||
|
len = i ? 1 : 2
|
||||||
|
$0 = sprintf("%s<a href=\"#%s\">%s</a>%s",
|
||||||
|
substr($0, 0, end - len - 1),
|
||||||
|
substr($0, end - 1, 1),
|
||||||
|
substr($0, end - len, len),
|
||||||
|
substr($0, end))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
# Make long opts (defined using `Fl Fl`) into a single tag
|
||||||
|
gsub(/<code class="Fl">-<\/code>\s*<code class="Fl">/, "<code class=\"Fl\">-")
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
print
|
||||||
|
}
|
||||||
Executable
+113
@@ -0,0 +1,113 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
cat <<EOF
|
||||||
|
Usage: $0 [-h] [-r] <rgbds-www> <version>
|
||||||
|
Copy renders from RGBDS repository to rgbds-www documentation
|
||||||
|
Execute from the root folder of the RGBDS repo, checked out at the desired tag
|
||||||
|
<rgbds-www> : Path to the rgbds-www repository
|
||||||
|
<version> : Version to be copied, such as 'v0.4.1' or 'master'
|
||||||
|
|
||||||
|
-h Display this help message
|
||||||
|
-r Update "latest stable" redirection pages and add a new entry to the index
|
||||||
|
(use for releases, not master)
|
||||||
|
EOF
|
||||||
|
}
|
||||||
|
|
||||||
|
is_release=0
|
||||||
|
bad_usage=0
|
||||||
|
while getopts ":hr" opt; do
|
||||||
|
case $opt in
|
||||||
|
r)
|
||||||
|
is_release=1
|
||||||
|
;;
|
||||||
|
h)
|
||||||
|
usage
|
||||||
|
exit 0
|
||||||
|
;;
|
||||||
|
\?)
|
||||||
|
echo "Unknown option '$OPTARG'"
|
||||||
|
bad_usage=1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
if [ $bad_usage -ne 0 ]; then
|
||||||
|
usage
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
shift $(($OPTIND - 1))
|
||||||
|
|
||||||
|
|
||||||
|
declare -A PAGES
|
||||||
|
PAGES=(
|
||||||
|
[rgbasm.1.html]=src/asm/rgbasm.1
|
||||||
|
[rgbasm.5.html]=src/asm/rgbasm.5
|
||||||
|
[rgblink.1.html]=src/link/rgblink.1
|
||||||
|
[rgblink.5.html]=src/link/rgblink.5
|
||||||
|
[rgbfix.1.html]=src/fix/rgbfix.1
|
||||||
|
[rgbgfx.1.html]=src/gfx/rgbgfx.1
|
||||||
|
[rgbds.5.html]=src/rgbds.5
|
||||||
|
[rgbds.7.html]=src/rgbds.7
|
||||||
|
[gbz80.7.html]=src/gbz80.7
|
||||||
|
)
|
||||||
|
WWWPATH="/docs"
|
||||||
|
mkdir -p "$1/_documentation/$2"
|
||||||
|
|
||||||
|
# `mandoc` uses a different format for referring to man pages present in the **current** directory.
|
||||||
|
# We want that format for RGBDS man pages, and the other one for the rest;
|
||||||
|
# we thus need to copy all pages to a temporary directory, and process them there.
|
||||||
|
|
||||||
|
# Copy all pages to current dir
|
||||||
|
cp "${PAGES[@]}" .
|
||||||
|
|
||||||
|
for page in "${!PAGES[@]}"; do
|
||||||
|
stem="${page%.html}"
|
||||||
|
manpage="${stem%.?}(${stem#*.})"
|
||||||
|
descr="$(awk -v 'FS=.Nd ' '/.Nd/ { print $2; }' "${PAGES[$page]}")"
|
||||||
|
|
||||||
|
cat >"$1/_documentation/$2/$page" <<EOF
|
||||||
|
---
|
||||||
|
layout: doc
|
||||||
|
title: $manpage [$2]
|
||||||
|
description: RGBDS $2 — $descr
|
||||||
|
---
|
||||||
|
EOF
|
||||||
|
options=fragment,man='%N.%S;https://linux.die.net/man/%S/%N'
|
||||||
|
if [ $stem = rgbasm.5 ]; then
|
||||||
|
options+=,toc
|
||||||
|
fi
|
||||||
|
mandoc -Thtml -I os=Linux -O$options "${PAGES[$page]##*/}" | .github/actions/doc_postproc.awk >> "$1/_documentation/$2/$page"
|
||||||
|
groff -Tpdf -mdoc -wall "${PAGES[$page]##*/}" >"$1/_documentation/$2/$stem.pdf"
|
||||||
|
if [ $is_release -ne 0 ]; then
|
||||||
|
cat - >"$1/_documentation/$page" <<EOF
|
||||||
|
---
|
||||||
|
redirect_to: $WWWPATH/$2/${page%.html}
|
||||||
|
permalink: $WWWPATH/${page%.html}/
|
||||||
|
title: $manpage [latest stable]
|
||||||
|
description: RGBDS latest stable — $descr
|
||||||
|
---
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
cat - >"$1/_documentation/$2/index.html" <<EOF
|
||||||
|
---
|
||||||
|
layout: doc_index
|
||||||
|
permalink: /docs/$2/
|
||||||
|
title: RGBDS online manual [$2]
|
||||||
|
description: RGBDS $2 - Online manual
|
||||||
|
---
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
# If making a release, add a new entry right after `master`
|
||||||
|
if [ $is_release -ne 0 ]; then
|
||||||
|
awk '{ print }
|
||||||
|
/"name": "master"/ { print "\t\t{\"name\": \"'$2'\", \"text\": \"'$2'\" }," }
|
||||||
|
' "$1/_data/doc.json" >"$1/_data/doc.json.tmp"
|
||||||
|
mv "$1/_data/doc.json"{.tmp,}
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Clean up
|
||||||
|
rm "${PAGES[@]##*/}"
|
||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
case `echo $1 | cut -d '-' -f 1` in
|
||||||
|
ubuntu)
|
||||||
|
sudo apt-get -qq update
|
||||||
|
sudo apt-get install -yq bison libpng-dev pkg-config
|
||||||
|
;;
|
||||||
|
macos)
|
||||||
|
brew install bison libpng pkg-config md5sha1sum
|
||||||
|
# For the version check below exclusively, re-do this before building
|
||||||
|
export PATH="/usr/local/opt/bison/bin:$PATH"
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "WARNING: Cannot install deps for OS '$1'"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
bison --version
|
||||||
|
make --version
|
||||||
|
cmake --version
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
source mingw-env @TRIPLE@
|
||||||
|
echo LAST IS: $last
|
||||||
|
|
||||||
|
# check if last arg is a path to configure, else use parent
|
||||||
|
for last; do true; done
|
||||||
|
if test -x "${last}/configure"; then
|
||||||
|
config_path="$last"
|
||||||
|
else
|
||||||
|
config_path=".."
|
||||||
|
fi
|
||||||
|
|
||||||
|
${config_path}/configure \
|
||||||
|
--host=@TRIPLE@ --target=@TRIPLE@ --build="$CHOST" \
|
||||||
|
--prefix=/usr/@TRIPLE@ --libdir=/usr/@TRIPLE@/lib --includedir=/usr/@TRIPLE@/include \
|
||||||
|
--enable-shared --enable-static "$@"
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
_arch=$1
|
||||||
|
|
||||||
|
default_mingw_pp_flags="-D_FORTIFY_SOURCE=2"
|
||||||
|
default_mingw_compiler_flags="$default_mingw_pp_flags -O2 -pipe -fno-plt -fexceptions --param=ssp-buffer-size=4"
|
||||||
|
default_mingw_linker_flags="-Wl,-O1,--sort-common,--as-needed -fstack-protector"
|
||||||
|
|
||||||
|
export CPPFLAGS="${MINGW_CPPFLAGS:-$default_mingw_pp_flags $CPPFLAGS}"
|
||||||
|
export CFLAGS="${MINGW_CFLAGS:-$default_mingw_compiler_flags $CFLAGS}"
|
||||||
|
export CXXFLAGS="${MINGW_CXXFLAGS:-$default_mingw_compiler_flags $CXXFLAGS}"
|
||||||
|
export LDFLAGS="${MINGW_LDFLAGS:-$default_mingw_linker_flags $LDFLAGS}"
|
||||||
|
|
||||||
|
mingw_prefix=/usr/${_arch}
|
||||||
|
export PKG_CONFIG_SYSROOT_DIR="${mingw_prefix}"
|
||||||
|
export PKG_CONFIG_LIBDIR="${mingw_prefix}/lib/pkgconfig:${mingw_prefix}/share/pkgconfig"
|
||||||
Executable
+44
@@ -0,0 +1,44 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
# This script was written by ISSOtm while looking at Arch Linux's PKGBUILD for
|
||||||
|
# the corresponding package. (And its dependencies)
|
||||||
|
# https://aur.archlinux.org/packages/mingw-w64-libpng/
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
pngver=1.6.37
|
||||||
|
_apngver=$pngver
|
||||||
|
_arch="$1"
|
||||||
|
|
||||||
|
|
||||||
|
## Install mingw-configure and mingw-env (both build dependencies)
|
||||||
|
|
||||||
|
install -m 755 .github/actions/mingw-env.sh /usr/bin/mingw-env
|
||||||
|
|
||||||
|
sed "s|@TRIPLE@|${_arch}|g" .github/actions/mingw-configure.sh > ${_arch}-configure
|
||||||
|
install -m 755 ${_arch}-configure /usr/bin/
|
||||||
|
|
||||||
|
|
||||||
|
## Grab sources and check them
|
||||||
|
|
||||||
|
wget http://downloads.sourceforge.net/sourceforge/libpng/libpng-$pngver.tar.xz
|
||||||
|
wget http://downloads.sourceforge.net/project/apng/libpng/libpng16/libpng-$_apngver-apng.patch.gz
|
||||||
|
sha256sum -c .github/actions/mingw-w64-libpng-dev.sha256sums
|
||||||
|
|
||||||
|
## Extract sources
|
||||||
|
|
||||||
|
tar -xf libpng-$pngver.tar.xz
|
||||||
|
gunzip libpng-$_apngver-apng.patch.gz
|
||||||
|
|
||||||
|
|
||||||
|
## Start building!
|
||||||
|
|
||||||
|
cd libpng-$pngver
|
||||||
|
# Patch in apng support
|
||||||
|
patch -p0 ../libpng-$_apngver-apng.patch
|
||||||
|
|
||||||
|
mkdir -p build-${_arch}
|
||||||
|
cd build-${_arch}
|
||||||
|
${_arch}-configure LDFLAGS=-static-libgcc
|
||||||
|
make
|
||||||
|
make install
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
10d9e0cb60e2b387a79b355eb7527c0bee2ed8cbd12cf04417cabc4d6976683c libpng-1.6.37-apng.patch.gz
|
||||||
|
505e70834d35383537b6491e7ae8641f1a4bed1876dbfe361201fc80868d88ca libpng-1.6.37.tar.xz
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
name: "Code style checking"
|
||||||
|
on: pull_request
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
checkpatch:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Set up repo
|
||||||
|
run: |
|
||||||
|
git clone -b "${{ github.event.pull_request.head.ref }}" "${{ github.event.pull_request.head.repo.clone_url }}" rgbds
|
||||||
|
cd rgbds
|
||||||
|
git remote add upstream "${{ github.event.pull_request.base.repo.clone_url }}"
|
||||||
|
git fetch upstream
|
||||||
|
- name: Set up checkpatch
|
||||||
|
working-directory: rgbds
|
||||||
|
run: |
|
||||||
|
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/checkpatch.pl'
|
||||||
|
chmod +x checkpatch.pl
|
||||||
|
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/const_structs.checkpatch'
|
||||||
|
wget 'https://raw.githubusercontent.com/torvalds/linux/master/scripts/spelling.txt'
|
||||||
|
- name: Checkpatch
|
||||||
|
working-directory: rgbds
|
||||||
|
run: |
|
||||||
|
make checkpatch CHECKPATCH=./checkpatch.pl "BASE_REF=${{ github.event.pull_request.base.sha }}" Q= | tee log
|
||||||
|
if grep -q ERROR: log; then exit 1; else exit 0; fi
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
name: "Create release docs"
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- released # This avoids triggering on pre-releases
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout rgbds@release
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
path: rgbds
|
||||||
|
- name: Checkout rgbds-www@master
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: ${{ github.repository_owner }}/rgbds-www
|
||||||
|
path: rgbds-www
|
||||||
|
# `-O toc` was added in 1.14.5, but the repos only have 1.14.4
|
||||||
|
- name: Build and install mandoc + install groff
|
||||||
|
run: |
|
||||||
|
sudo apt-get -qq update
|
||||||
|
sudo apt-get install -yq groff zlib1g-dev
|
||||||
|
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
|
||||||
|
tar xf mandoc-1.14.5.tar.gz
|
||||||
|
cd mandoc-1.14.5
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
- name: Update pages
|
||||||
|
working-directory: rgbds
|
||||||
|
run: | # The ref appears to be in the format "refs/tags/<version>", so strip that
|
||||||
|
./.github/actions/get-pages.sh -r ../rgbds-www ${GITHUB_REF##*/}
|
||||||
|
- name: Push new pages
|
||||||
|
working-directory: rgbds-www
|
||||||
|
run: |
|
||||||
|
mkdir -p -m 700 ~/.ssh
|
||||||
|
cat > ~/.ssh/id_ed25519 <<<"${{ secrets.SSH_KEY_SECRET }}"
|
||||||
|
chmod 0600 ~/.ssh/id_ed25519
|
||||||
|
eval $(ssh-agent -s)
|
||||||
|
ssh-add ~/.ssh/id_ed25519
|
||||||
|
git config --global user.name "GitHub Action"
|
||||||
|
git config --global user.email "[email protected]"
|
||||||
|
git add -A
|
||||||
|
git commit -m "Create RGBDS ${GITHUB_REF##*/} documentation"
|
||||||
|
if git remote | grep -q origin; then
|
||||||
|
git remote set-url origin [email protected]:${{ github.repository_owner }}/rgbds-www.git
|
||||||
|
else
|
||||||
|
git remote add origin [email protected]:${{ github.repository_owner }}/rgbds-www.git
|
||||||
|
fi
|
||||||
|
git push origin master
|
||||||
@@ -0,0 +1,200 @@
|
|||||||
|
name: "Regression testing"
|
||||||
|
on:
|
||||||
|
- push
|
||||||
|
- pull_request
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
unix-testing:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
os: [ubuntu-20.04, ubuntu-18.04, ubuntu-16.04, macos-10.15]
|
||||||
|
cc: [gcc, clang]
|
||||||
|
buildsys: [make, cmake]
|
||||||
|
include:
|
||||||
|
- os: ubuntu-18.04
|
||||||
|
cc: gcc
|
||||||
|
target: develop
|
||||||
|
cmakevars: -DSANITIZERS=ON -DMORE_WARNINGS=ON -DCMAKE_BUILD_TYPE=Debug
|
||||||
|
- os: ubuntu-20.04
|
||||||
|
cc: gcc
|
||||||
|
target: develop
|
||||||
|
cmakevars: -DSANITIZERS=ON -DMORE_WARNINGS=ON -DCMAKE_BUILD_TYPE=Debug
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install deps
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
./.github/actions/install_deps.sh ${{ matrix.os }}
|
||||||
|
# The `export` lines are to allow working on macOS...
|
||||||
|
# Apple's base version is severely outdated, not even supporting -Wall,
|
||||||
|
# but it overrides Homebrew's version nonetheless...
|
||||||
|
- name: Build & install using Make
|
||||||
|
run: |
|
||||||
|
export PATH="/usr/local/opt/bison/bin:$PATH"
|
||||||
|
make ${{ matrix.target }} -j Q= CC=${{ matrix.cc }}
|
||||||
|
sudo make install -j Q=
|
||||||
|
if: matrix.buildsys == 'make'
|
||||||
|
- name: Build & install using CMake
|
||||||
|
run: |
|
||||||
|
export PATH="/usr/local/opt/bison/bin:$PATH"
|
||||||
|
cmake -S . -B build -DCMAKE_VERBOSE_MAKEFILE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=${{ matrix.cc }} ${{ matrix.cmakevars }}
|
||||||
|
cmake --build build
|
||||||
|
cp build/src/rgb{asm,link,fix,gfx} .
|
||||||
|
sudo cmake --install build
|
||||||
|
if: matrix.buildsys == 'cmake'
|
||||||
|
- name: Package binaries
|
||||||
|
run: |
|
||||||
|
mkdir bins
|
||||||
|
cp rgb{asm,link,fix,gfx} bins
|
||||||
|
- name: Upload binaries
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: rgbds-canary-${{ matrix.os }}-${{ matrix.cc }}-${{ matrix.buildsys }}
|
||||||
|
path: bins
|
||||||
|
- name: Test
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
test/run-tests.sh
|
||||||
|
|
||||||
|
windows-testing:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
bits: [32, 64]
|
||||||
|
include:
|
||||||
|
- bits: 32
|
||||||
|
arch: x86
|
||||||
|
platform: Win32
|
||||||
|
- bits: 64
|
||||||
|
arch: x86_x64
|
||||||
|
platform: x64
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: windows-2019
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Get zlib, libpng and bison
|
||||||
|
run: | # TODO: use an array
|
||||||
|
$wc = New-Object System.Net.WebClient
|
||||||
|
$wc.DownloadFile('https://www.zlib.net/zlib1211.zip', 'zlib.zip')
|
||||||
|
$hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
|
||||||
|
if ($hash -ne 'd7510a8ee1918b7d0cad197a089c0a2cd4d6df05fee22389f67f115e738b178d') {
|
||||||
|
Write-Host "zlib SHA256 mismatch! ($hash)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
|
||||||
|
$hash = (Get-FileHash "libpng.zip" -Algorithm SHA256).Hash
|
||||||
|
if ($hash -ne '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2') {
|
||||||
|
Write-Host "libpng SHA256 mismatch! ($hash)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$wc.DownloadFile('https://github.com/lexxmark/winflexbison/releases/download/v2.5.23/win_flex_bison-2.5.23.zip', 'winflexbison.zip')
|
||||||
|
$hash = (Get-FileHash "winflexbison.zip" -Algorithm SHA256).Hash
|
||||||
|
if ($hash -ne '6AA5C8EA662DA1550020A5804C28BE63FFAA53486DA9F6842E24C379EC422DFC') {
|
||||||
|
Write-Host "bison SHA256 mismatch! ($hash)"
|
||||||
|
}
|
||||||
|
Expand-Archive -DestinationPath . "zlib.zip"
|
||||||
|
Expand-Archive -DestinationPath . "libpng.zip"
|
||||||
|
Expand-Archive -DestinationPath install_dir "winflexbison.zip"
|
||||||
|
Move-Item zlib-1.2.11 zlib
|
||||||
|
Move-Item lpng1637 libpng
|
||||||
|
- name: Build zlib
|
||||||
|
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
|
||||||
|
cmake -S zlib -B zbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
|
||||||
|
cmake --build zbuild --config Release
|
||||||
|
cmake --install zbuild
|
||||||
|
- name: Build libpng
|
||||||
|
run: |
|
||||||
|
cmake -S libpng -B pngbuild -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
|
||||||
|
cmake --build pngbuild --config Release
|
||||||
|
cmake --install pngbuild
|
||||||
|
- name: Build Windows binaries
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build -A ${{ matrix.platform }} -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build --config Release
|
||||||
|
cmake --install build
|
||||||
|
- name: Package binaries
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir bins
|
||||||
|
cp install_dir/bin/{rgbasm.exe,rgblink.exe,rgbfix.exe,rgbgfx.exe,zlib1.dll,libpng16.dll} bins
|
||||||
|
- name: Upload Windows binaries
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: rgbds-canary-win${{ matrix.bits }}
|
||||||
|
path: bins
|
||||||
|
- name: Test
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cp bins/* .
|
||||||
|
test/run-tests.sh
|
||||||
|
|
||||||
|
windows-xbuild:
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
bits: [32, 64]
|
||||||
|
os: [ubuntu-18.04]
|
||||||
|
include:
|
||||||
|
- bits: 32
|
||||||
|
arch: i686
|
||||||
|
triplet: i686-w64-mingw32
|
||||||
|
- bits: 64
|
||||||
|
arch: x86-64
|
||||||
|
triplet: x86_64-w64-mingw32
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: ${{ matrix.os }}
|
||||||
|
env:
|
||||||
|
DIST_DIR: win${{ matrix.bits }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Install deps
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
./.github/actions/install_deps.sh ${{ matrix.os }}
|
||||||
|
- name: Install MinGW
|
||||||
|
run: |
|
||||||
|
sudo apt-get install gcc-mingw-w64-${{ matrix.arch }} mingw-w64-tools libz-mingw-w64-dev
|
||||||
|
- name: Install libpng dev headers for MinGW
|
||||||
|
run: |
|
||||||
|
sudo ./.github/actions/mingw-w64-libpng-dev.sh ${{ matrix.triplet }}
|
||||||
|
- name: Cross-build Windows binaries
|
||||||
|
run: |
|
||||||
|
make mingw${{ matrix.bits }} -j Q=
|
||||||
|
- name: Package binaries
|
||||||
|
run: |
|
||||||
|
mkdir bins
|
||||||
|
mv rgbasm bins/rgbasm.exe
|
||||||
|
mv rgblink bins/rgblink.exe
|
||||||
|
mv rgbfix bins/rgbfix.exe
|
||||||
|
mv rgbgfx bins/rgbgfx.exe
|
||||||
|
cp /usr/${{ matrix.triplet }}/lib/zlib1.dll bins
|
||||||
|
cp /usr/${{ matrix.triplet }}/bin/libpng16-16.dll bins
|
||||||
|
if [ ${{ matrix.bits }} -eq 32 ]; then cp /usr/lib/gcc/${{ matrix.triplet }}/7.3-win32/libgcc_s_sjlj-1.dll bins; fi
|
||||||
|
- name: Upload Windows binaries
|
||||||
|
uses: actions/upload-artifact@v1
|
||||||
|
with:
|
||||||
|
name: rgbds-canary-mingw-win${{ matrix.bits }}
|
||||||
|
path: bins
|
||||||
|
|
||||||
|
windows-xtesting:
|
||||||
|
needs: windows-xbuild
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
bits: [32, 64]
|
||||||
|
fail-fast: false
|
||||||
|
runs-on: windows-2019
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Retrieve binaries
|
||||||
|
uses: actions/download-artifact@v1
|
||||||
|
with:
|
||||||
|
name: rgbds-canary-mingw-win${{ matrix.bits }}
|
||||||
|
path: bins
|
||||||
|
- name: Extract binaries
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
cp bins/* .
|
||||||
|
- name: Run tests
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
test/run-tests.sh
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
name: "Update master docs"
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths:
|
||||||
|
- .github/actions/get-pages.sh
|
||||||
|
- src/gbz80.7
|
||||||
|
- src/rgbds.5
|
||||||
|
- src/rgbds.7
|
||||||
|
- src/asm/rgbasm.1
|
||||||
|
- src/asm/rgbasm.5
|
||||||
|
- src/link/rgblink.1
|
||||||
|
- src/link/rgblink.5
|
||||||
|
- src/fix/rgbfix.1
|
||||||
|
- src/gfx/rgbgfx.1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-18.04
|
||||||
|
steps:
|
||||||
|
- name: Checkout rgbds@master
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: gbdev/rgbds
|
||||||
|
ref: master
|
||||||
|
path: rgbds
|
||||||
|
- name: Checkout rgbds-www@master
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
repository: gbdev/rgbds-www
|
||||||
|
ref: master
|
||||||
|
path: rgbds-www
|
||||||
|
- name: Build and install mandoc + install groff
|
||||||
|
run: |
|
||||||
|
sudo apt-get -qq update
|
||||||
|
sudo apt-get install -yq groff zlib1g-dev
|
||||||
|
wget 'http://mandoc.bsd.lv/snapshots/mandoc-1.14.5.tar.gz'
|
||||||
|
tar xf mandoc-1.14.5.tar.gz
|
||||||
|
cd mandoc-1.14.5
|
||||||
|
./configure
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
- name: Update pages
|
||||||
|
working-directory: rgbds
|
||||||
|
run: |
|
||||||
|
./.github/actions/get-pages.sh ../rgbds-www master
|
||||||
|
- name: Push new pages
|
||||||
|
working-directory: rgbds-www
|
||||||
|
run: |
|
||||||
|
mkdir -p -m 700 ~/.ssh
|
||||||
|
echo "${{ secrets.SSH_KEY_SECRET }}" > ~/.ssh/id_ed25519
|
||||||
|
chmod 0600 ~/.ssh/id_ed25519
|
||||||
|
eval $(ssh-agent -s)
|
||||||
|
ssh-add ~/.ssh/id_ed25519
|
||||||
|
git config --global user.name "GitHub Action"
|
||||||
|
git config --global user.email "[email protected]"
|
||||||
|
git add .
|
||||||
|
git commit -m "Update RGBDS master documentation"
|
||||||
|
if git remote | grep -q origin; then
|
||||||
|
git remote set-url origin [email protected]:gbdev/rgbds-www.git
|
||||||
|
else
|
||||||
|
git remote add origin [email protected]:gbdev/rgbds-www.git
|
||||||
|
fi
|
||||||
|
git push origin master
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
name: "Create release artifacts"
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- v[0-9]*
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
windows:
|
||||||
|
runs-on: windows-2019
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- name: Get version from tag
|
||||||
|
shell: bash
|
||||||
|
run: | # Turn "refs/tags/vX.Y.Z" into "X.Y.Z"
|
||||||
|
VERSION="${{ github.ref }}"
|
||||||
|
echo "version=${VERSION##*/v}" >> $GITHUB_ENV
|
||||||
|
- name: Get zlib, libpng and bison
|
||||||
|
run: | # TODO: use an array
|
||||||
|
$wc = New-Object System.Net.WebClient
|
||||||
|
$wc.DownloadFile('https://www.zlib.net/zlib1211.zip', 'zlib.zip')
|
||||||
|
$hash = (Get-FileHash "zlib.zip" -Algorithm SHA256).Hash
|
||||||
|
if ($hash -ne 'd7510a8ee1918b7d0cad197a089c0a2cd4d6df05fee22389f67f115e738b178d') {
|
||||||
|
Write-Host "zlib SHA256 mismatch! ($hash)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$wc.DownloadFile('https://download.sourceforge.net/libpng/lpng1637.zip', 'libpng.zip')
|
||||||
|
$hash = (Get-FileHash "libpng.zip" -Algorithm SHA256).Hash
|
||||||
|
if ($hash -ne '3b4b1cbd0bae6822f749d39b1ccadd6297f05e2b85a83dd2ce6ecd7d09eabdf2') {
|
||||||
|
Write-Host "libpng SHA256 mismatch! ($hash)"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
$wc.DownloadFile('https://github.com/lexxmark/winflexbison/releases/download/v2.5.23/win_flex_bison-2.5.23.zip', 'winflexbison.zip')
|
||||||
|
$hash = (Get-FileHash "winflexbison.zip" -Algorithm SHA256).Hash
|
||||||
|
if ($hash -ne '6AA5C8EA662DA1550020A5804C28BE63FFAA53486DA9F6842E24C379EC422DFC') {
|
||||||
|
Write-Host "bison SHA256 mismatch! ($hash)"
|
||||||
|
}
|
||||||
|
Expand-Archive -DestinationPath . "zlib.zip"
|
||||||
|
Expand-Archive -DestinationPath . "libpng.zip"
|
||||||
|
Expand-Archive -DestinationPath install_dir "winflexbison.zip"
|
||||||
|
Move-Item zlib-1.2.11 zlib
|
||||||
|
Move-Item lpng1637 libpng
|
||||||
|
- name: Build 32-bit zlib
|
||||||
|
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
|
||||||
|
cmake -S zlib -B zbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
|
||||||
|
cmake --build zbuild32 --config Release
|
||||||
|
cmake --install zbuild32
|
||||||
|
- name: Build 32-bit libpng
|
||||||
|
run: |
|
||||||
|
cmake -S libpng -B pngbuild32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
|
||||||
|
cmake --build pngbuild32 --config Release
|
||||||
|
cmake --install pngbuild32
|
||||||
|
- name: Build 32-bit Windows binaries
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build32 -A Win32 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build32 --config Release
|
||||||
|
cmake --install build32
|
||||||
|
- name: Package 32-bit binaries
|
||||||
|
run: |
|
||||||
|
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win32.zip"
|
||||||
|
- name: Build 64-bit zlib
|
||||||
|
run: | # BUILD_SHARED_LIBS causes the output DLL to be correctly called `zlib1.dll`
|
||||||
|
cmake -S zlib -B zbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DBUILD_SHARED_LIBS=ON
|
||||||
|
cmake --build zbuild64 --config Release
|
||||||
|
cmake --install zbuild64
|
||||||
|
- name: Build 64-bit libpng
|
||||||
|
run: |
|
||||||
|
cmake -S libpng -B pngbuild64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DPNG_SHARED=ON -DPNG_STATIC=ON -DPNG_TESTS=OFF
|
||||||
|
cmake --build pngbuild64 --config Release
|
||||||
|
cmake --install pngbuild64
|
||||||
|
- name: Build 64-bit Windows binaries
|
||||||
|
run: |
|
||||||
|
cmake -S . -B build64 -A x64 -DCMAKE_INSTALL_PREFIX=install_dir -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build64 --config Release
|
||||||
|
cmake --install build64
|
||||||
|
- name: Package 64-bit binaries
|
||||||
|
run: |
|
||||||
|
Compress-Archive -LiteralPath @("install_dir/bin/rgbasm.exe", "install_dir/bin/rgblink.exe", "install_dir/bin/rgbfix.exe", "install_dir/bin/rgbgfx.exe", "install_dir/bin/zlib1.dll", "install_dir/bin/libpng16.dll") "rgbds-${{ env.version }}-win64.zip"
|
||||||
|
- name: Package sources
|
||||||
|
run: |
|
||||||
|
make dist
|
||||||
|
- name: Release
|
||||||
|
uses: softprops/action-gh-release@v1
|
||||||
|
with:
|
||||||
|
body: |
|
||||||
|
Please ensure that the three assets below work properly.
|
||||||
|
Once that's done, replace this text with the changelog, un-draft the release, and update the `release` branch.
|
||||||
|
By the way, if you forgot to update `include/version.h`, RGBASM's version test is gonna fail in the tag's regression testing! (Use `git push --delete origin <tag>` to delete it)
|
||||||
|
draft: true # Don't publish the release quite yet...
|
||||||
|
prerelease: ${{ contains(github.ref, '-rc') }}
|
||||||
|
files: |
|
||||||
|
rgbds-${{ env.version }}-win32.zip
|
||||||
|
rgbds-${{ env.version }}-win64.zip
|
||||||
|
rgbds-${{ env.version }}.tar.gz
|
||||||
|
fail_on_unmatched_files: true
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
@@ -2,6 +2,15 @@ rgbasm
|
|||||||
rgblink
|
rgblink
|
||||||
rgbfix
|
rgbfix
|
||||||
rgbgfx
|
rgbgfx
|
||||||
|
rgbshim.sh
|
||||||
*.o
|
*.o
|
||||||
*.exe
|
*.exe
|
||||||
|
*.dll
|
||||||
.checkpatch-camelcase.*
|
.checkpatch-camelcase.*
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
cmake_install.cmake
|
||||||
|
|
||||||
|
test/pokecrystal
|
||||||
|
test/pokered
|
||||||
|
test/ucity
|
||||||
|
|||||||
@@ -1,48 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
echo "Checking code style..."
|
|
||||||
|
|
||||||
# Return failure as soon as a command fails to execute
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Download checkpatch.pl and related files
|
|
||||||
|
|
||||||
echo "Getting checkpatch.pl..."
|
|
||||||
|
|
||||||
mkdir checkpatchdir
|
|
||||||
|
|
||||||
wget https://raw.githubusercontent.com/torvalds/linux/master/scripts/checkpatch.pl
|
|
||||||
mv checkpatch.pl checkpatchdir/checkpatch.pl
|
|
||||||
chmod +x checkpatchdir/checkpatch.pl
|
|
||||||
|
|
||||||
touch checkpatchdir/const_structs.checkpatch
|
|
||||||
touch checkpatchdir/spelling.txt
|
|
||||||
|
|
||||||
# Run checkpatch.pl on the new commits
|
|
||||||
|
|
||||||
echo "Running checkpatch.pl..."
|
|
||||||
|
|
||||||
fname=$(mktemp)
|
|
||||||
rc=0
|
|
||||||
|
|
||||||
git remote set-branches --add origin develop
|
|
||||||
git fetch
|
|
||||||
|
|
||||||
make CHECKPATCH=checkpatchdir/checkpatch.pl checkpatch > $fname
|
|
||||||
|
|
||||||
cat $fname
|
|
||||||
|
|
||||||
if grep "ERROR" $fname; then
|
|
||||||
# At least one error found
|
|
||||||
echo "Code style errors have been found!"
|
|
||||||
rc=1
|
|
||||||
else
|
|
||||||
echo "No code style errors found, your patches are ready!"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Cleanup
|
|
||||||
|
|
||||||
rm -rf checkpatchdir
|
|
||||||
|
|
||||||
exit $rc
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
#!/bin/sh
|
|
||||||
|
|
||||||
if [ $TRAVIS_OS_NAME = "osx" ]; then
|
|
||||||
brew update
|
|
||||||
brew install libpng pkg-config
|
|
||||||
else # linux
|
|
||||||
sudo apt-get -qq update
|
|
||||||
sudo apt-get install -y -q bison flex libpng-dev pkg-config
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Dependencies:"
|
|
||||||
yacc --version
|
|
||||||
flex --version
|
|
||||||
-15
@@ -1,15 +0,0 @@
|
|||||||
language: c
|
|
||||||
sudo: required
|
|
||||||
install:
|
|
||||||
- ./.travis-deps.sh
|
|
||||||
- make
|
|
||||||
- sudo make install
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
compiler:
|
|
||||||
- clang
|
|
||||||
- gcc
|
|
||||||
script:
|
|
||||||
- ./.travis-checkpatch.sh
|
|
||||||
- cd test
|
|
||||||
- ./run-tests.sh
|
|
||||||
@@ -0,0 +1,97 @@
|
|||||||
|
#
|
||||||
|
# This file is part of RGBDS.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 RGBDS contributors.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
|
||||||
|
# 3.9 required for LTO checks
|
||||||
|
cmake_minimum_required(VERSION 3.9 FATAL_ERROR)
|
||||||
|
|
||||||
|
project(rgbds
|
||||||
|
LANGUAGES C)
|
||||||
|
|
||||||
|
# get real path of source and binary directories
|
||||||
|
get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH)
|
||||||
|
get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH)
|
||||||
|
|
||||||
|
# reject in-source builds, may conflict with Makefile
|
||||||
|
if(srcdir STREQUAL bindir)
|
||||||
|
message("RGBDS should not be built in the source directory.")
|
||||||
|
message("Instead, create a separate build directory and specify to CMake the path to the source directory.")
|
||||||
|
message(FATAL_ERROR "Terminating configuration")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(SANITIZERS "Build with sanitizers enabled" OFF) # Ignored on MSVC
|
||||||
|
option(MORE_WARNINGS "Turn on more warnings" OFF) # Ignored on MSVC
|
||||||
|
option(TRACE_PARSER "Trace parser execution" OFF)
|
||||||
|
option(TRACE_LEXER "Trace lexer execution" OFF)
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
# MSVC's standard library triggers warning C5105,
|
||||||
|
# "macro expansion producing 'defined' has undefined behavior"
|
||||||
|
add_compile_options(/std:c11 /W1 /MP /wd5105)
|
||||||
|
add_definitions(/D_CRT_SECURE_NO_WARNINGS)
|
||||||
|
else()
|
||||||
|
add_compile_options(-Wall -pedantic)
|
||||||
|
if(SANITIZERS)
|
||||||
|
set(SAN_FLAGS -fsanitize=shift -fsanitize=integer-divide-by-zero
|
||||||
|
-fsanitize=unreachable -fsanitize=vla-bound
|
||||||
|
-fsanitize=signed-integer-overflow -fsanitize=bounds
|
||||||
|
-fsanitize=object-size -fsanitize=bool -fsanitize=enum
|
||||||
|
-fsanitize=alignment -fsanitize=null)
|
||||||
|
add_compile_options(${SAN_FLAGS})
|
||||||
|
link_libraries(${SAN_FLAGS})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(MORE_WARNINGS)
|
||||||
|
add_compile_options(-Werror -Wextra -Wno-type-limits
|
||||||
|
-Wno-sign-compare -Wvla -Wformat -Wformat-security -Wformat-overflow=2
|
||||||
|
-Wformat-truncation=1 -Wformat-y2k -Wswitch-enum -Wunused
|
||||||
|
-Wuninitialized -Wunknown-pragmas -Wstrict-overflow=5
|
||||||
|
-Wstringop-overflow=4 -Walloc-zero -Wduplicated-cond
|
||||||
|
-Wfloat-equal -Wshadow -Wcast-qual -Wcast-align -Wlogical-op
|
||||||
|
-Wnested-externs -Wno-aggressive-loop-optimizations -Winline
|
||||||
|
-Wundef -Wstrict-prototypes -Wold-style-definition)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Use versioning consistent with Makefile
|
||||||
|
# the git revision is used but uses the fallback in an archive
|
||||||
|
|
||||||
|
execute_process(COMMAND git describe --tags --dirty --always
|
||||||
|
OUTPUT_VARIABLE GIT_REV
|
||||||
|
ERROR_QUIET)
|
||||||
|
string(STRIP "${GIT_REV}" GIT_REV)
|
||||||
|
|
||||||
|
include_directories("${PROJECT_SOURCE_DIR}/include")
|
||||||
|
|
||||||
|
add_definitions(-DBUILD_VERSION_STRING="${GIT_REV}")
|
||||||
|
|
||||||
|
set(CMAKE_C_STANDARD 11)
|
||||||
|
set(CMAKE_C_STANDARD_REQUIRED True)
|
||||||
|
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
# By default, build in Release mode; Debug mode must be explicitly requested
|
||||||
|
# (You may want to augment it with the options above)
|
||||||
|
if(CMAKE_BUILD_TYPE STREQUAL "Release")
|
||||||
|
message(CHECK_START "Checking if LTO is supported")
|
||||||
|
include(CheckIPOSupported)
|
||||||
|
check_ipo_supported(RESULT enable_lto)
|
||||||
|
if(enable_lto)
|
||||||
|
message(CHECK_PASS "yes")
|
||||||
|
set_property(TARGET rgbasm rgblink rgbfix rgbgfx PROPERTY INTERPROCEDURAL_OPTIMIZATION ON)
|
||||||
|
else()
|
||||||
|
message(CHECK_FAIL "no")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TRACE_PARSER)
|
||||||
|
target_compile_definitions(rgbasm PRIVATE -DYYDEBUG)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(TRACE_LEXER)
|
||||||
|
target_compile_definitions(rgbasm PRIVATE -DLEXER_DEBUG)
|
||||||
|
endif()
|
||||||
+10
-12
@@ -65,9 +65,9 @@ copyright and the reference to the MIT License.
|
|||||||
|
|
||||||
1. Fork this repository.
|
1. Fork this repository.
|
||||||
|
|
||||||
2. Checkout the ``develop`` branch.
|
2. Checkout the ``master`` branch.
|
||||||
|
|
||||||
3. Create a new branch to work on. You could still work on ``develop``, but it's
|
3. Create a new branch to work on. You could still work on ``master``, but it's
|
||||||
easier that way.
|
easier that way.
|
||||||
|
|
||||||
4. Compile your changes with ``make develop`` instead of just ``make``. This
|
4. Compile your changes with ``make develop`` instead of just ``make``. This
|
||||||
@@ -75,24 +75,22 @@ copyright and the reference to the MIT License.
|
|||||||
new warning (but it may be possible to remove some warning checks if it makes
|
new warning (but it may be possible to remove some warning checks if it makes
|
||||||
the code much easier).
|
the code much easier).
|
||||||
|
|
||||||
5. Sign off your commits: ``git commit -s``
|
5. Follow the Linux kernel coding style, which can be found in the file
|
||||||
|
|
||||||
6. Follow the Linux kernel coding style, which can be found in the file
|
|
||||||
``Documentation/process/coding-style.rst`` in the Linux kernel repository.
|
``Documentation/process/coding-style.rst`` in the Linux kernel repository.
|
||||||
Note that the coding style isn't writen on stone, if there is a good reason
|
Note that the coding style isn't written in stone, if there is a good reason
|
||||||
to deviate from it, it should be fine.
|
to deviate from it, it should be fine.
|
||||||
|
|
||||||
7. Download the files ``checkpatch.pl``, ``const_structs.checkpatch`` and
|
6. Download the files ``checkpatch.pl``, ``const_structs.checkpatch`` and
|
||||||
``spelling.txt`` from the folder ``scripts`` in the Linux kernel repository.
|
``spelling.txt`` from the folder ``scripts`` in the Linux kernel repository.
|
||||||
|
|
||||||
8. To use ``checkpatch.pl`` you can use ``make checkpatch``, which will check
|
7. To use ``checkpatch.pl`` you can use ``make checkpatch``, which will check
|
||||||
the coding style of all patches between the current one and the upstream
|
the coding style of all patches between the current one and the upstream
|
||||||
code. By default, the Makefile expects the script (and associate files) to be
|
code. By default, the Makefile expects the script (and associate files) to be
|
||||||
located in ``../linux/scripts/``, but you can place them anywhere you like as
|
located in ``../linux/scripts/``, but you can place them anywhere you like as
|
||||||
long as you specify it when executing the command:
|
long as you specify it when executing the command:
|
||||||
``CHECKPATCH=../path/to/folder make checkpatch``.
|
``make checkpatch CHECKPATCH=../path/to/folder``.
|
||||||
|
|
||||||
9. Create a pull request against the branch ``develop``.
|
8. Create a pull request against the branch ``master``.
|
||||||
|
|
||||||
10. Be prepared to get some comments about your code and to modify it. Tip: Use
|
9. Be prepared to get some comments about your code and to modify it. Tip: Use
|
||||||
``git rebase -i origin/develop`` to modify chains of commits.
|
``git rebase -i origin/master`` to modify chains of commits.
|
||||||
|
|||||||
+13
-1
@@ -22,20 +22,32 @@ Main contributors
|
|||||||
Other contributors
|
Other contributors
|
||||||
------------------
|
------------------
|
||||||
|
|
||||||
- Ben10do
|
- Ben Hetherington <[email protected]>
|
||||||
|
|
||||||
- Björn Höhrmann <[email protected]>
|
- Björn Höhrmann <[email protected]>
|
||||||
|
|
||||||
- Christophe Staïesse <[email protected]>
|
- Christophe Staïesse <[email protected]>
|
||||||
|
|
||||||
|
- David Brotz <[email protected]>
|
||||||
|
|
||||||
|
- Eldred Habert <[email protected]>
|
||||||
|
|
||||||
- The Musl C library <http://www.musl-libc.org>
|
- The Musl C library <http://www.musl-libc.org>
|
||||||
|
|
||||||
- obskyr <[email protected]>
|
- obskyr <[email protected]>
|
||||||
|
|
||||||
- The OpenBSD Project <http://www.openbsd.org>
|
- The OpenBSD Project <http://www.openbsd.org>
|
||||||
|
|
||||||
|
- Quint Guvernator <[email protected]>
|
||||||
|
|
||||||
|
- Rangi <http://github.com/Rangi42>
|
||||||
|
|
||||||
- Sanqui <[email protected]>
|
- Sanqui <[email protected]>
|
||||||
|
|
||||||
- YamaArashi <[email protected]>
|
- YamaArashi <[email protected]>
|
||||||
|
|
||||||
- yenatch <[email protected]>
|
- yenatch <[email protected]>
|
||||||
|
|
||||||
|
- phs <[email protected]>
|
||||||
|
|
||||||
|
- jidoc01 <[email protected]>
|
||||||
|
|||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
# This file is part of RGBDS.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2018-2019, Phil Smith and RGBDS contributors.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# docker build -t rgbds:vX.X.X-alpine
|
||||||
|
FROM alpine:latest
|
||||||
|
RUN apk add --update \
|
||||||
|
build-base \
|
||||||
|
bison \
|
||||||
|
libpng-dev
|
||||||
|
COPY . /rgbds
|
||||||
|
WORKDIR /rgbds
|
||||||
|
RUN make Q='' all
|
||||||
|
|
||||||
|
FROM alpine:latest
|
||||||
|
RUN apk add --update \
|
||||||
|
libpng
|
||||||
|
COPY --from=0 \
|
||||||
|
/rgbds/rgbasm \
|
||||||
|
/rgbds/rgbfix \
|
||||||
|
/rgbds/rgblink \
|
||||||
|
/rgbds/rgbgfx \
|
||||||
|
/bin/
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
The MIT License
|
The MIT License
|
||||||
|
|
||||||
Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
Copyright (c) 1997-2020, Carsten Sorensen and RGBDS contributors.
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to
|
of this software and associated documentation files (the "Software"), to
|
||||||
|
|||||||
@@ -6,39 +6,46 @@
|
|||||||
# SPDX-License-Identifier: MIT
|
# SPDX-License-Identifier: MIT
|
||||||
#
|
#
|
||||||
|
|
||||||
|
.SUFFIXES:
|
||||||
|
.SUFFIXES: .h .y .c .o
|
||||||
|
|
||||||
# User-defined variables
|
# User-defined variables
|
||||||
|
|
||||||
Q := @
|
Q := @
|
||||||
PREFIX := /usr/local
|
PREFIX := /usr/local
|
||||||
bindir := ${PREFIX}/bin
|
bindir := ${PREFIX}/bin
|
||||||
mandir := ${PREFIX}/man
|
mandir := ${PREFIX}/share/man
|
||||||
STRIP := -s
|
STRIP := -s
|
||||||
BINMODE := 555
|
BINMODE := 755
|
||||||
MANMODE := 444
|
MANMODE := 644
|
||||||
CHECKPATCH := ../linux/scripts/checkpatch.pl
|
CHECKPATCH := ../linux/scripts/checkpatch.pl
|
||||||
|
|
||||||
# Other variables
|
# Other variables
|
||||||
|
|
||||||
PKG_CONFIG := pkg-config
|
PKG_CONFIG := pkg-config
|
||||||
PNGCFLAGS := `${PKG_CONFIG} --static --cflags libpng`
|
PNGCFLAGS := `${PKG_CONFIG} --cflags libpng`
|
||||||
PNGLDFLAGS := `${PKG_CONFIG} --static --libs-only-L libpng`
|
PNGLDFLAGS := `${PKG_CONFIG} --libs-only-L libpng`
|
||||||
PNGLDLIBS := `${PKG_CONFIG} --static --libs-only-l libpng`
|
PNGLDLIBS := `${PKG_CONFIG} --libs-only-l libpng`
|
||||||
|
|
||||||
|
# Note: if this comes up empty, `version.c` will automatically fall back to last release number
|
||||||
VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
|
VERSION_STRING := `git describe --tags --dirty --always 2>/dev/null`
|
||||||
|
|
||||||
WARNFLAGS := -Wall
|
WARNFLAGS := -Wall
|
||||||
|
|
||||||
# Overridable CFLAGS
|
# Overridable CFLAGS
|
||||||
CFLAGS := -g
|
CFLAGS ?= -O3 -flto -DNDEBUG
|
||||||
# Non-overridable CFLAGS
|
# Non-overridable CFLAGS
|
||||||
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=c99 -D_POSIX_C_SOURCE=200809L \
|
REALCFLAGS := ${CFLAGS} ${WARNFLAGS} -std=gnu11 -D_POSIX_C_SOURCE=200809L \
|
||||||
-Iinclude -DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
|
-Iinclude
|
||||||
|
# Overridable LDFLAGS
|
||||||
|
LDFLAGS ?=
|
||||||
|
# Non-overridable LDFLAGS
|
||||||
|
REALLDFLAGS := ${LDFLAGS} ${WARNFLAGS} \
|
||||||
|
-DBUILD_VERSION_STRING=\"${VERSION_STRING}\"
|
||||||
|
|
||||||
YFLAGS :=
|
YFLAGS ?= -Wall
|
||||||
LFLAGS := --nounistd
|
|
||||||
|
|
||||||
YACC := yacc
|
BISON := bison
|
||||||
LEX := flex
|
|
||||||
RM := rm -rf
|
RM := rm -rf
|
||||||
|
|
||||||
# Rules to build the RGBDS binaries
|
# Rules to build the RGBDS binaries
|
||||||
@@ -46,98 +53,106 @@ RM := rm -rf
|
|||||||
all: rgbasm rgblink rgbfix rgbgfx
|
all: rgbasm rgblink rgbfix rgbgfx
|
||||||
|
|
||||||
rgbasm_obj := \
|
rgbasm_obj := \
|
||||||
src/asm/asmy.o \
|
|
||||||
src/asm/charmap.o \
|
src/asm/charmap.o \
|
||||||
|
src/asm/fixpoint.o \
|
||||||
|
src/asm/format.o \
|
||||||
src/asm/fstack.o \
|
src/asm/fstack.o \
|
||||||
src/asm/globlex.o \
|
|
||||||
src/asm/lexer.o \
|
src/asm/lexer.o \
|
||||||
|
src/asm/macro.o \
|
||||||
src/asm/main.o \
|
src/asm/main.o \
|
||||||
src/asm/math.o \
|
src/asm/parser.o \
|
||||||
|
src/asm/opt.o \
|
||||||
src/asm/output.o \
|
src/asm/output.o \
|
||||||
src/asm/rpn.o \
|
src/asm/rpn.o \
|
||||||
|
src/asm/section.o \
|
||||||
src/asm/symbol.o \
|
src/asm/symbol.o \
|
||||||
|
src/asm/util.o \
|
||||||
|
src/asm/warning.o \
|
||||||
src/extern/err.o \
|
src/extern/err.o \
|
||||||
|
src/extern/getopt.o \
|
||||||
src/extern/utf8decoder.o \
|
src/extern/utf8decoder.o \
|
||||||
src/version.o
|
src/hashmap.o \
|
||||||
|
src/linkdefs.o \
|
||||||
|
src/opmath.o
|
||||||
|
|
||||||
src/asm/asmy.h: src/asm/asmy.c
|
src/asm/lexer.o src/asm/main.o: src/asm/parser.h
|
||||||
src/asm/locallex.o src/asm/globlex.o src/asm/lexer.o: src/asm/asmy.h
|
|
||||||
|
|
||||||
rgblink_obj := \
|
rgblink_obj := \
|
||||||
src/link/assign.o \
|
src/link/assign.o \
|
||||||
src/link/lexer.o \
|
|
||||||
src/link/library.o \
|
|
||||||
src/link/main.o \
|
src/link/main.o \
|
||||||
src/link/mapfile.o \
|
|
||||||
src/link/object.o \
|
src/link/object.o \
|
||||||
src/link/output.o \
|
src/link/output.o \
|
||||||
src/link/patch.o \
|
src/link/patch.o \
|
||||||
src/link/parser.o \
|
|
||||||
src/link/script.o \
|
src/link/script.o \
|
||||||
|
src/link/section.o \
|
||||||
src/link/symbol.o \
|
src/link/symbol.o \
|
||||||
src/extern/err.o \
|
src/extern/err.o \
|
||||||
src/version.o
|
src/extern/getopt.o \
|
||||||
|
src/hashmap.o \
|
||||||
src/link/parser.h: src/link/parser.c
|
src/linkdefs.o \
|
||||||
src/link/lexer.o: src/link/parser.h
|
src/opmath.o
|
||||||
|
|
||||||
rgbfix_obj := \
|
rgbfix_obj := \
|
||||||
src/fix/main.o \
|
src/fix/main.o \
|
||||||
src/extern/err.o \
|
src/extern/err.o \
|
||||||
src/version.o
|
src/extern/getopt.o
|
||||||
|
|
||||||
rgbgfx_obj := \
|
rgbgfx_obj := \
|
||||||
src/gfx/gb.o \
|
src/gfx/gb.o \
|
||||||
src/gfx/main.o \
|
src/gfx/main.o \
|
||||||
src/gfx/makepng.o \
|
src/gfx/makepng.o \
|
||||||
src/extern/err.o \
|
src/extern/err.o \
|
||||||
src/version.o
|
src/extern/getopt.o
|
||||||
|
|
||||||
rgbasm: ${rgbasm_obj}
|
rgbasm: ${rgbasm_obj}
|
||||||
$Q${CC} ${REALCFLAGS} -o $@ ${rgbasm_obj} -lm
|
$Q${CC} ${REALLDFLAGS} -o $@ ${rgbasm_obj} ${REALCFLAGS} src/version.c -lm
|
||||||
|
|
||||||
rgblink: ${rgblink_obj}
|
rgblink: ${rgblink_obj}
|
||||||
$Q${CC} ${REALCFLAGS} -o $@ ${rgblink_obj}
|
$Q${CC} ${REALLDFLAGS} -o $@ ${rgblink_obj} ${REALCFLAGS} src/version.c
|
||||||
|
|
||||||
rgbfix: ${rgbfix_obj}
|
rgbfix: ${rgbfix_obj}
|
||||||
$Q${CC} ${REALCFLAGS} -o $@ ${rgbfix_obj}
|
$Q${CC} ${REALLDFLAGS} -o $@ ${rgbfix_obj} ${REALCFLAGS} src/version.c
|
||||||
|
|
||||||
rgbgfx: ${rgbgfx_obj}
|
rgbgfx: ${rgbgfx_obj}
|
||||||
$Q${CC} ${REALCFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${PNGLDLIBS}
|
$Q${CC} ${REALLDFLAGS} ${PNGLDFLAGS} -o $@ ${rgbgfx_obj} ${REALCFLAGS} src/version.c ${PNGLDLIBS}
|
||||||
|
|
||||||
# Rules to process files
|
# Rules to process files
|
||||||
|
|
||||||
.y.c:
|
# We want the Bison invocation to pass through our rules, not default ones
|
||||||
$Q${YACC} -d ${YFLAGS} -o $@ $<
|
.y.o:
|
||||||
|
|
||||||
.l.o:
|
# Bison-generated C files have an accompanying header
|
||||||
$Q${RM} $*.c
|
src/asm/parser.h: src/asm/parser.c
|
||||||
$Q${LEX} ${LFLAGS} -o $*.c $<
|
$Qtouch $@
|
||||||
$Q${CC} ${REALCFLAGS} -c -o $@ $*.c
|
|
||||||
$Q${RM} $*.c
|
src/asm/parser.c: src/asm/parser.y
|
||||||
|
$QDEFS=; \
|
||||||
|
add_flag(){ \
|
||||||
|
if src/check_bison_ver.sh $$1 $$2; then \
|
||||||
|
DEFS="-D$$3 $$DEFS"; \
|
||||||
|
fi \
|
||||||
|
}; \
|
||||||
|
add_flag 3 5 api.token.raw=true; \
|
||||||
|
add_flag 3 6 parse.error=detailed; \
|
||||||
|
add_flag 3 0 parse.error=verbose; \
|
||||||
|
add_flag 3 0 parse.lac=full; \
|
||||||
|
add_flag 3 0 lr.type=ielr; \
|
||||||
|
echo "DEFS=$$DEFS"; \
|
||||||
|
${BISON} $$DEFS -d ${YFLAGS} -o $@ $<
|
||||||
|
|
||||||
.c.o:
|
.c.o:
|
||||||
$Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
$Q${CC} ${REALCFLAGS} ${PNGCFLAGS} -c -o $@ $<
|
||||||
|
|
||||||
# Target used to remove all files generated by other Makefile targets, except
|
# Target used to remove all files generated by other Makefile targets
|
||||||
# for the html documentation.
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
$Q${RM} rgbasm rgbasm.exe ${rgbasm_obj}
|
$Q${RM} rgbasm rgbasm.exe
|
||||||
$Q${RM} rgblink rgblink.exe ${rgblink_obj}
|
$Q${RM} rgblink rgblink.exe
|
||||||
$Q${RM} rgbfix rgbfix.exe ${rgbfix_obj}
|
$Q${RM} rgbfix rgbfix.exe
|
||||||
$Q${RM} rgbgfx rgbgfx.exe ${rgbgfx_obj}
|
$Q${RM} rgbgfx rgbgfx.exe
|
||||||
$Q${RM} src/asm/asmy.c src/asm/asmy.h
|
$Qfind src/ -name "*.o" -exec rm {} \;
|
||||||
$Q${RM} src/link/lexer.c src/link/parser.c src/link/parser.h
|
$Q${RM} rgbshim.sh
|
||||||
|
$Q${RM} src/asm/parser.c src/asm/parser.h
|
||||||
# Target used to remove all html files generated by the wwwman target
|
|
||||||
|
|
||||||
cleanwwwman:
|
|
||||||
$Q${RM} docs/rgbds.7.html docs/gbz80.7.html docs/rgbds.5.html
|
|
||||||
$Q${RM} docs/rgbasm.1.html docs/rgbasm.5.html
|
|
||||||
$Q${RM} docs/rgblink.1.html docs/rgblink.5.html
|
|
||||||
$Q${RM} docs/rgbfix.1.html
|
|
||||||
$Q${RM} docs/rgbgfx.1.html
|
|
||||||
|
|
||||||
# Target used to install the binaries and man pages.
|
# Target used to install the binaries and man pages.
|
||||||
|
|
||||||
@@ -158,52 +173,40 @@ install: all
|
|||||||
$Qinstall -m ${MANMODE} src/link/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5
|
$Qinstall -m ${MANMODE} src/link/rgblink.5 ${DESTDIR}${mandir}/man5/rgblink.5
|
||||||
$Qinstall -m ${MANMODE} src/gfx/rgbgfx.1 ${DESTDIR}${mandir}/man1/rgbgfx.1
|
$Qinstall -m ${MANMODE} src/gfx/rgbgfx.1 ${DESTDIR}${mandir}/man1/rgbgfx.1
|
||||||
|
|
||||||
# Target used to check the coding style of the whole codebase. '.y' and '.l'
|
# Target used to check the coding style of the whole codebase.
|
||||||
# files aren't checked, unfortunately...
|
# `extern/` is excluded, as it contains external code that should not be patched
|
||||||
|
# to meet our coding style, so applying upstream patches is easier.
|
||||||
|
# `.y` files aren't checked, unfortunately...
|
||||||
|
|
||||||
checkcodebase:
|
checkcodebase:
|
||||||
$Qfor file in `git ls-files | grep -E '\.c|\.h' | grep -v '\.html'`; do \
|
$Qfor file in `git ls-files | grep -E '(\.c|\.h)$$' | grep -Ev '(src|include)/extern/'`; do \
|
||||||
${CHECKPATCH} -f "$$file"; \
|
${CHECKPATCH} -f "$$file"; \
|
||||||
done
|
done
|
||||||
|
|
||||||
# Target used to check the coding style of the patches from the upstream branch
|
# Target used to check the coding style of the patches from the upstream branch
|
||||||
# to the HEAD. Runs checkpatch once for each commit between the current HEAD and
|
# to the HEAD. Runs checkpatch once for each commit between the current HEAD and
|
||||||
# the first common commit between the HEAD and origin/develop. '.y' and '.l'
|
# the first common commit between the HEAD and origin/master.
|
||||||
# files aren't checked, unfortunately...
|
# `.y` files aren't checked, unfortunately...
|
||||||
|
|
||||||
|
BASE_REF:= origin/master
|
||||||
checkpatch:
|
checkpatch:
|
||||||
$Qeval COMMON_COMMIT=$$(git merge-base HEAD origin/develop); \
|
$Qeval COMMON_COMMIT=$$(git merge-base HEAD ${BASE_REF}); \
|
||||||
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
|
for commit in `git rev-list $$COMMON_COMMIT..HEAD`; do \
|
||||||
echo "[*] Analyzing commit '$$commit'"; \
|
echo "[*] Analyzing commit '$$commit'"; \
|
||||||
git format-patch --stdout "$$commit~..$$commit" \
|
git format-patch --stdout "$$commit~..$$commit" \
|
||||||
|
-- src include '!src/extern' '!include/extern' \
|
||||||
| ${CHECKPATCH} - || true; \
|
| ${CHECKPATCH} - || true; \
|
||||||
done
|
done
|
||||||
|
|
||||||
# Target for the project maintainer to easily create web manuals.
|
|
||||||
# It relies on mandoc: http://mdocml.bsd.lv
|
|
||||||
|
|
||||||
MANDOC := -Thtml -Ios=General -Oman=%N.%S.html -Ostyle=mandoc.css
|
|
||||||
|
|
||||||
wwwman:
|
|
||||||
$Qmandoc ${MANDOC} src/rgbds.7 > docs/rgbds.7.html
|
|
||||||
$Qmandoc ${MANDOC} src/gbz80.7 > docs/gbz80.7.html
|
|
||||||
$Qmandoc ${MANDOC} src/rgbds.5 > docs/rgbds.5.html
|
|
||||||
$Qmandoc ${MANDOC} src/asm/rgbasm.1 > docs/rgbasm.1.html
|
|
||||||
$Qmandoc ${MANDOC} src/asm/rgbasm.5 > docs/rgbasm.5.html
|
|
||||||
$Qmandoc ${MANDOC} src/fix/rgbfix.1 > docs/rgbfix.1.html
|
|
||||||
$Qmandoc ${MANDOC} src/link/rgblink.1 > docs/rgblink.1.html
|
|
||||||
$Qmandoc ${MANDOC} src/link/rgblink.5 > docs/rgblink.5.html
|
|
||||||
$Qmandoc ${MANDOC} src/gfx/rgbgfx.1 > docs/rgbgfx.1.html
|
|
||||||
|
|
||||||
# This target is used during development in order to prevent adding new issues
|
# This target is used during development in order to prevent adding new issues
|
||||||
# to the source code. All warnings are treated as errors in order to block the
|
# to the source code. All warnings are treated as errors in order to block the
|
||||||
# compilation and make the continous integration infrastructure return failure.
|
# compilation and make the continous integration infrastructure return failure.
|
||||||
|
|
||||||
develop:
|
develop:
|
||||||
$Qenv make -j WARNFLAGS="-Werror -Wall -Wextra -Wpedantic \
|
$Qenv $(MAKE) -j WARNFLAGS="-Werror -Wall -Wextra -Wpedantic -Wno-type-limits \
|
||||||
-Wno-sign-compare -Wchkp -Wformat=2 -Wformat-overflow=2 \
|
-Wno-sign-compare -Wvla -Wformat -Wformat-security -Wformat-overflow=2 \
|
||||||
-Wformat-truncation=1 -Wformat-y2k -Wswitch-enum -Wunused \
|
-Wformat-truncation=1 -Wformat-y2k -Wswitch-enum -Wunused \
|
||||||
-Wuninitialized -Wunknown-pragmas -Wstrict-overflow=5 \
|
-Wuninitialized -Wunknown-pragmas -Wstrict-overflow=4 \
|
||||||
-Wstringop-overflow=4 -Walloc-zero -Wduplicated-cond \
|
-Wstringop-overflow=4 -Walloc-zero -Wduplicated-cond \
|
||||||
-Wfloat-equal -Wshadow -Wcast-qual -Wcast-align -Wlogical-op \
|
-Wfloat-equal -Wshadow -Wcast-qual -Wcast-align -Wlogical-op \
|
||||||
-Wnested-externs -Wno-aggressive-loop-optimizations -Winline \
|
-Wnested-externs -Wno-aggressive-loop-optimizations -Winline \
|
||||||
@@ -212,7 +215,7 @@ develop:
|
|||||||
-fsanitize=unreachable -fsanitize=vla-bound \
|
-fsanitize=unreachable -fsanitize=vla-bound \
|
||||||
-fsanitize=signed-integer-overflow -fsanitize=bounds \
|
-fsanitize=signed-integer-overflow -fsanitize=bounds \
|
||||||
-fsanitize=object-size -fsanitize=bool -fsanitize=enum \
|
-fsanitize=object-size -fsanitize=bool -fsanitize=enum \
|
||||||
-fsanitize=alignment -fsanitize=null"
|
-fsanitize=alignment -fsanitize=null" CFLAGS="-ggdb3 -O0"
|
||||||
|
|
||||||
# Targets for the project maintainer to easily create Windows exes.
|
# Targets for the project maintainer to easily create Windows exes.
|
||||||
# This is not for Windows users!
|
# This is not for Windows users!
|
||||||
@@ -220,17 +223,25 @@ develop:
|
|||||||
# install instructions instead.
|
# install instructions instead.
|
||||||
|
|
||||||
mingw32:
|
mingw32:
|
||||||
$Qenv PKG_CONFIG_PATH=/usr/i686-w64-mingw32/sys-root/mingw/lib/pkgconfig/ \
|
$Qmake CC=i686-w64-mingw32-gcc BISON=bison \
|
||||||
make CC=i686-w64-mingw32-gcc YACC=bison -j
|
PKG_CONFIG=i686-w64-mingw32-pkg-config -j
|
||||||
$Qmv rgbasm rgbasm.exe
|
|
||||||
$Qmv rgblink rgblink.exe
|
|
||||||
$Qmv rgbfix rgbfix.exe
|
|
||||||
$Qmv rgbgfx rgbgfx.exe
|
|
||||||
|
|
||||||
mingw64:
|
mingw64:
|
||||||
$Qenv PKG_CONFIG_PATH=/usr/x86_64-w64-mingw32/sys-root/mingw/lib/pkgconfig/ \
|
$Qmake CC=x86_64-w64-mingw32-gcc BISON=bison \
|
||||||
make CC=x86_64-w64-mingw32-gcc YACC=bison -j
|
PKG_CONFIG=x86_64-w64-mingw32-pkg-config -j
|
||||||
$Qmv rgbasm rgbasm.exe
|
|
||||||
$Qmv rgblink rgblink.exe
|
wine-shim:
|
||||||
$Qmv rgbfix rgbfix.exe
|
$Qecho '#!/bin/bash' > rgbshim.sh
|
||||||
$Qmv rgbgfx rgbgfx.exe
|
$Qecho 'WINEDEBUG=-all wine $$0.exe "$${@:1}"' >> rgbshim.sh
|
||||||
|
$Qchmod +x rgbshim.sh
|
||||||
|
$Qln -s rgbshim.sh rgbasm
|
||||||
|
$Qln -s rgbshim.sh rgblink
|
||||||
|
$Qln -s rgbshim.sh rgbfix
|
||||||
|
$Qln -s rgbshim.sh rgbgfx
|
||||||
|
|
||||||
|
# Target for the project maintainer to produce distributable release tarballs
|
||||||
|
# of the source code.
|
||||||
|
|
||||||
|
dist:
|
||||||
|
$Qgit ls-files | sed s~^~$${PWD##*/}/~ \
|
||||||
|
| tar -czf rgbds-`git describe --tags | cut -c 2-`.tar.gz -C .. -T -
|
||||||
|
|||||||
+58
-117
@@ -15,148 +15,87 @@ other UNIX tools.
|
|||||||
This toolchain is maintained on `GitHub <https://github.com/rednex/rgbds>`__.
|
This toolchain is maintained on `GitHub <https://github.com/rednex/rgbds>`__.
|
||||||
|
|
||||||
The documentation of this toolchain can be viewed online
|
The documentation of this toolchain can be viewed online
|
||||||
`here <https://rednex.github.io/rgbds/>`__, it is generated from the man pages
|
`here <https://rgbds.gbdev.io/docs/>`__, it is generated from the man pages
|
||||||
found in this repository.
|
found in this repository.
|
||||||
|
|
||||||
1. Installing RGBDS
|
1. Installing RGBDS
|
||||||
-------------------
|
-------------------
|
||||||
|
|
||||||
1.1 Windows
|
The `installation procedure <https://rgbds.gbdev.io/install>`__ is available
|
||||||
~~~~~~~~~~~
|
online for various platforms. `Building from source <https://rgbds.gbdev.io/install/source>`__
|
||||||
|
is possible using ``make`` or ``cmake``; follow the link for more detailed instructions.
|
||||||
Windows builds are available in the releases page on GitHub:
|
|
||||||
|
|
||||||
::
|
|
||||||
|
|
||||||
https://github.com/rednex/rgbds/releases
|
|
||||||
|
|
||||||
Copy the ``.exe`` files to ``C:\Windows\`` or similar.
|
|
||||||
|
|
||||||
If you require the latest version in development, it should be possible to
|
|
||||||
compile RGBDS with MinGW or Cygwin by following the instructions to build it on
|
|
||||||
UNIX systems.
|
|
||||||
|
|
||||||
1.2 macOS
|
|
||||||
~~~~~~~~~
|
|
||||||
|
|
||||||
You can build RGBDS by following the instructions below. However, if you would
|
|
||||||
prefer not to build RGBDS yourself, you may also install it using
|
|
||||||
`Homebrew <http://brew.sh/>`__.
|
|
||||||
|
|
||||||
To install the latest release, use:
|
|
||||||
|
|
||||||
.. code:: sh
|
|
||||||
|
|
||||||
brew install rgbds
|
|
||||||
|
|
||||||
To install RGBDS with all of the current changes in development (as seen on the
|
|
||||||
``master`` branch on GitHub), use:
|
|
||||||
|
|
||||||
.. code:: sh
|
|
||||||
|
|
||||||
brew install rgbds --HEAD
|
|
||||||
|
|
||||||
1.3 Other UNIX-like systems
|
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
No official binaries of RGBDS are distributed for these systems, you must follow
|
|
||||||
the simple instructions below to compile and install it.
|
|
||||||
|
|
||||||
2. Building RGBDS from source
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
RGBDS can be built in UNIX-like systems by following the instructions below.
|
|
||||||
|
|
||||||
2.1 Dependencies
|
|
||||||
~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
RGBDS requires yacc, flex, libpng and pkg-config to be installed.
|
|
||||||
|
|
||||||
On macOS, install the latter two with `Homebrew <http://brew.sh/>`__:
|
|
||||||
|
|
||||||
.. code:: sh
|
|
||||||
|
|
||||||
brew install libpng pkg-config
|
|
||||||
|
|
||||||
On other Unixes, use the built-in package manager. For example, on Debian or
|
|
||||||
Ubuntu:
|
|
||||||
|
|
||||||
.. code:: sh
|
|
||||||
|
|
||||||
sudo apt-get install byacc flex pkg-config libpng-dev
|
|
||||||
|
|
||||||
You can test if libpng and pkg-config are installed by running ``pkg-config
|
|
||||||
--cflags libpng``: if the output is a path, then you're good, and if it outputs
|
|
||||||
an error then you need to install them via a package manager.
|
|
||||||
|
|
||||||
2.2 Build process
|
|
||||||
~~~~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
To build the programs, run in your terminal:
|
|
||||||
|
|
||||||
.. code:: sh
|
.. code:: sh
|
||||||
|
|
||||||
make
|
make
|
||||||
|
sudo make install
|
||||||
Then, to install the compiled programs and manual pages, run (with appropriate
|
|
||||||
privileges, e.g, with ``sudo``):
|
|
||||||
|
|
||||||
.. code:: sh
|
.. code:: sh
|
||||||
|
|
||||||
make install
|
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build
|
||||||
|
cmake --install build
|
||||||
|
|
||||||
After installation, you can read the manuals with the ``man`` command. E.g.,
|
2. RGBDS Folder Organization
|
||||||
|
----------------------------
|
||||||
|
|
||||||
.. code:: sh
|
The RGBDS source code file structure somewhat resembles the following:
|
||||||
|
|
||||||
man 7 rgbds
|
::
|
||||||
|
|
||||||
There are some variables in the Makefile that can be redefined by the user. The
|
.
|
||||||
variables described below can affect installation behavior when given on the
|
├── .github/
|
||||||
make command line. For example, to install RGBDS in your home directory instead
|
│ ├── actions/
|
||||||
of systemwide, run the following:
|
│ │ └── ...
|
||||||
|
│ └── workflows/
|
||||||
|
│ └── ...
|
||||||
|
├── contrib/
|
||||||
|
│ ├── zsh_compl/
|
||||||
|
│ │ └── ...
|
||||||
|
│ └── ...
|
||||||
|
├── include/
|
||||||
|
│ └── ...
|
||||||
|
├── src/
|
||||||
|
│ ├── asm/
|
||||||
|
│ │ └── ...
|
||||||
|
│ ├── extern/
|
||||||
|
│ │ └── ...
|
||||||
|
│ ├── fix/
|
||||||
|
│ │ └── ...
|
||||||
|
│ ├── gfx/
|
||||||
|
│ │ └── ...
|
||||||
|
│ ├── link/
|
||||||
|
│ │ └── ...
|
||||||
|
│ ├── CMakeLists.txt
|
||||||
|
│ └── ...
|
||||||
|
├── test/
|
||||||
|
│ ├── ...
|
||||||
|
│ └── run-tests.sh
|
||||||
|
├── CMakeLists.txt
|
||||||
|
├── Makefile
|
||||||
|
└── README.rst
|
||||||
|
|
||||||
.. code:: sh
|
- ``.github/`` - files and scripts related to the integration of the RGBDS codebase with
|
||||||
|
GitHub.
|
||||||
|
|
||||||
make install PREFIX=$HOME
|
- ``contrib/`` - scripts and other resources which may be useful to users and developers of
|
||||||
|
RGBDS.
|
||||||
|
|
||||||
To do a verbose build, run:
|
* ``zsh_compl`` contains tab completion scripts for use with zsh. Put them somewhere in your ``fpath``, and they should auto-load.
|
||||||
|
|
||||||
.. code:: sh
|
- ``include/`` - header files for each respective C files in `src`.
|
||||||
|
|
||||||
make Q=
|
- ``src/`` - source code and manual pages for RGBDS.
|
||||||
|
|
||||||
This is the complete list of user-defined variables:
|
* Note that the code unique to each RGBDS tool is stored in its respective subdirectory
|
||||||
|
(rgbasm -> ``src/asm/``, for example). ``src/extern/`` contains code imported from external sources.
|
||||||
|
|
||||||
- ``PREFIX``: Location where RGBDS will be installed. Defaults to
|
- ``test/`` - testing framework used to verify that changes to the code don't break or modify the behavior of RGBDS.
|
||||||
``/usr/local``.
|
|
||||||
|
|
||||||
- ``bindir``: Location where the binaries will be installed. Defaults to
|
3. History
|
||||||
``${PREFIX}/bin``.
|
----------
|
||||||
|
|
||||||
- ``mandir``: Location where the manpages will be installed. Defaults to
|
- Around 1997, Carsten Sørensen (AKA SurfSmurf) writes ASMotor as a
|
||||||
``${PREFIX}/man``.
|
|
||||||
|
|
||||||
- ``DESTDIR``: This is prepended to all paths during the installation. It is
|
|
||||||
mainly used for packaging.
|
|
||||||
|
|
||||||
- ``Q``: Whether to quiet the build or not. To make the build more verbose,
|
|
||||||
clear this variable. Defaults to ``@``.
|
|
||||||
|
|
||||||
- ``STRIP``: Whether to strip the installed binaries of debug symbols or not.
|
|
||||||
Defaults to ``-s``.
|
|
||||||
|
|
||||||
- ``BINMODE``: Permissions of the installed binaries. Defaults to ``555``.
|
|
||||||
|
|
||||||
- ``MANMODE``: Permissions of the installed manpages. Defaults to ``444``.
|
|
||||||
|
|
||||||
- ``CHECKPATCH``: Path of the script ``checkpatch.pl`` of the Linux kernel.
|
|
||||||
Defaults to ``../linux/scripts/checkpatch.pl``.
|
|
||||||
|
|
||||||
3 History
|
|
||||||
---------
|
|
||||||
|
|
||||||
- Around 1997, Carsten Sorensen (AKA SurfSmurf) writes ASMotor as a
|
|
||||||
general-purpose assembler/linker system for DOS/Win32
|
general-purpose assembler/linker system for DOS/Win32
|
||||||
|
|
||||||
- Around 1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to read and
|
- Around 1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to read and
|
||||||
@@ -172,3 +111,5 @@ This is the complete list of user-defined variables:
|
|||||||
- 2017, Bentley's repository is moved to a neutral name.
|
- 2017, Bentley's repository is moved to a neutral name.
|
||||||
|
|
||||||
- 2018, codebase relicensed under the MIT license.
|
- 2018, codebase relicensed under the MIT license.
|
||||||
|
|
||||||
|
- 2020, repository is moved to the `gbdev <https://github.com/gbdev>`__ organisation. The `rgbds.gbdev.io <https://rgbds.gbdev.io>`__ website serving documentation and downloads is created.
|
||||||
|
|||||||
Executable
+73
@@ -0,0 +1,73 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 Eldred Habert
|
||||||
|
#
|
||||||
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
# of this software and associated documentation files (the "Software"), to deal
|
||||||
|
# in the Software without restriction, including without limitation the rights
|
||||||
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
# copies of the Software, and to permit persons to whom the Software is
|
||||||
|
# furnished to do so, subject to the following conditions:
|
||||||
|
#
|
||||||
|
# The above copyright notice and this permission notice shall be included in all
|
||||||
|
# copies or substantial portions of the Software.
|
||||||
|
#
|
||||||
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
# SOFTWARE.
|
||||||
|
|
||||||
|
STATE=0
|
||||||
|
diff <(xxd $1) <(xxd $2) | while read -r LINE; do
|
||||||
|
if [ $STATE -eq 0 ]; then
|
||||||
|
# Discard first line (line info)
|
||||||
|
STATE=1
|
||||||
|
elif [ "$LINE" = '---' ]; then
|
||||||
|
# Separator between files switches states
|
||||||
|
echo $LINE
|
||||||
|
STATE=3
|
||||||
|
elif grep -Eq '^[0-9]+(,[0-9]+)?[cd][0-9]+(,[0-9]+)?' <<< "$LINE"; then
|
||||||
|
# Line info resets the whole thing
|
||||||
|
STATE=1
|
||||||
|
elif [ $STATE -eq 1 -o $STATE -eq 3 ]; then
|
||||||
|
# Compute the GB address from the ROM offset
|
||||||
|
OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':')
|
||||||
|
BANK=$((0x$OFS / 0x4000))
|
||||||
|
ADDR=$((0x$OFS % 0x4000 + ($BANK != 0) * 0x4000))
|
||||||
|
# Try finding the preceding symbol closest to the diff
|
||||||
|
if [ $STATE -eq 1 ]; then
|
||||||
|
STATE=2
|
||||||
|
SYMFILE=${1%.*}.sym
|
||||||
|
else
|
||||||
|
STATE=4
|
||||||
|
SYMFILE=${2%.*}.sym
|
||||||
|
fi
|
||||||
|
EXTRA=$(if [ -f "$SYMFILE" ]; then
|
||||||
|
# Read the sym file for such a symbol
|
||||||
|
# Ignore comment lines, only pick matching bank
|
||||||
|
# (The bank regex ignores comments already, make `cut` and `tr` process less lines)
|
||||||
|
grep -Ei $(printf "^%02x:" $BANK) "$SYMFILE" |
|
||||||
|
cut -d ';' -f 1 |
|
||||||
|
tr -d "\r" |
|
||||||
|
while read -r SYMADDR SYM; do
|
||||||
|
SYMADDR=$((0x${SYMADDR#*:}))
|
||||||
|
if [ $SYMADDR -le $ADDR ]; then
|
||||||
|
printf " (%s+%#x)\n" "$SYM" $(($ADDR - $SYMADDR))
|
||||||
|
fi
|
||||||
|
# TODO: assumes sorted sym files
|
||||||
|
done | tail -n 1
|
||||||
|
fi)
|
||||||
|
printf "%02x:%04x %s\n" $BANK $ADDR $EXTRA
|
||||||
|
fi
|
||||||
|
if [ $STATE -eq 2 -o $STATE -eq 4 ]; then
|
||||||
|
OFS=$(cut -d ' ' -f 2 <<< "$LINE" | tr -d ':')
|
||||||
|
BANK=$((0x$OFS / 0x4000))
|
||||||
|
ADDR=$((0x$OFS % 0x4000 + ($BANK != 0) * 0x4000))
|
||||||
|
printf "%s %02x:%04x: %s\n" "${LINE:0:1}" $BANK $ADDR "${LINE#*: }"
|
||||||
|
fi
|
||||||
|
done
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
#compdef rgbasm
|
||||||
|
|
||||||
|
_rgbasm_warnings() {
|
||||||
|
local warnings=(
|
||||||
|
'error:Turn all warnings into errors'
|
||||||
|
|
||||||
|
'all:Enable most warning messages'
|
||||||
|
'extra:Enable extra, possibly unwanted, messages'
|
||||||
|
'everything:Enable literally everything'
|
||||||
|
|
||||||
|
'assert:Warn when WARN-type asserts fail'
|
||||||
|
'builtin-args:Report incorrect args to built-in funcs'
|
||||||
|
'div:Warn when dividing the smallest int by -1'
|
||||||
|
'empty-entry:Warn on empty entries in db, dw, dl args'
|
||||||
|
'large-constant:Warn on constants too large for a signed 32-bit int'
|
||||||
|
'long-string:Warn on strings too long'
|
||||||
|
'obsolete:Warn when using deprecated features'
|
||||||
|
'shift:Warn when shifting negative values'
|
||||||
|
'shift-amount:Warn when a shift'\''s operand it negative or \> 32'
|
||||||
|
'truncation:Warn when implicit truncations lose bits'
|
||||||
|
'user:Warn when executing the WARN built-in'
|
||||||
|
)
|
||||||
|
# TODO: handle `no-` and `error=` somehow?
|
||||||
|
_describe warning warnings
|
||||||
|
}
|
||||||
|
|
||||||
|
local args=(
|
||||||
|
# Arguments are listed here in the same order as in the manual, except for the version
|
||||||
|
'(- : * options)'{-V,--version}'[Print version number]'
|
||||||
|
|
||||||
|
'(-E --export-all)'{-E,--export-all}'[Export all symbols]'
|
||||||
|
'(-h --halt-without-nop)'{-h,--halt-without-nop}'[Avoid outputting a `nop` after `halt`]'
|
||||||
|
'(-L ---preserve-ld)'{-L,--preserve-ld}'[Prevent auto-optimizing `ld` into `ldh`]'
|
||||||
|
'(-v --verbose)'{-v,--verbose}'[Print additional messages regarding progression]'
|
||||||
|
-w'[Disable all warnings]'
|
||||||
|
|
||||||
|
'(-b --binary-digits)'{-b,--binary-digits}'+[Change chars for binary constants]:digit spec:'
|
||||||
|
'(-D --define)'{-D,--define}'+[Define a string symbol]:name + value (default 1):'
|
||||||
|
'(-g --gfx-chars)'{-g,--gfx-chars}'+[Change chars for gfx constants]:chars spec:'
|
||||||
|
'(-i --include)'{-i,--include}'+[Add an include directory]:include path:_files -/'
|
||||||
|
'(-M --dependfile)'{-M,--dependfile}"+[List deps in make format]:output file:_files -g '*.{d,mk}"
|
||||||
|
'(-o --output)'{-o,--output}'+[Output file]:output file:_files'
|
||||||
|
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
|
||||||
|
'(-r --recursion-depth)'{-r,--recursion-depth}'+[Set maximum recursion depth]:depth:'
|
||||||
|
'(-W --warning)'{-W,--warning}'+[Toggle warning flags]:warning flag:_rgbasm_warnings'
|
||||||
|
|
||||||
|
'*'":assembly sources:_files -g '*.asm'"
|
||||||
|
)
|
||||||
|
_arguments -s -S : $args
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#compdef rgbfix
|
||||||
|
|
||||||
|
local args=(
|
||||||
|
# Arguments are listed here in the same order as in the manual, except for the version
|
||||||
|
'(- : * options)'{-V,--version}'[Print version number]'
|
||||||
|
|
||||||
|
'(-C --color-only)'{-C,--color-only}'[Mark ROM as GBC-only]'
|
||||||
|
'(-c --color-compatible)'{-c,--color-compatible}'[Mark ROM as GBC-compatible]'
|
||||||
|
'(-j --non-japanese)'{-j,--non-japanese}'[Set the non-Japanese region flag]'
|
||||||
|
'(-s --sgb-compatible)'{-s,--sgb-compatible}'[Set the SGB flag]'
|
||||||
|
'(-f --fix-spec -v --validate)'{-v,--validate}'[Shorthand for -f lhg]'
|
||||||
|
|
||||||
|
'(-f --fix-spec -v --validate)'{-f,--fix-spec}'+[Fix or trash some header values]:fix spec:'
|
||||||
|
'(-i --game-id)'{-i,--game-id}'+[Set game ID string]:4-char game ID:'
|
||||||
|
'(-k --new-licensee)'{-k,--new-licensee}'+[Set new licensee string]:2-char licensee ID:'
|
||||||
|
'(-l --old-licensee)'{-l,--old-licensee}'+[Set old licensee ID]:licensee number:'
|
||||||
|
'(-m --mbc-type)'{-m,--mbc-type}'+[Set MBC flags]:mbc flags byte:'
|
||||||
|
'(-n --rom-version)'{-n,--rom-version}'+[Set ROM version]:rom version byte:'
|
||||||
|
'(-p --pad-value)'{-p,--pad-value}'+[Pad to next valid size using this byte as padding]:padding byte:'
|
||||||
|
'(-r --ram-size)'{-r,--ram-size}'+[Set RAM size]:ram size byte:'
|
||||||
|
'(-t --title)'{-t,--title}'+[Set title string]:11-char title string:'
|
||||||
|
|
||||||
|
'*'":ROM files:_files -g '*.{gb,sgb,gbc}'"
|
||||||
|
)
|
||||||
|
_arguments -s -S : $args
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
#compdef rgbgfx
|
||||||
|
|
||||||
|
_depths() {
|
||||||
|
local depths=(
|
||||||
|
'1:1bpp'
|
||||||
|
'2:2bpp (native)'
|
||||||
|
)
|
||||||
|
|
||||||
|
_describe 'bit depth' depths
|
||||||
|
}
|
||||||
|
|
||||||
|
local args=(
|
||||||
|
# Arguments are listed here in the same order as in the manual, except for the version
|
||||||
|
'(- : * options)'{-V,--version}'[Print version number]'
|
||||||
|
|
||||||
|
'(-a --attr-map -A --output-attr-map)'{-A,--output-attr-map}'[Shortcut for -a <file>.attrmap]'
|
||||||
|
'(-C --color-curve)'{-C,--color-curve}'[Generate palettes using GBC color curve]'
|
||||||
|
'(-D --debug)'{-D,--debug}'[Enable debug features]'
|
||||||
|
'(-f --fix -F --fix-and-save)'{-f,--fix}'[Fix input PNG into an indexed image]'
|
||||||
|
'(-f --fix -F --fix-and-save)'{-F,--fix-and-save}'[Like -f but also save CLI params within the PNG]'
|
||||||
|
'(-h --horizontal)'{-h,--horizontal}'[Lay out tiles horizontally instead of vertically]'
|
||||||
|
'(-m --mirror-tiles)'{-m,--mirror-tiles}'[Eliminate mirrored tiles from output]'
|
||||||
|
'(-p --palette -P --output-palette)'{-P,--output-palette}'[Shortcut for -p <file>.pal]'
|
||||||
|
'(-t --tilemap -T --output-tilemap)'{-T,--output-tilemap}'[Shortcut for -t <file>.tilemap]'
|
||||||
|
'(-u --unique-tiles)'{-u,--unique-tiles}'[Eliminate redundant tiles]'
|
||||||
|
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
|
||||||
|
|
||||||
|
'(-a --attr-map -A --output-attr-map)'{-a,--attr-map}'+[Generate a map of tile attributes (mirroring)]:attrmap file:_files'
|
||||||
|
'(-d --depth)'{-d,--depth}'+[Set bit depth]:bit depth:_depths'
|
||||||
|
'(-o --output)'{-o,--output}'+[Set output file]:output file:_files'
|
||||||
|
'(-p --palette -P --output-palette)'{-p,--palette}"+[Output the image's palette in little-endian native RGB555 format]:palette file:_files"
|
||||||
|
'(-t --tilemap -T --output-tilemap)'{-t,--tilemap}'+[Generate a map of tile indices]:tilemap file:_files'
|
||||||
|
'(-x --trim-end)'{-x,--trim-end}'+[Trim end of output by this many tiles]:tile count:'
|
||||||
|
|
||||||
|
'*'":input png files:_files -g '*.png'"
|
||||||
|
)
|
||||||
|
_arguments -s -S : $args
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#compdef rgblink
|
||||||
|
|
||||||
|
local args=(
|
||||||
|
# Arguments are listed here in the same order as in the manual, except for the version
|
||||||
|
'(- : * options)'{-V,--version}'[Print version number]'
|
||||||
|
|
||||||
|
'(-d --dmg)'{-d,--dmg}'[Enable DMG mode (-w + no VRAM banking)]'
|
||||||
|
'(-t --tiny)'{-t,--tiny}'[Enable tiny mode, disabling ROM banking]'
|
||||||
|
'(-v --verbose)'{-v,--verbose}'[Enable verbose output]'
|
||||||
|
'(-w --wramx)'{-w,--wramx}'[Disable WRAM banking]'
|
||||||
|
|
||||||
|
'(-l --linkerscript)'{-l,--linkerscript}"+[Use a linker script]:linker script:_files -g '*.link'"
|
||||||
|
'(-m --map)'{-m,--map}"+[Produce a map file]:map file:_files -g '*.map'"
|
||||||
|
'(-n --sym)'(-n,--sym)"+[Produce a symbol file]:sym file:_files -g '*.sym'"
|
||||||
|
'(-O --overlay)'{-O,--overlay}'+[Overlay sections over on top of bin file]:base overlay:_files'
|
||||||
|
'(-o --output)'{-o,--output}"+[Write ROM image to this file]:rom file:_files -g '*.{gb,sgb,gbc}'"
|
||||||
|
'(-p --pad-value)'{-p,--pad-value}'+[Set padding byte]:padding byte:'
|
||||||
|
'(-s --smart)'{-s,--smart}'+[!BROKEN! Perform smart linking from this symbol]:symbol name:'
|
||||||
|
|
||||||
|
'*'":object files:_files -g '*.o'"
|
||||||
|
)
|
||||||
|
_arguments -s -S : $args
|
||||||
-1701
File diff suppressed because it is too large
Load Diff
@@ -1,36 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
|
|
||||||
<title>General Information</title>
|
|
||||||
<link rel="stylesheet" type="text/css" href="mandoc.css">
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<h1>RGBDS — Rednex Game Boy Development System</h1>
|
|
||||||
<h2>Table of Contents</h2>
|
|
||||||
<ol>
|
|
||||||
<li>General information
|
|
||||||
<ul>
|
|
||||||
<li><a href="rgbds.7.html">RGBDS general information</a></li>
|
|
||||||
<li><a href="rgbds.5.html">RGBDS object file format</a></li>
|
|
||||||
</ul>
|
|
||||||
<li>Language description
|
|
||||||
<ul>
|
|
||||||
<li><a href="rgbasm.5.html">RGBASM language description</a></li>
|
|
||||||
<li><a href="rgblink.5.html">RGBLINK linkerscript language description</a></li>
|
|
||||||
<li><a href="gbz80.7.html">GBZ80 CPU instruction set description</a></li>
|
|
||||||
</ul>
|
|
||||||
<li>Command line usage
|
|
||||||
<ul>
|
|
||||||
<li><a href="rgbasm.1.html">RGBASM command-line usage</a></li>
|
|
||||||
<li><a href="rgblink.1.html">RGBLINK command-line usage</a></li>
|
|
||||||
<li><a href="rgbfix.1.html">RGBFIX command-line usage</a></li>
|
|
||||||
<li><a href="rgbgfx.1.html">RGBGFX command-line usage</a></li>
|
|
||||||
</ul>
|
|
||||||
</ol>
|
|
||||||
<h2 id="GitHub Repository">GitHub Repository:</h2>
|
|
||||||
<ul>
|
|
||||||
<li><a href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a></li>
|
|
||||||
</ul>
|
|
||||||
</body>
|
|
||||||
-203
@@ -1,203 +0,0 @@
|
|||||||
/* $Id: mandoc.css,v 1.22 2017/07/16 18:45:00 schwarze Exp $ */
|
|
||||||
/*
|
|
||||||
* Standard style sheet for mandoc(1) -Thtml and man.cgi(8).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Global defaults. */
|
|
||||||
|
|
||||||
html { max-width: 100ex; }
|
|
||||||
body { font-family: Helvetica,Arial,sans-serif; }
|
|
||||||
table { margin-top: 0em;
|
|
||||||
margin-bottom: 0em; }
|
|
||||||
td { vertical-align: top; }
|
|
||||||
ul, ol, dl { margin-top: 0em;
|
|
||||||
margin-bottom: 0em; }
|
|
||||||
li, dt { margin-top: 1em; }
|
|
||||||
|
|
||||||
a.selflink { border-bottom: thin dotted;
|
|
||||||
color: inherit;
|
|
||||||
font: inherit;
|
|
||||||
text-decoration: inherit; }
|
|
||||||
* { clear: both }
|
|
||||||
|
|
||||||
/* Search form and search results. */
|
|
||||||
|
|
||||||
fieldset { border: thin solid silver;
|
|
||||||
border-radius: 1em;
|
|
||||||
text-align: center; }
|
|
||||||
input[name=expr] {
|
|
||||||
width: 25%; }
|
|
||||||
|
|
||||||
table.results { margin-top: 1em;
|
|
||||||
margin-left: 2em;
|
|
||||||
font-size: smaller; }
|
|
||||||
|
|
||||||
/* Header and footer lines. */
|
|
||||||
|
|
||||||
table.head { width: 100%;
|
|
||||||
border-bottom: 1px dotted #808080;
|
|
||||||
margin-bottom: 1em;
|
|
||||||
font-size: smaller; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
td.head-rtitle {
|
|
||||||
text-align: right; }
|
|
||||||
span.Nd { }
|
|
||||||
|
|
||||||
table.foot { width: 100%;
|
|
||||||
border-top: 1px dotted #808080;
|
|
||||||
margin-top: 1em;
|
|
||||||
font-size: smaller; }
|
|
||||||
td.foot-os { text-align: right; }
|
|
||||||
|
|
||||||
/* Sections and paragraphs. */
|
|
||||||
|
|
||||||
div.manual-text {
|
|
||||||
margin-left: 5ex; }
|
|
||||||
h1.Sh { margin-top: 2ex;
|
|
||||||
margin-bottom: 1ex;
|
|
||||||
margin-left: -4ex;
|
|
||||||
font-size: 110%; }
|
|
||||||
h2.Ss { margin-top: 2ex;
|
|
||||||
margin-bottom: 1ex;
|
|
||||||
margin-left: -2ex;
|
|
||||||
font-size: 105%; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
a.Sx { }
|
|
||||||
a.Xr { }
|
|
||||||
|
|
||||||
/* Displays and lists. */
|
|
||||||
|
|
||||||
div.Bd { }
|
|
||||||
div.D1 { margin-left: 5ex; }
|
|
||||||
|
|
||||||
ul.Bl-bullet { list-style-type: disc;
|
|
||||||
padding-left: 1em; }
|
|
||||||
li.It-bullet { }
|
|
||||||
ul.Bl-dash { list-style-type: none;
|
|
||||||
padding-left: 0em; }
|
|
||||||
li.It-dash:before {
|
|
||||||
content: "\2014 "; }
|
|
||||||
ul.Bl-item { list-style-type: none;
|
|
||||||
padding-left: 0em; }
|
|
||||||
li.It-item { }
|
|
||||||
ul.Bl-compact > li {
|
|
||||||
margin-top: 0ex; }
|
|
||||||
|
|
||||||
ol.Bl-enum { padding-left: 2em; }
|
|
||||||
li.It-enum { }
|
|
||||||
ol.Bl-compact > li {
|
|
||||||
margin-top: 0ex; }
|
|
||||||
|
|
||||||
dl.Bl-diag { }
|
|
||||||
dt.It-diag { }
|
|
||||||
dd.It-diag { margin-left: 0ex; }
|
|
||||||
b.It-diag { font-style: normal; }
|
|
||||||
dl.Bl-hang { }
|
|
||||||
dt.It-hang { }
|
|
||||||
dd.It-hang { margin-left: 10.2ex; }
|
|
||||||
dl.Bl-inset { }
|
|
||||||
dt.It-inset { }
|
|
||||||
dd.It-inset { margin-left: 0ex; }
|
|
||||||
dl.Bl-ohang { }
|
|
||||||
dt.It-ohang { }
|
|
||||||
dd.It-ohang { margin-left: 0ex; }
|
|
||||||
dl.Bl-tag { margin-left: 10.2ex; }
|
|
||||||
dt.It-tag { float: left;
|
|
||||||
margin-top: 0ex;
|
|
||||||
margin-left: -10.2ex;
|
|
||||||
padding-right: 2ex;
|
|
||||||
vertical-align: top; }
|
|
||||||
dd.It-tag { clear: right;
|
|
||||||
width: 100%;
|
|
||||||
margin-top: 0ex;
|
|
||||||
margin-left: 0ex;
|
|
||||||
vertical-align: top;
|
|
||||||
overflow: auto; }
|
|
||||||
dl.Bl-compact > dt {
|
|
||||||
margin-top: 0ex; }
|
|
||||||
|
|
||||||
table.Bl-column { }
|
|
||||||
tr.It-column { }
|
|
||||||
td.It-column { margin-top: 1em; }
|
|
||||||
table.Bl-compact > tbody > tr > td {
|
|
||||||
margin-top: 0ex; }
|
|
||||||
|
|
||||||
cite.Rs { font-style: normal;
|
|
||||||
font-weight: normal; }
|
|
||||||
span.RsA { }
|
|
||||||
i.RsB { font-weight: normal; }
|
|
||||||
span.RsC { }
|
|
||||||
span.RsD { }
|
|
||||||
i.RsI { font-weight: normal; }
|
|
||||||
i.RsJ { font-weight: normal; }
|
|
||||||
span.RsN { }
|
|
||||||
span.RsO { }
|
|
||||||
span.RsP { }
|
|
||||||
span.RsQ { }
|
|
||||||
span.RsR { }
|
|
||||||
span.RsT { text-decoration: underline; }
|
|
||||||
a.RsU { }
|
|
||||||
span.RsV { }
|
|
||||||
|
|
||||||
span.eqn { }
|
|
||||||
table.tbl { }
|
|
||||||
|
|
||||||
/* Semantic markup for command line utilities. */
|
|
||||||
|
|
||||||
table.Nm { }
|
|
||||||
b.Nm { font-style: normal; }
|
|
||||||
b.Fl { font-style: normal; }
|
|
||||||
b.Cm { font-style: normal; }
|
|
||||||
var.Ar { font-style: italic;
|
|
||||||
font-weight: normal; }
|
|
||||||
span.Op { }
|
|
||||||
b.Ic { font-style: normal; }
|
|
||||||
code.Ev { font-style: normal;
|
|
||||||
font-weight: normal;
|
|
||||||
font-family: monospace; }
|
|
||||||
i.Pa { font-weight: normal; }
|
|
||||||
|
|
||||||
/* Semantic markup for function libraries. */
|
|
||||||
|
|
||||||
span.Lb { }
|
|
||||||
b.In { font-style: normal; }
|
|
||||||
a.In { }
|
|
||||||
b.Fd { font-style: normal; }
|
|
||||||
var.Ft { font-style: italic;
|
|
||||||
font-weight: normal; }
|
|
||||||
b.Fn { font-style: normal; }
|
|
||||||
var.Fa { font-style: italic;
|
|
||||||
font-weight: normal; }
|
|
||||||
var.Vt { font-style: italic;
|
|
||||||
font-weight: normal; }
|
|
||||||
var.Va { font-style: italic;
|
|
||||||
font-weight: normal; }
|
|
||||||
code.Dv { font-style: normal;
|
|
||||||
font-weight: normal;
|
|
||||||
font-family: monospace; }
|
|
||||||
code.Er { font-style: normal;
|
|
||||||
font-weight: normal;
|
|
||||||
font-family: monospace; }
|
|
||||||
|
|
||||||
/* Various semantic markup. */
|
|
||||||
|
|
||||||
span.An { }
|
|
||||||
a.Lk { }
|
|
||||||
a.Mt { }
|
|
||||||
b.Cd { font-style: normal; }
|
|
||||||
i.Ad { font-weight: normal; }
|
|
||||||
b.Ms { font-style: normal; }
|
|
||||||
span.St { }
|
|
||||||
a.Ux { }
|
|
||||||
|
|
||||||
/* Physical markup. */
|
|
||||||
|
|
||||||
.No { font-style: normal;
|
|
||||||
font-weight: normal; }
|
|
||||||
.Em { font-style: italic;
|
|
||||||
font-weight: normal; }
|
|
||||||
.Sy { font-style: normal;
|
|
||||||
font-weight: bold; }
|
|
||||||
.Li { font-style: normal;
|
|
||||||
font-weight: normal;
|
|
||||||
font-family: monospace; }
|
|
||||||
@@ -1,157 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
|
||||||
<title>RGBASM(1)</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table class="head">
|
|
||||||
<tr>
|
|
||||||
<td class="head-ltitle">RGBASM(1)</td>
|
|
||||||
<td class="head-vol">General Commands Manual</td>
|
|
||||||
<td class="head-rtitle">RGBASM(1)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="manual-text">
|
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbasm</b> — <span class="Nd" title="Nd">Game
|
|
||||||
Boy assembler</span>
|
|
||||||
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
|
||||||
<table class="Nm">
|
|
||||||
<tr>
|
|
||||||
<td><b class="Nm" title="Nm">rgbasm</b></td>
|
|
||||||
<td>[<span class="Op"><b class="Fl" title="Fl">-EhLVvw</b></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-b</b>
|
|
||||||
<var class="Ar" title="Ar">chars</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-D</b>
|
|
||||||
<var class="Ar" title="Ar">name</var>[<span class="Op">=<var class="Ar" title="Ar">value</var></span>]</span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-g</b>
|
|
||||||
<var class="Ar" title="Ar">chars</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-i</b>
|
|
||||||
<var class="Ar" title="Ar">path</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-M</b>
|
|
||||||
<var class="Ar" title="Ar">dependfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-o</b>
|
|
||||||
<var class="Ar" title="Ar">outfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-p</b>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></span>]
|
|
||||||
<var class="Ar" title="Ar">file</var></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
|
||||||
The <b class="Nm" title="Nm">rgbasm</b> program creates an object file from an
|
|
||||||
assembly source file. Its arguments are as follows:
|
|
||||||
<dl class="Bl-tag">
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#b"><b class="Fl" title="Fl" id="b">-b</b></a>
|
|
||||||
<var class="Ar" title="Ar">chars</var></dt>
|
|
||||||
<dd class="It-tag">Change the two characters used for binary constants. The
|
|
||||||
defaults are 01.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#D"><b class="Fl" title="Fl" id="D">-D</b></a>
|
|
||||||
<var class="Ar" title="Ar">name</var>[<span class="Op">=<var class="Ar" title="Ar">value</var></span>]</dt>
|
|
||||||
<dd class="It-tag">Add string symbol to the compiled source code. This is
|
|
||||||
equivalent to <var class="Ar" title="Ar">name</var>
|
|
||||||
<b class="Cm" title="Cm">EQUS</b>
|
|
||||||
“<var class="Ar" title="Ar">value</var>” in code. If a value
|
|
||||||
is not specified, a value of 1 is given.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#E"><b class="Fl" title="Fl" id="E">-E</b></a></dt>
|
|
||||||
<dd class="It-tag">Export all labels, including unreferenced and local
|
|
||||||
labels.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#g"><b class="Fl" title="Fl" id="g">-g</b></a>
|
|
||||||
<var class="Ar" title="Ar">chars</var></dt>
|
|
||||||
<dd class="It-tag">Change the four characters used for binary constants. The
|
|
||||||
defaults are 0123.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#h"><b class="Fl" title="Fl" id="h">-h</b></a></dt>
|
|
||||||
<dd class="It-tag">By default, <b class="Nm" title="Nm">rgbasm</b> inserts a
|
|
||||||
‘nop’ instruction immediately after any ‘halt’
|
|
||||||
instruction. The <b class="Fl" title="Fl">-h</b> option disables this
|
|
||||||
behavior.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#i"><b class="Fl" title="Fl" id="i">-i</b></a>
|
|
||||||
<var class="Ar" title="Ar">path</var></dt>
|
|
||||||
<dd class="It-tag">Add an include path.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#L"><b class="Fl" title="Fl" id="L">-L</b></a></dt>
|
|
||||||
<dd class="It-tag">Disable the optimization that turns loads of the form
|
|
||||||
<b class="Sy" title="Sy">LD [$FF00+n8],A</b> into the opcode
|
|
||||||
<b class="Sy" title="Sy">LDH [$FF00+n8],A</b> in order to have full
|
|
||||||
control of the result in the final ROM.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#M"><b class="Fl" title="Fl" id="M">-M</b></a>
|
|
||||||
<var class="Ar" title="Ar">dependfile</var></dt>
|
|
||||||
<dd class="It-tag">Print <a class="Xr" title="Xr">make(1)</a> dependencies to
|
|
||||||
<var class="Ar" title="Ar">dependfile</var>.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
|
|
||||||
<var class="Ar" title="Ar">outfile</var></dt>
|
|
||||||
<dd class="It-tag">Write an object file to the given filename.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></dt>
|
|
||||||
<dd class="It-tag">When padding an image, pad with this value. The default is
|
|
||||||
0x00.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
|
|
||||||
<dd class="It-tag">Print the version of the program and exit.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
|
|
||||||
<dd class="It-tag">Be verbose.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#w"><b class="Fl" title="Fl" id="w">-w</b></a></dt>
|
|
||||||
<dd class="It-tag">Disable warning output.</dd>
|
|
||||||
</dl>
|
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
|
||||||
Assembling a basic source file is simple:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="Bd" style="margin-left: 5.00ex;">
|
|
||||||
<pre class="Li">
|
|
||||||
$ rgbasm -o bar.o foo.asm
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The resulting object file is not yet a usable ROM image — it must first
|
|
||||||
be run through <a class="Xr" title="Xr">rgblink(1)</a> and
|
|
||||||
<a class="Xr" title="Xr">rgbfix(1)</a>.
|
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
|
||||||
ALSO</a></h1>
|
|
||||||
<a class="Xr" title="Xr">rgbasm(5)</a>, <a class="Xr" title="Xr">rgbfix(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgblink(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbds(5)</a>, <a class="Xr" title="Xr">rgbds(7)</a>,
|
|
||||||
<a class="Xr" title="Xr">gbz80(7)</a>
|
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbasm</b> was originally written by Carsten
|
|
||||||
Sørensen as part of the ASMotor package, and was later packaged in
|
|
||||||
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
|
||||||
<table class="foot">
|
|
||||||
<tr>
|
|
||||||
<td class="foot-date">February 24, 2018</td>
|
|
||||||
<td class="foot-os">RGBDS Manual</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
-1599
File diff suppressed because it is too large
Load Diff
@@ -1,309 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
|
||||||
<title>RGBDS(5)</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table class="head">
|
|
||||||
<tr>
|
|
||||||
<td class="head-ltitle">RGBDS(5)</td>
|
|
||||||
<td class="head-vol">File Formats Manual</td>
|
|
||||||
<td class="head-rtitle">RGBDS(5)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="manual-text">
|
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbds</b> — <span class="Nd" title="Nd">object
|
|
||||||
file format documentation</span>
|
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
|
||||||
This is the description of the object files used by
|
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a> and
|
|
||||||
<a class="Xr" title="Xr">rgblink(1)</a>. Please, note that the specifications
|
|
||||||
may change. This toolchain is in development and new features may require
|
|
||||||
adding more information to the current format, or modifying some fields, which
|
|
||||||
would break compatibility with older versions.
|
|
||||||
<h1 class="Sh" title="Sh" id="FILE_STRUCTURE"><a class="selflink" href="#FILE_STRUCTURE">FILE
|
|
||||||
STRUCTURE</a></h1>
|
|
||||||
The following types are used:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<var class="Ar" title="Ar">LONG</var> is a 32‐bit integer stored in
|
|
||||||
little‐endian format (Intel). <var class="Ar" title="Ar">BYTE</var> is
|
|
||||||
an 8‐bit integer. <var class="Ar" title="Ar">STRING</var> is a
|
|
||||||
0‐terminated string of <var class="Ar" title="Ar">BYTE</var>.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="Bd" style="margin-left: 0.00ex;">
|
|
||||||
<pre class="Li">
|
|
||||||
; Header
|
|
||||||
|
|
||||||
BYTE ID[4] ; "RGB6"
|
|
||||||
LONG NumberOfSymbols ; The number of symbols used in this file
|
|
||||||
LONG NumberOfSections ; The number of sections used in this file
|
|
||||||
|
|
||||||
; Symbols
|
|
||||||
|
|
||||||
REPT NumberOfSymbols ; Number of symbols defined in this object file.
|
|
||||||
|
|
||||||
STRING Name ; The name of this symbol. Local symbols are stored
|
|
||||||
; as "Scope.Symbol".
|
|
||||||
|
|
||||||
BYTE Type ; 0 = LOCAL symbol only used in this file.
|
|
||||||
; 1 = IMPORT this symbol from elsewhere (unused).
|
|
||||||
; 2 = EXPORT this symbol to other objects.
|
|
||||||
|
|
||||||
IF Type != 1 ; If symbol is defined in this object file.
|
|
||||||
|
|
||||||
STRING FileName ; File where the symbol is defined.
|
|
||||||
|
|
||||||
LONG LineNum ; Line number in the file where the symbol is defined.
|
|
||||||
|
|
||||||
LONG SectionID ; The section number (of this object file) in which
|
|
||||||
; this symbol is defined. If it doesn't belong to any
|
|
||||||
; specific section (like a constant), this field has
|
|
||||||
; the value -1.
|
|
||||||
|
|
||||||
LONG Value ; The symbols value. It's the offset into that
|
|
||||||
; symbol's section.
|
|
||||||
|
|
||||||
ENDC
|
|
||||||
|
|
||||||
ENDR
|
|
||||||
|
|
||||||
; Sections
|
|
||||||
|
|
||||||
REPT NumberOfSections
|
|
||||||
STRING Name ; Name of the section
|
|
||||||
|
|
||||||
LONG Size ; Size in bytes of this section
|
|
||||||
|
|
||||||
BYTE Type ; 0 = WRAM0
|
|
||||||
; 1 = VRAM
|
|
||||||
; 2 = ROMX
|
|
||||||
; 3 = ROM0
|
|
||||||
; 4 = HRAM
|
|
||||||
; 5 = WRAMX
|
|
||||||
; 6 = SRAM
|
|
||||||
; 7 = OAM
|
|
||||||
|
|
||||||
LONG Org ; Address to fix this section at. -1 if the linker should
|
|
||||||
; decide (floating address).
|
|
||||||
|
|
||||||
LONG Bank ; Bank to load this section into. -1 if the linker should
|
|
||||||
; decide (floating bank). This field is only valid for ROMX,
|
|
||||||
; VRAM, WRAMX and SRAM sections.
|
|
||||||
|
|
||||||
LONG Align ; Alignment of this section (expressed as number of low bits
|
|
||||||
; to leave as 0). -1 if not defined.
|
|
||||||
|
|
||||||
IF (Type == ROMX) || (Type == ROM0) ; Sections that can contain data.
|
|
||||||
|
|
||||||
BYTE Data[Size] ; Raw data of the section.
|
|
||||||
|
|
||||||
LONG NumberOfPatches ; Number of patches to apply.
|
|
||||||
|
|
||||||
; These types of sections may have patches
|
|
||||||
|
|
||||||
REPT NumberOfPatches
|
|
||||||
|
|
||||||
STRING SourceFile ; Name of the source file (for printing error
|
|
||||||
; messages).
|
|
||||||
|
|
||||||
LONG Line ; The line of the source file.
|
|
||||||
|
|
||||||
LONG Offset ; Offset into the section where patch should
|
|
||||||
; be applied (in bytes).
|
|
||||||
|
|
||||||
BYTE Type ; 0 = BYTE patch.
|
|
||||||
; 1 = little endian WORD patch.
|
|
||||||
; 2 = little endian LONG patch.
|
|
||||||
; 3 = JR offset value BYTE patch.
|
|
||||||
|
|
||||||
LONG RPNSize ; Size of the buffer with the RPN.
|
|
||||||
; expression.
|
|
||||||
|
|
||||||
BYTE RPN[RPNSize] ; RPN expression. Definition below.
|
|
||||||
|
|
||||||
ENDR
|
|
||||||
|
|
||||||
ENDC
|
|
||||||
|
|
||||||
ENDR
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<h2 class="Ss" title="Ss" id="RPN_DATA"><a class="selflink" href="#RPN_DATA">RPN
|
|
||||||
DATA</a></h2>
|
|
||||||
Expressions in the object file are stored as RPN. This is an expression of the
|
|
||||||
form “2 5 +”. This will first push the value “2”
|
|
||||||
to the stack. Then “5”. The “+” operator pops two
|
|
||||||
arguments from the stack, adds them, and then pushes the result on the stack,
|
|
||||||
effectively replacing the two top arguments with their sum. In the RGB format,
|
|
||||||
RPN expressions are stored as BYTEs with some bytes being special prefixes for
|
|
||||||
integers and symbols.
|
|
||||||
<table class="Bl-column" style="margin-left: 6.00ex;">
|
|
||||||
<colgroup>
|
|
||||||
<col style="width: 15.00ex;"/>
|
|
||||||
<col style="min-width: 10.00ex;"/>
|
|
||||||
</colgroup>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><b class="Sy" title="Sy">Value</b></td>
|
|
||||||
<td class="It-column"><b class="Sy" title="Sy">Meaning</b></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$00"><code class="Li" id="$00">$00</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#+_operator"><code class="Li" id="+_operator">+
|
|
||||||
operator</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$01"><code class="Li" id="$01">$01</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#-_operator"><code class="Li" id="-_operator">-
|
|
||||||
operator</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$02"><code class="Li" id="$02">$02</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#*_operator"><code class="Li" id="*_operator">*
|
|
||||||
operator</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$03"><code class="Li" id="$03">$03</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#/_operator"><code class="Li" id="/_operator">/
|
|
||||||
operator</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$04"><code class="Li" id="$04">$04</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#%_operator"><code class="Li" id="%_operator">%
|
|
||||||
operator</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$05"><code class="Li" id="$05">$05</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#unary_-"><code class="Li" id="unary_-">unary
|
|
||||||
-</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$10"><code class="Li" id="$10">$10</code></a></td>
|
|
||||||
<td class="It-column">|
|
|
||||||
<a class="selflink" href="#operator"><code class="Li" id="operator">operator</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$11"><code class="Li" id="$11">$11</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#&_operator"><code class="Li" id="&_operator">&
|
|
||||||
operator</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$12"><code class="Li" id="$12">$12</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#^_operator"><code class="Li" id="^_operator">^
|
|
||||||
operator</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$13"><code class="Li" id="$13">$13</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#unary_~"><code class="Li" id="unary_~">unary
|
|
||||||
~</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$21"><code class="Li" id="$21">$21</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#&&_comparison"><code class="Li" id="&&_comparison">&&
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$22"><code class="Li" id="$22">$22</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#||_comparison"><code class="Li" id="||_comparison">||
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$23"><code class="Li" id="$23">$23</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#unary"><code class="Li" id="unary">unary</code></a>!</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$30"><code class="Li" id="$30">$30</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#==_comparison"><code class="Li" id="==_comparison">==
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$31"><code class="Li" id="$31">$31</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#!=_comparison"><code class="Li" id="!=_comparison">!=
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$32"><code class="Li" id="$32">$32</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#>_comparison"><code class="Li" id=">_comparison">>
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$33"><code class="Li" id="$33">$33</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#<_comparison"><code class="Li" id="<_comparison"><
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$34"><code class="Li" id="$34">$34</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#>=_comparison"><code class="Li" id=">=_comparison">>=
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$35"><code class="Li" id="$35">$35</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#<=_comparison"><code class="Li" id="<=_comparison"><=
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$40"><code class="Li" id="$40">$40</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#<<_comparison"><code class="Li" id="<<_comparison"><<
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$41"><code class="Li" id="$41">$41</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#>>_comparison"><code class="Li" id=">>_comparison">>>
|
|
||||||
comparison</code></a></td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$50"><code class="Li" id="$50">$50</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#BANK(symbol),"><code class="Li" id="BANK(symbol),">BANK(symbol),</code></a>
|
|
||||||
a <var class="Ar" title="Ar">LONG</var> Symbol ID follows.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$51"><code class="Li" id="$51">$51</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#BANK(section_name),"><code class="Li" id="BANK(section_name),">BANK(section_name),</code></a>
|
|
||||||
a null-terminated string follows.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$52"><code class="Li" id="$52">$52</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#Current_BANK()"><code class="Li" id="Current_BANK()">Current
|
|
||||||
BANK()</code></a>.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$60"><code class="Li" id="$60">$60</code></a></td>
|
|
||||||
<td class="It-column"><a class="selflink" href="#HRAMCheck."><code class="Li" id="HRAMCheck.">HRAMCheck.</code></a>
|
|
||||||
Check if the value is in HRAM, AND it with 0xFF.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$80"><code class="Li" id="$80">$80</code></a></td>
|
|
||||||
<td class="It-column"><var class="Ar" title="Ar">LONG</var> integer
|
|
||||||
follows.</td>
|
|
||||||
</tr>
|
|
||||||
<tr class="It-column">
|
|
||||||
<td class="It-column"><a class="selflink" href="#$81"><code class="Li" id="$81">$81</code></a></td>
|
|
||||||
<td class="It-column"><var class="Ar" title="Ar">LONG</var> Symbol ID
|
|
||||||
follows.</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
|
||||||
ALSO</a></h1>
|
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
|
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbds</b> was originally written by Carsten
|
|
||||||
Sørensen as part of the ASMotor package, and was later packaged in
|
|
||||||
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
|
||||||
<table class="foot">
|
|
||||||
<tr>
|
|
||||||
<td class="foot-date">January 26, 2018</td>
|
|
||||||
<td class="foot-os">RGBDS Manual</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
|
||||||
<title>RGBDS(7)</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table class="head">
|
|
||||||
<tr>
|
|
||||||
<td class="head-ltitle">RGBDS(7)</td>
|
|
||||||
<td class="head-vol">Miscellaneous Information Manual</td>
|
|
||||||
<td class="head-rtitle">RGBDS(7)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="manual-text">
|
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbds</b> — <span class="Nd" title="Nd">Rednex
|
|
||||||
Game Boy Development System</span>
|
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
|
||||||
To get a working ROM image from a single assembly source file:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="Bd" style="margin-left: 5.00ex;">
|
|
||||||
<pre class="Li">
|
|
||||||
$ rgbasm -o bar.o foo.asm
|
|
||||||
$ rgblink -o baz.gb bar.o
|
|
||||||
$ rgbfix -v -p 0 baz.gb
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
|
||||||
ALSO</a></h1>
|
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgbfix(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgblink(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbds(5)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
|
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
|
||||||
<dl class="Bl-ohang">
|
|
||||||
<dt class="It-ohang"></dt>
|
|
||||||
<dd class="It-ohang">1997, Carsten Sørensen (AKA SurfSmurf) writes
|
|
||||||
ASMotor as a general-purpose assembler/linker system for DOS/Win32.</dd>
|
|
||||||
<dt class="It-ohang"></dt>
|
|
||||||
<dd class="It-ohang">1999, Justin Lloyd (AKA Otaku no Zoku) adapts ASMotor to
|
|
||||||
read and produce GBZ80 assembly/machine code, and releases this version as
|
|
||||||
RGBDS.</dd>
|
|
||||||
<dt class="It-ohang"></dt>
|
|
||||||
<dd class="It-ohang">2009, Vegard Nossum adapts the code to be more UNIX-like
|
|
||||||
and releases this version as rgbds-linux on GitHub.</dd>
|
|
||||||
<dt class="It-ohang"></dt>
|
|
||||||
<dd class="It-ohang">2010, Anthony J. Bentley forks that repository. The fork
|
|
||||||
becomes the reference implementation of rgbds.</dd>
|
|
||||||
<dt class="It-ohang"></dt>
|
|
||||||
<dd class="It-ohang">2017, Bentley's repository is moved to a neutral name. It
|
|
||||||
is now maintained by a number of contributors at
|
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</dd>
|
|
||||||
<dt class="It-ohang"></dt>
|
|
||||||
<dd class="It-ohang">2018, codebase relicensed under the MIT license.</dd>
|
|
||||||
</dl>
|
|
||||||
</div>
|
|
||||||
<table class="foot">
|
|
||||||
<tr>
|
|
||||||
<td class="foot-date">March 7, 2018</td>
|
|
||||||
<td class="foot-os">RGBDS Manual</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,213 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
|
||||||
<title>RGBFIX(1)</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table class="head">
|
|
||||||
<tr>
|
|
||||||
<td class="head-ltitle">RGBFIX(1)</td>
|
|
||||||
<td class="head-vol">General Commands Manual</td>
|
|
||||||
<td class="head-rtitle">RGBFIX(1)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="manual-text">
|
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbfix</b> — <span class="Nd" title="Nd">Game
|
|
||||||
Boy checksum fixer</span>
|
|
||||||
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
|
||||||
<table class="Nm">
|
|
||||||
<tr>
|
|
||||||
<td><b class="Nm" title="Nm">rgbfix</b></td>
|
|
||||||
<td>[<span class="Op"><b class="Fl" title="Fl">-CcjsVv</b></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-f</b>
|
|
||||||
<var class="Ar" title="Ar">fix_spec</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-i</b>
|
|
||||||
<var class="Ar" title="Ar">game_id</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-k</b>
|
|
||||||
<var class="Ar" title="Ar">licensee_str</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-l</b>
|
|
||||||
<var class="Ar" title="Ar">licensee_id</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-m</b>
|
|
||||||
<var class="Ar" title="Ar">mbc_type</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-n</b>
|
|
||||||
<var class="Ar" title="Ar">rom_version</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-p</b>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-r</b>
|
|
||||||
<var class="Ar" title="Ar">ram_size</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-t</b>
|
|
||||||
<var class="Ar" title="Ar">title_str</var></span>]
|
|
||||||
<var class="Ar" title="Ar">file</var></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
|
||||||
The <b class="Nm" title="Nm">rgbfix</b> program changes headers of Game Boy ROM
|
|
||||||
images. It also performs other filetype operations, such as truncation. The
|
|
||||||
arguments are as follows:
|
|
||||||
<dl class="Bl-tag">
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#C"><b class="Fl" title="Fl" id="C">-C</b></a></dt>
|
|
||||||
<dd class="It-tag">Set the Game Boy Color–only flag:
|
|
||||||
<i class="Ad">0x143</i> = 0xC0. If both this and the
|
|
||||||
<b class="Fl" title="Fl">-c</b> flag are set, this takes precedence.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#c"><b class="Fl" title="Fl" id="c">-c</b></a></dt>
|
|
||||||
<dd class="It-tag">Set the Game Boy Color–compatible flag:
|
|
||||||
<i class="Ad">0x143</i> = 0x80. If both this and the
|
|
||||||
<b class="Fl" title="Fl">-C</b> flag are set,
|
|
||||||
<b class="Fl" title="Fl">-C</b> takes precedence.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#f"><b class="Fl" title="Fl" id="f">-f</b></a>
|
|
||||||
<var class="Ar" title="Ar">fix_spec</var></dt>
|
|
||||||
<dd class="It-tag">Fix certain header values that the Game Boy checks for
|
|
||||||
correctness. Alternatively, intentionally trash these values by writing
|
|
||||||
their binary inverse instead. <var class="Ar" title="Ar">fix_spec</var> is
|
|
||||||
a string containing any combination of the following characters:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<dl class="Bl-tag Bl-compact" style="margin-left: 5.40ex;">
|
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#l"><b class="Cm" title="Cm" id="l">l</b></a></dt>
|
|
||||||
<dd class="It-tag">Fix the Nintendo logo
|
|
||||||
(<i class="Ad">0x104</i>–<i class="Ad">0x133</i>).</dd>
|
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#L"><b class="Cm" title="Cm" id="L">L</b></a></dt>
|
|
||||||
<dd class="It-tag">Trash the Nintendo logo.</dd>
|
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#h"><b class="Cm" title="Cm" id="h">h</b></a></dt>
|
|
||||||
<dd class="It-tag">Fix the header checksum (<i class="Ad">0x14D</i>).</dd>
|
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#H"><b class="Cm" title="Cm" id="H">H</b></a></dt>
|
|
||||||
<dd class="It-tag">Trash the header checksum.</dd>
|
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#g"><b class="Cm" title="Cm" id="g">g</b></a></dt>
|
|
||||||
<dd class="It-tag">Fix the global checksum
|
|
||||||
(<i class="Ad">0x14E</i>–<i class="Ad">0x14F</i>).</dd>
|
|
||||||
<dt class="It-tag" style="margin-left: -5.40ex;"><a class="selflink" href="#G"><b class="Cm" title="Cm" id="G">G</b></a></dt>
|
|
||||||
<dd class="It-tag">Trash the global checksum.</dd>
|
|
||||||
</dl>
|
|
||||||
</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#i"><b class="Fl" title="Fl" id="i">-i</b></a>
|
|
||||||
<var class="Ar" title="Ar">game_id</var></dt>
|
|
||||||
<dd class="It-tag">Set the game ID string
|
|
||||||
(<i class="Ad">0x13F</i>–<i class="Ad">0x142</i>) to a given string
|
|
||||||
of exactly 4 characters. If both this and the title are set, the game ID
|
|
||||||
will overwrite the overlapping portion of the title.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#j"><b class="Fl" title="Fl" id="j">-j</b></a></dt>
|
|
||||||
<dd class="It-tag">Set the non-Japanese region flag: <i class="Ad">0x14A</i> =
|
|
||||||
1.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#k"><b class="Fl" title="Fl" id="k">-k</b></a>
|
|
||||||
<var class="Ar" title="Ar">licensee_str</var></dt>
|
|
||||||
<dd class="It-tag">Set the new licensee string
|
|
||||||
(<i class="Ad">0x144</i>–<i class="Ad">0x145</i>) to a given
|
|
||||||
string, truncated to at most two characters.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#l"><b class="Fl" title="Fl" id="l">-l</b></a>
|
|
||||||
<var class="Ar" title="Ar">licensee_id</var></dt>
|
|
||||||
<dd class="It-tag">Set the old licensee code, <i class="Ad">0x14B</i>, to a
|
|
||||||
given value from 0 to 0xFF. This value is deprecated and should be set to
|
|
||||||
0x33 in all new software.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#m"><b class="Fl" title="Fl" id="m">-m</b></a>
|
|
||||||
<var class="Ar" title="Ar">mbc_type</var></dt>
|
|
||||||
<dd class="It-tag">Set the MBC type, <i class="Ad">0x147</i>, to a given value
|
|
||||||
from 0 to 0xFF.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#n"><b class="Fl" title="Fl" id="n">-n</b></a>
|
|
||||||
<var class="Ar" title="Ar">rom_version</var></dt>
|
|
||||||
<dd class="It-tag">Set the ROM version, <i class="Ad">0x14C</i>, to a given
|
|
||||||
value from 0 to 0xFF.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></dt>
|
|
||||||
<dd class="It-tag">Pad the image to a valid size with a given pad value from 0
|
|
||||||
to 0xFF. <b class="Nm" title="Nm">rgbfix</b> will automatically pick a
|
|
||||||
size from 32KiB, 64KiB, 128KiB, ..., 8192KiB and give a warning
|
|
||||||
thereafter. The cartridge size byte (<i class="Ad">0x148</i>) will be
|
|
||||||
changed to reflect this new size.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#r"><b class="Fl" title="Fl" id="r">-r</b></a>
|
|
||||||
<var class="Ar" title="Ar">ram_size</var></dt>
|
|
||||||
<dd class="It-tag">Set the RAM size, <i class="Ad">0x149</i>, to a given value
|
|
||||||
from 0 to 0xFF.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#s"><b class="Fl" title="Fl" id="s">-s</b></a></dt>
|
|
||||||
<dd class="It-tag">Set the SGB flag: <i class="Ad">0x146</i> = 3.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a>
|
|
||||||
<var class="Ar" title="Ar">title</var></dt>
|
|
||||||
<dd class="It-tag">Set the title string
|
|
||||||
(<i class="Ad">0x134</i>–<i class="Ad">0x143</i>) to a given
|
|
||||||
string, truncated to at most 16 characters. It is recommended to use 15
|
|
||||||
characters instead, to avoid clashing with the CGB flag
|
|
||||||
(<b class="Fl" title="Fl">-c</b> or <b class="Fl" title="Fl">-C</b>). If
|
|
||||||
both this and the game ID are set, the game ID will overwrite the
|
|
||||||
overlapping portion of the title.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
|
|
||||||
<dd class="It-tag">Print the version of the program and exit.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
|
|
||||||
<dd class="It-tag">Equivalent to <b class="Fl" title="Fl">-f</b>
|
|
||||||
<b class="Cm" title="Cm">lhg</b>.</dd>
|
|
||||||
</dl>
|
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
|
||||||
Most values in the ROM header are only cosmetic. The bare minimum requirements
|
|
||||||
for a workable image are checksums, the Nintendo logo, and (if needed) the
|
|
||||||
CGB/SGB flags. It is a good idea to pad the image to a valid size as well
|
|
||||||
(“valid” meaning a multiple of 32KiB).
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The following will make a plain, no-color Game Boy game without checking for a
|
|
||||||
valid size:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgbfix -v foo.gb</div>
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The following will make a SGB-enabled, color-enabled game with a title of
|
|
||||||
“foobar”, and pad it to a multiple of 32KiB. (The Game Boy
|
|
||||||
itself does not use the title, but some emulators or ROM managers might.)
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgbfix -vcs -l 0x33 -p 0 -t foobar baz.gb</div>
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The following will duplicate the header (sans global checksum) of the game
|
|
||||||
“Survival Kids”:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgbfix -cjsv -k A4 -l 0x33 -m 0x1B -p 0xFF -r 3 -t
|
|
||||||
SURVIVALKIDAVKE SurvivalKids.gbc</div>
|
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
|
||||||
ALSO</a></h1>
|
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>
|
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbfix</b> was originally released by Carsten
|
|
||||||
Sørensen as a standalone program called gbfix, and was later packaged
|
|
||||||
in RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
|
||||||
<table class="foot">
|
|
||||||
<tr>
|
|
||||||
<td class="foot-date">March 11, 2018</td>
|
|
||||||
<td class="foot-os">RGBDS Manual</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
|
||||||
<title>RGBGFX(1)</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table class="head">
|
|
||||||
<tr>
|
|
||||||
<td class="head-ltitle">RGBGFX(1)</td>
|
|
||||||
<td class="head-vol">General Commands Manual</td>
|
|
||||||
<td class="head-rtitle">RGBGFX(1)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="manual-text">
|
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbgfx</b> — <span class="Nd" title="Nd">Game
|
|
||||||
Boy graphics converter</span>
|
|
||||||
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
|
||||||
<table class="Nm">
|
|
||||||
<tr>
|
|
||||||
<td><b class="Nm" title="Nm">rgbgfx</b></td>
|
|
||||||
<td>[<span class="Op"><b class="Fl" title="Fl">-DfFhPTVv</b></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-o</b>
|
|
||||||
<var class="Ar" title="Ar">outfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-d</b>
|
|
||||||
<var class="Ar" title="Ar">depth</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-p</b>
|
|
||||||
<var class="Ar" title="Ar">palfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-t</b>
|
|
||||||
<var class="Ar" title="Ar">mapfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-x</b>
|
|
||||||
<var class="Ar" title="Ar">tiles</var></span>]
|
|
||||||
<var class="Ar" title="Ar">file</var></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
|
||||||
The <b class="Nm" title="Nm">rgbgfx</b> program converts PNG images into the
|
|
||||||
Nintendo Game Boy's planar tile format.
|
|
||||||
<div style="height: 1.00em;"> </div>
|
|
||||||
The resulting colors and their palette indices are determined differently
|
|
||||||
depending on the input PNG file:
|
|
||||||
<ul class="Bl-dash">
|
|
||||||
<li class="It-dash">If the file has an embedded palette, that palette's color
|
|
||||||
and order are used.</li>
|
|
||||||
<li class="It-dash">If not, and the image only contains shades of gray, rgbgfx
|
|
||||||
maps them to the indices appropriate for each shade. Any undetermined
|
|
||||||
indices are set to respective default shades of gray. For example: if the
|
|
||||||
bit depth is 2 and the image contains light gray and black, they become
|
|
||||||
the second and fourth colors - and the first and third colors get set to
|
|
||||||
default white and dark gray. If the image has multiple shades that map to
|
|
||||||
the same index, the palette is instead determined as if the image had
|
|
||||||
color.</li>
|
|
||||||
<li class="It-dash">If the image has color (or the grayscale method failed),
|
|
||||||
the colors are sorted from lightest to darkest.</li>
|
|
||||||
</ul>
|
|
||||||
<div style="height: 1.00em;"> </div>
|
|
||||||
The input image may not contain more colors than the selected bit depth allows.
|
|
||||||
Transparent pixels are set to palette index 0.
|
|
||||||
<h1 class="Sh" title="Sh" id="ARGUMENTS"><a class="selflink" href="#ARGUMENTS">ARGUMENTS</a></h1>
|
|
||||||
<dl class="Bl-tag">
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#D"><b class="Fl" title="Fl" id="D">-D</b></a></dt>
|
|
||||||
<dd class="It-tag">Debug features are enabled.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#f"><b class="Fl" title="Fl" id="f">-f</b></a></dt>
|
|
||||||
<dd class="It-tag">Fix the input PNG file to be a correctly indexed
|
|
||||||
image.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#F"><b class="Fl" title="Fl" id="F">-F</b></a></dt>
|
|
||||||
<dd class="It-tag">Same as <b class="Fl" title="Fl">-f</b>, but additionally,
|
|
||||||
the supplied command line parameters are saved within the PNG and will be
|
|
||||||
loaded and automatically used next time.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#d"><b class="Fl" title="Fl" id="d">-d</b></a>
|
|
||||||
<var class="Ar" title="Ar">depth</var></dt>
|
|
||||||
<dd class="It-tag">The bit depth of the output image (either 1 or 2). By
|
|
||||||
default, the bit depth is 2 (two bits per pixel).</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#h"><b class="Fl" title="Fl" id="h">-h</b></a></dt>
|
|
||||||
<dd class="It-tag">Lay out tiles horizontally rather than vertically.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
|
|
||||||
<var class="Ar" title="Ar">outfile</var></dt>
|
|
||||||
<dd class="It-tag">The name of the output file.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
|
|
||||||
<var class="Ar" title="Ar">palfile</var></dt>
|
|
||||||
<dd class="It-tag">Output the image's palette in standard GBC palette format -
|
|
||||||
bytes (8 bytes for two bits per pixel, 4 bytes for one bit per pixel)
|
|
||||||
containing the RGB15 values in little-endian byte order. If the palette
|
|
||||||
contains too few colors, the remaining entries are set to black.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#P"><b class="Fl" title="Fl" id="P">-P</b></a></dt>
|
|
||||||
<dd class="It-tag">Same as <b class="Fl" title="Fl">-p</b>, but the palette
|
|
||||||
file output name is made by taking the input PNG file's filename, removing
|
|
||||||
the file extension, and appending <i class="Pa" title="Pa">.pal</i>.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a>
|
|
||||||
<var class="Ar" title="Ar">mapfile</var></dt>
|
|
||||||
<dd class="It-tag">If any tiles are the same, don't place the repeat tiles in
|
|
||||||
the output file, and make a tilemap file.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#T"><b class="Fl" title="Fl" id="T">-T</b></a></dt>
|
|
||||||
<dd class="It-tag">Same as <b class="Fl" title="Fl">-t</b>, but the tilemap
|
|
||||||
file output name is made by taking the input filename, removing the file
|
|
||||||
extension, and appending <i class="Pa" title="Pa">.tilemap</i>.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#u"><b class="Fl" title="Fl" id="u">-u</b></a></dt>
|
|
||||||
<dd class="It-tag">Truncate repeated tiles. Useful with tilemaps.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
|
|
||||||
<dd class="It-tag">Print the version of the program and exit.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#v"><b class="Fl" title="Fl" id="v">-v</b></a></dt>
|
|
||||||
<dd class="It-tag">Verbose. Print errors when the command line parameters and
|
|
||||||
the parameters in the PNG file don't match.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#x"><b class="Fl" title="Fl" id="x">-x</b></a>
|
|
||||||
<var class="Ar" title="Ar">tiles</var></dt>
|
|
||||||
<dd class="It-tag">Trim the end of the output file by this many tiles.</dd>
|
|
||||||
</dl>
|
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
|
||||||
The following will take a PNG file with a bit depth of 1, 2, or 8, and output
|
|
||||||
planar 2bpp data:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgbgfx -o out.2bpp in.png</div>
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The following creates a planar 2bpp file with only unique tiles, and its tilemap
|
|
||||||
<i class="Pa" title="Pa">out.tilemap</i>:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgbgfx -T -u -o out.2bpp in.png</div>
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The following will do nothing:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgbgfx in.png</div>
|
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
|
||||||
ALSO</a></h1>
|
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>, <a class="Xr" title="Xr">rgbasm(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgblink(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">gbz80(7)</a>
|
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgbgfx</b> was created by
|
|
||||||
<span class="An" title="An">stag019</span> to be included in RGBDS. It is now
|
|
||||||
maintained by a number of contributors at
|
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
|
||||||
<table class="foot">
|
|
||||||
<tr>
|
|
||||||
<td class="foot-date">January 26, 2018</td>
|
|
||||||
<td class="foot-os">RGBDS Manual</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,161 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
|
||||||
<title>RGBLINK(1)</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table class="head">
|
|
||||||
<tr>
|
|
||||||
<td class="head-ltitle">RGBLINK(1)</td>
|
|
||||||
<td class="head-vol">General Commands Manual</td>
|
|
||||||
<td class="head-rtitle">RGBLINK(1)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="manual-text">
|
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgblink</b> — <span class="Nd" title="Nd">Game
|
|
||||||
Boy linker</span>
|
|
||||||
<h1 class="Sh" title="Sh" id="SYNOPSIS"><a class="selflink" href="#SYNOPSIS">SYNOPSIS</a></h1>
|
|
||||||
<table class="Nm">
|
|
||||||
<tr>
|
|
||||||
<td><b class="Nm" title="Nm">rgblink</b></td>
|
|
||||||
<td>[<span class="Op"><b class="Fl" title="Fl">-dtVw</b></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-m</b>
|
|
||||||
<var class="Ar" title="Ar">mapfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-n</b>
|
|
||||||
<var class="Ar" title="Ar">symfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-O</b>
|
|
||||||
<var class="Ar" title="Ar">overlayfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-o</b>
|
|
||||||
<var class="Ar" title="Ar">outfile</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-p</b>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-s</b>
|
|
||||||
<var class="Ar" title="Ar">symbol</var></span>]
|
|
||||||
[<span class="Op"><b class="Fl" title="Fl">-l</b>
|
|
||||||
<var class="Ar" title="Ar">linkerscript</var></span>]
|
|
||||||
<var class="Ar" title="Ar">file ...</var></td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
|
||||||
The <b class="Nm" title="Nm">rgblink</b> program links objects created by
|
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a> into a single Game Boy ROM file.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
By default, ROM0 sections created by the assembler are placed in the 16KiB bank
|
|
||||||
0, and ROMX sections are placed in any bank except bank 0. If your ROM will
|
|
||||||
only be 32KiB, you can use the <b class="Fl" title="Fl">-t</b> option to
|
|
||||||
override this.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
Similarly, WRAM0 sections are placed in the first 4KiB of WRAM bank 0 and WRAMX
|
|
||||||
sections are placed in any bank except bank 0. If your ROM doesn't use banked
|
|
||||||
WRAM you can use option <b class="Fl" title="Fl">-w</b> option to override
|
|
||||||
this.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
Also, if your ROM is designed for DMG, you can make sure that you don't use any
|
|
||||||
prohibited section by using the option <b class="Fl" title="Fl">-d</b>, which
|
|
||||||
implies <b class="Fl" title="Fl">-w</b> but also prohibits the use of VRAM
|
|
||||||
bank 1.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The arguments are as follows:
|
|
||||||
<dl class="Bl-tag">
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#m"><b class="Fl" title="Fl" id="m">-m</b></a>
|
|
||||||
<var class="Ar" title="Ar">mapfile</var></dt>
|
|
||||||
<dd class="It-tag">Write a mapfile to the given filename.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#n"><b class="Fl" title="Fl" id="n">-n</b></a>
|
|
||||||
<var class="Ar" title="Ar">symfile</var></dt>
|
|
||||||
<dd class="It-tag">Write a symbol file to the given filename.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#O"><b class="Fl" title="Fl" id="O">-O</b></a>
|
|
||||||
<var class="Ar" title="Ar">overlayfile</var></dt>
|
|
||||||
<dd class="It-tag">The ROM image to overlay sections over. When an overlay ROM
|
|
||||||
is provided, all sections must be fixed. This may be used to patch an
|
|
||||||
existing binary.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#o"><b class="Fl" title="Fl" id="o">-o</b></a>
|
|
||||||
<var class="Ar" title="Ar">outfile</var></dt>
|
|
||||||
<dd class="It-tag">Write ROM image to the given filename.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#p"><b class="Fl" title="Fl" id="p">-p</b></a>
|
|
||||||
<var class="Ar" title="Ar">pad_value</var></dt>
|
|
||||||
<dd class="It-tag">When padding an image, pad with this value. The default is
|
|
||||||
0x00.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#s"><b class="Fl" title="Fl" id="s">-s</b></a>
|
|
||||||
<var class="Ar" title="Ar">symbol</var></dt>
|
|
||||||
<dd class="It-tag">???</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#w"><b class="Fl" title="Fl" id="w">-w</b></a></dt>
|
|
||||||
<dd class="It-tag">Expand the WRAM0 section size from 4KiB to the full 8KiB
|
|
||||||
assigned to WRAM and prohibit the use of WRAMX sections.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#d"><b class="Fl" title="Fl" id="d">-d</b></a></dt>
|
|
||||||
<dd class="It-tag">Enable DMG mode. Prohibit the use of sections that doesn't
|
|
||||||
exist on a DMG, such as WRAMX and VRAM bank 1. This option automatically
|
|
||||||
enables <b class="Fl" title="Fl">-w</b>.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#t"><b class="Fl" title="Fl" id="t">-t</b></a></dt>
|
|
||||||
<dd class="It-tag">Expand the ROM0 section size from 16KiB to the full 32KiB
|
|
||||||
assigned to ROM and prohibit the use of ROMX sections. Useful for ROMs
|
|
||||||
that fit in 32 KiB.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#l"><b class="Fl" title="Fl" id="l">-l</b></a>
|
|
||||||
<var class="Ar" title="Ar">linkerscript</var></dt>
|
|
||||||
<dd class="It-tag">Specify a linkerscript file that tells the linker how
|
|
||||||
sections must be placed in the ROM. This file has priority over the
|
|
||||||
attributes assigned in the source code, but they have to be consistent.
|
|
||||||
See <a class="Xr" title="Xr">rgblink(5)</a> for more information about its
|
|
||||||
format.</dd>
|
|
||||||
<dt class="It-tag"> </dt>
|
|
||||||
<dd class="It-tag"> </dd>
|
|
||||||
<dt class="It-tag"><a class="selflink" href="#V"><b class="Fl" title="Fl" id="V">-V</b></a></dt>
|
|
||||||
<dd class="It-tag">Print the version of the program and exit.</dd>
|
|
||||||
</dl>
|
|
||||||
<h1 class="Sh" title="Sh" id="EXAMPLES"><a class="selflink" href="#EXAMPLES">EXAMPLES</a></h1>
|
|
||||||
All you need for a basic ROM is an object file, which can be made into a ROM
|
|
||||||
image like so:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgblink -o bar.gb foo.o</div>
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The resulting bar.gb will not have correct checksums (unless you put them in the
|
|
||||||
assembly source). You should use <a class="Xr" title="Xr">rgbfix(1)</a> to fix
|
|
||||||
these so that the program will actually run in a Game Boy:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="D1">$ rgbfix -v bar.gb</div>
|
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
|
||||||
ALSO</a></h1>
|
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(5)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">rgbds(5)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>
|
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgblink</b> was originally written by Carsten
|
|
||||||
Sørensen as part of the ASMotor package, and was later packaged in
|
|
||||||
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
|
||||||
<table class="foot">
|
|
||||||
<tr>
|
|
||||||
<td class="foot-date">January 26, 2018</td>
|
|
||||||
<td class="foot-os">RGBDS Manual</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html>
|
|
||||||
<head>
|
|
||||||
<meta charset="utf-8"/>
|
|
||||||
<style>
|
|
||||||
table.head, table.foot { width: 100%; }
|
|
||||||
td.head-rtitle, td.foot-os { text-align: right; }
|
|
||||||
td.head-vol { text-align: center; }
|
|
||||||
div.Pp { margin: 1ex 0ex; }
|
|
||||||
</style>
|
|
||||||
<link rel="stylesheet" href="mandoc.css" type="text/css" media="all"/>
|
|
||||||
<title>RGBLINK(5)</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<table class="head">
|
|
||||||
<tr>
|
|
||||||
<td class="head-ltitle">RGBLINK(5)</td>
|
|
||||||
<td class="head-vol">File Formats Manual</td>
|
|
||||||
<td class="head-rtitle">RGBLINK(5)</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
<div class="manual-text">
|
|
||||||
<h1 class="Sh" title="Sh" id="NAME"><a class="selflink" href="#NAME">NAME</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgblink</b> —
|
|
||||||
<span class="Nd" title="Nd">linkerscript file format</span>
|
|
||||||
<h1 class="Sh" title="Sh" id="DESCRIPTION"><a class="selflink" href="#DESCRIPTION">DESCRIPTION</a></h1>
|
|
||||||
The linkerscript is an external file that allows the user to specify the order
|
|
||||||
of sections without the need for doing so before assembling each object file.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The placement of sections specified in the linkerscript is done before the
|
|
||||||
sections whose placement is defined in the source code.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
A linkerscript consists on a series of banks followed by a list of sections and,
|
|
||||||
optionally, commands. They can be lowercase or uppercase, it is ignored. Any
|
|
||||||
line can contain a comment starting with
|
|
||||||
‘<code class="Li">;</code>’ that ends at the end of the line:
|
|
||||||
<div class="Pp"></div>
|
|
||||||
<div class="Bd" style="margin-left: 5.00ex;">
|
|
||||||
<pre class="Li">
|
|
||||||
ROMX $F ; This is a comment
|
|
||||||
"Functions to read array"
|
|
||||||
ALIGN 8
|
|
||||||
"Array aligned to 256 bytes"
|
|
||||||
|
|
||||||
WRAMX 2
|
|
||||||
"Some variables"
|
|
||||||
</pre>
|
|
||||||
</div>
|
|
||||||
<div class="Pp"></div>
|
|
||||||
Numbers can be in decimal or hexadecimal format (the prefix is
|
|
||||||
‘<code class="Li">$</code>’). It is an error if any section name
|
|
||||||
or command are found before setting a bank.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
Files can be included by using the <var class="Ar" title="Ar">INCLUDE</var>
|
|
||||||
keyword followed by a string with the path of the file that has to be
|
|
||||||
included.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The possible bank types are: <b class="Sy" title="Sy">ROM0</b>,
|
|
||||||
<b class="Sy" title="Sy">ROMX</b>, <b class="Sy" title="Sy">VRAM</b>,
|
|
||||||
<b class="Sy" title="Sy">WRAM0</b>, <b class="Sy" title="Sy">WRAMX</b>,
|
|
||||||
<b class="Sy" title="Sy">OAM</b> and <b class="Sy" title="Sy">HRAM</b>. Types
|
|
||||||
<b class="Sy" title="Sy">ROMX</b>, <b class="Sy" title="Sy">VRAM</b>,
|
|
||||||
<b class="Sy" title="Sy">WRAMX</b> and <b class="Sy" title="Sy">SRAM</b> are
|
|
||||||
banked, which means that it is needed to specify a bank after the type.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
When a new bank statement is found, sections found after it will be placed right
|
|
||||||
from the beginning of that bank. If the linkerscript switches to a different
|
|
||||||
bank and then it comes back to the previous one it will continue from the last
|
|
||||||
address that was used.
|
|
||||||
<div class="Pp"></div>
|
|
||||||
The only two commands are <var class="Ar" title="Ar">ORG</var> and
|
|
||||||
<var class="Ar" title="Ar">ALIGN</var>:
|
|
||||||
<ul class="Bl-bullet">
|
|
||||||
<li class="It-bullet"><var class="Ar" title="Ar">ORG</var> sets the address in
|
|
||||||
which new sections will be placed. It can not be lower than the current
|
|
||||||
address.</li>
|
|
||||||
<li class="It-bullet"><var class="Ar" title="Ar">ALIGN</var> will increase the
|
|
||||||
address until it is aligned to the specified boundary (it tries to set to
|
|
||||||
0 the number of bits specified after the command:
|
|
||||||
<b class="Sy" title="Sy">ALIGN 8</b> will align to $100).</li>
|
|
||||||
</ul>
|
|
||||||
<div class="Pp"></div>
|
|
||||||
Note: The bank, alignment, address and type of sections can be specified both in
|
|
||||||
the source code and in the linkerscript. For a section to be able to be placed
|
|
||||||
with the linkerscript the bank must be left unassigned in the source code or
|
|
||||||
be the same as the one specified in the linkerscript. The address and
|
|
||||||
alignment musn't be set.
|
|
||||||
<h1 class="Sh" title="Sh" id="SEE_ALSO"><a class="selflink" href="#SEE_ALSO">SEE
|
|
||||||
ALSO</a></h1>
|
|
||||||
<a class="Xr" title="Xr">rgbasm(1)</a>, <a class="Xr" title="Xr">rgblink(1)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbfix(1)</a>, <a class="Xr" title="Xr">rgbds(5)</a>,
|
|
||||||
<a class="Xr" title="Xr">rgbds(7)</a>
|
|
||||||
<h1 class="Sh" title="Sh" id="HISTORY"><a class="selflink" href="#HISTORY">HISTORY</a></h1>
|
|
||||||
<b class="Nm" title="Nm">rgblink</b> was originally written by Carsten
|
|
||||||
Sørensen as part of the ASMotor package, and was later packaged in
|
|
||||||
RGBDS by Justin Lloyd. It is now maintained by a number of contributors at
|
|
||||||
<a class="Lk" title="Lk" href="https://github.com/rednex/rgbds">https://github.com/rednex/rgbds</a>.</div>
|
|
||||||
<table class="foot">
|
|
||||||
<tr>
|
|
||||||
<td class="foot-date">January 27, 2018</td>
|
|
||||||
<td class="foot-os">RGBDS Manual</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Contains some assembler-wide defines and externs
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RGBDS_ASM_ASM_H
|
|
||||||
#define RGBDS_ASM_ASM_H
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "asm/localasm.h"
|
|
||||||
#include "asm/symbol.h"
|
|
||||||
|
|
||||||
#define MAXUNIONS 128
|
|
||||||
#define MAXMACROARGS 256
|
|
||||||
#define MAXINCPATHS 128
|
|
||||||
|
|
||||||
extern int32_t nLineNo;
|
|
||||||
extern uint32_t nTotalLines;
|
|
||||||
extern uint32_t nPC;
|
|
||||||
extern uint32_t nPass;
|
|
||||||
extern uint32_t nIFDepth;
|
|
||||||
extern bool skipElif;
|
|
||||||
extern uint32_t nUnionDepth;
|
|
||||||
extern uint32_t unionStart[MAXUNIONS];
|
|
||||||
extern uint32_t unionSize[MAXUNIONS];
|
|
||||||
extern char tzCurrentFileName[_MAX_PATH + 1];
|
|
||||||
extern struct Section *pCurrentSection;
|
|
||||||
extern struct sSymbol *tHashedSymbols[HASHSIZE];
|
|
||||||
extern struct sSymbol *pPCSymbol;
|
|
||||||
extern bool oDontExpandStrings;
|
|
||||||
|
|
||||||
size_t symvaluetostring(char *dest, size_t maxLength, char *sym);
|
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_ASM_H */
|
|
||||||
+7
-12
@@ -11,17 +11,12 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define MAXCHARMAPS 512
|
struct Charmap *charmap_New(const char *name, const char *baseName);
|
||||||
#define CHARMAPLENGTH 16
|
void charmap_Delete(struct Charmap *charmap);
|
||||||
|
void charmap_Set(const char *name);
|
||||||
struct Charmap {
|
void charmap_Push(void);
|
||||||
int32_t count;
|
void charmap_Pop(void);
|
||||||
char input[MAXCHARMAPS][CHARMAPLENGTH + 1];
|
void charmap_Add(char *mapping, uint8_t value);
|
||||||
char output[MAXCHARMAPS];
|
size_t charmap_Convert(char const *input, uint8_t *output);
|
||||||
};
|
|
||||||
|
|
||||||
int32_t readUTF8Char(char *destination, char *source);
|
|
||||||
int32_t charmap_Add(char *input, uint8_t output);
|
|
||||||
int32_t charmap_Convert(char **input);
|
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_CHARMAP_H */
|
#endif /* RGBDS_ASM_CHARMAP_H */
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 1997-2021, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_ASM_FIXPOINT_H
|
||||||
|
#define RGBDS_ASM_FIXPOINT_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int32_t fix_Callback_PI(void);
|
||||||
|
void fix_Print(int32_t i);
|
||||||
|
int32_t fix_Sin(int32_t i);
|
||||||
|
int32_t fix_Cos(int32_t i);
|
||||||
|
int32_t fix_Tan(int32_t i);
|
||||||
|
int32_t fix_ASin(int32_t i);
|
||||||
|
int32_t fix_ACos(int32_t i);
|
||||||
|
int32_t fix_ATan(int32_t i);
|
||||||
|
int32_t fix_ATan2(int32_t i, int32_t j);
|
||||||
|
int32_t fix_Mul(int32_t i, int32_t j);
|
||||||
|
int32_t fix_Div(int32_t i, int32_t j);
|
||||||
|
int32_t fix_Pow(int32_t i, int32_t j);
|
||||||
|
int32_t fix_Log(int32_t i, int32_t j);
|
||||||
|
int32_t fix_Round(int32_t i);
|
||||||
|
int32_t fix_Ceil(int32_t i);
|
||||||
|
int32_t fix_Floor(int32_t i);
|
||||||
|
|
||||||
|
#endif /* RGBDS_ASM_FIXPOINT_H */
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_FORMAT_SPEC_H
|
||||||
|
#define RGBDS_FORMAT_SPEC_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
enum FormatState {
|
||||||
|
FORMAT_SIGN, // expects '+' or ' ' (optional)
|
||||||
|
FORMAT_PREFIX, // expects '#' (optional)
|
||||||
|
FORMAT_ALIGN, // expects '-' (optional)
|
||||||
|
FORMAT_WIDTH, // expects '0'-'9', max 255 (optional) (leading '0' indicates pad)
|
||||||
|
FORMAT_FRAC, // got '.', expects '0'-'9', max 255 (optional)
|
||||||
|
FORMAT_DONE, // got [duXxbofs] (required)
|
||||||
|
FORMAT_INVALID, // got unexpected character
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FormatSpec {
|
||||||
|
enum FormatState state;
|
||||||
|
int sign;
|
||||||
|
bool prefix;
|
||||||
|
bool alignLeft;
|
||||||
|
bool padZero;
|
||||||
|
uint8_t width;
|
||||||
|
bool hasFrac;
|
||||||
|
uint8_t fracWidth;
|
||||||
|
int type;
|
||||||
|
bool valid;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct StrFmtArg {
|
||||||
|
union {
|
||||||
|
uint32_t number;
|
||||||
|
char *string;
|
||||||
|
};
|
||||||
|
bool isNumeric;
|
||||||
|
};
|
||||||
|
|
||||||
|
#define INITIAL_STRFMT_ARG_SIZE 4
|
||||||
|
struct StrFmtArgList {
|
||||||
|
char *format;
|
||||||
|
size_t nbArgs;
|
||||||
|
size_t capacity;
|
||||||
|
struct StrFmtArg *args;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct FormatSpec fmt_NewSpec(void);
|
||||||
|
bool fmt_IsEmpty(struct FormatSpec const *fmt);
|
||||||
|
bool fmt_IsValid(struct FormatSpec const *fmt);
|
||||||
|
bool fmt_IsFinished(struct FormatSpec const *fmt);
|
||||||
|
void fmt_UseCharacter(struct FormatSpec *fmt, int c);
|
||||||
|
void fmt_FinishCharacters(struct FormatSpec *fmt);
|
||||||
|
void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value);
|
||||||
|
void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value);
|
||||||
|
|
||||||
|
#endif /* RGBDS_FORMAT_SPEC_H */
|
||||||
+57
-22
@@ -13,36 +13,71 @@
|
|||||||
#ifndef RGBDS_ASM_FSTACK_H
|
#ifndef RGBDS_ASM_FSTACK_H
|
||||||
#define RGBDS_ASM_FSTACK_H
|
#define RGBDS_ASM_FSTACK_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "asm/asm.h"
|
|
||||||
#include "asm/lexer.h"
|
#include "asm/lexer.h"
|
||||||
|
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
struct sContext {
|
struct FileStackNode {
|
||||||
YY_BUFFER_STATE FlexHandle;
|
struct FileStackNode *parent; /* Pointer to parent node, for error reporting */
|
||||||
struct sSymbol *pMacro;
|
/* Line at which the parent context was exited; meaningless for the root level */
|
||||||
struct sContext *pNext;
|
uint32_t lineNo;
|
||||||
char tzFileName[_MAX_PATH + 1];
|
|
||||||
char *tzMacroArgs[MAXMACROARGS + 1];
|
struct FileStackNode *next; /* Next node in the output linked list */
|
||||||
int32_t nLine;
|
bool referenced; /* If referenced, don't free! */
|
||||||
uint32_t nStatus;
|
uint32_t ID; /* Set only if referenced: ID within the object file, -1 if not output yet */
|
||||||
FILE *pFile;
|
|
||||||
char *pREPTBlock;
|
enum {
|
||||||
uint32_t nREPTBlockCount;
|
NODE_REPT,
|
||||||
uint32_t nREPTBlockSize;
|
NODE_FILE,
|
||||||
|
NODE_MACRO,
|
||||||
|
} type;
|
||||||
};
|
};
|
||||||
|
|
||||||
void fstk_RunInclude(char *tzFileName);
|
struct FileStackReptNode { /* NODE_REPT */
|
||||||
void fstk_RunMacroArg(int32_t s);
|
struct FileStackNode node;
|
||||||
void fstk_Init(char *s);
|
uint32_t reptDepth;
|
||||||
void fstk_Dump(void);
|
/* WARNING: if changing this type, change overflow check in `fstk_Init` */
|
||||||
void fstk_AddIncludePath(char *s);
|
uint32_t iters[]; /* REPT iteration counts since last named node, in reverse depth order */
|
||||||
uint32_t fstk_RunMacro(char *s);
|
};
|
||||||
void fstk_RunRept(uint32_t count);
|
|
||||||
FILE *fstk_FindFile(char *fname);
|
struct FileStackNamedNode { /* NODE_FILE, NODE_MACRO */
|
||||||
int32_t fstk_GetLine(void);
|
struct FileStackNode node;
|
||||||
|
char name[]; /* File name for files, file::macro name for macros */
|
||||||
|
};
|
||||||
|
|
||||||
|
extern size_t nMaxRecursionDepth;
|
||||||
|
|
||||||
|
struct MacroArgs;
|
||||||
|
|
||||||
|
void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo);
|
||||||
|
void fstk_DumpCurrent(void);
|
||||||
|
struct FileStackNode *fstk_GetFileStack(void);
|
||||||
|
/* The lifetime of the returned chars is until reaching the end of that file */
|
||||||
|
char const *fstk_GetFileName(void);
|
||||||
|
|
||||||
|
void fstk_AddIncludePath(char const *s);
|
||||||
|
/**
|
||||||
|
* @param path The user-provided file name
|
||||||
|
* @param fullPath The address of a pointer, which will be made to point at the full path
|
||||||
|
* The pointer's value must be a valid argument to `realloc`, including NULL
|
||||||
|
* @param size Current size of the buffer, or 0 if the pointer is NULL
|
||||||
|
* @return True if the file was found, false if no path worked
|
||||||
|
*/
|
||||||
|
bool fstk_FindFile(char const *path, char **fullPath, size_t *size);
|
||||||
|
|
||||||
|
bool yywrap(void);
|
||||||
|
void fstk_RunInclude(char const *path);
|
||||||
|
void fstk_RunMacro(char const *macroName, struct MacroArgs *args);
|
||||||
|
void fstk_RunRept(uint32_t count, int32_t nReptLineNo, char *body, size_t size);
|
||||||
|
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
||||||
|
int32_t reptLineNo, char *body, size_t size);
|
||||||
|
void fstk_StopRept(void);
|
||||||
|
bool fstk_Break(void);
|
||||||
|
|
||||||
|
void fstk_Init(char const *mainPath, size_t maxRecursionDepth);
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_FSTACK_H */
|
#endif /* RGBDS_ASM_FSTACK_H */
|
||||||
|
|||||||
+80
-56
@@ -9,69 +9,93 @@
|
|||||||
#ifndef RGBDS_ASM_LEXER_H
|
#ifndef RGBDS_ASM_LEXER_H
|
||||||
#define RGBDS_ASM_LEXER_H
|
#define RGBDS_ASM_LEXER_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#define LEXHASHSIZE (1 << 11)
|
|
||||||
#define MAXSTRLEN 255
|
#define MAXSTRLEN 255
|
||||||
|
|
||||||
struct sLexInitString {
|
struct LexerState;
|
||||||
char *tzName;
|
extern struct LexerState *lexerState;
|
||||||
uint32_t nToken;
|
extern struct LexerState *lexerStateEOL;
|
||||||
|
|
||||||
|
static inline struct LexerState *lexer_GetState(void)
|
||||||
|
{
|
||||||
|
return lexerState;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lexer_SetState(struct LexerState *state)
|
||||||
|
{
|
||||||
|
lexerState = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lexer_SetStateAtEOL(struct LexerState *state)
|
||||||
|
{
|
||||||
|
lexerStateEOL = state;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern char binDigits[2];
|
||||||
|
extern char gfxDigits[4];
|
||||||
|
|
||||||
|
static inline void lexer_SetBinDigits(char const digits[2])
|
||||||
|
{
|
||||||
|
binDigits[0] = digits[0];
|
||||||
|
binDigits[1] = digits[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void lexer_SetGfxDigits(char const digits[4])
|
||||||
|
{
|
||||||
|
gfxDigits[0] = digits[0];
|
||||||
|
gfxDigits[1] = digits[1];
|
||||||
|
gfxDigits[2] = digits[2];
|
||||||
|
gfxDigits[3] = digits[3];
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* `path` is referenced, but not held onto..!
|
||||||
|
*/
|
||||||
|
struct LexerState *lexer_OpenFile(char const *path);
|
||||||
|
struct LexerState *lexer_OpenFileView(char *buf, size_t size, uint32_t lineNo);
|
||||||
|
void lexer_RestartRept(uint32_t lineNo);
|
||||||
|
void lexer_DeleteState(struct LexerState *state);
|
||||||
|
void lexer_Init(void);
|
||||||
|
|
||||||
|
enum LexerMode {
|
||||||
|
LEXER_NORMAL,
|
||||||
|
LEXER_RAW,
|
||||||
|
LEXER_SKIP_TO_ELIF,
|
||||||
|
LEXER_SKIP_TO_ENDC,
|
||||||
|
LEXER_SKIP_TO_ENDR
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sLexFloat {
|
void lexer_SetMode(enum LexerMode mode);
|
||||||
uint32_t (*Callback)(char *s, uint32_t size);
|
void lexer_ToggleStringExpansion(bool enable);
|
||||||
uint32_t nToken;
|
|
||||||
|
uint32_t lexer_GetIFDepth(void);
|
||||||
|
void lexer_IncIFDepth(void);
|
||||||
|
void lexer_DecIFDepth(void);
|
||||||
|
bool lexer_RanIFBlock(void);
|
||||||
|
bool lexer_ReachedELSEBlock(void);
|
||||||
|
void lexer_RunIFBlock(void);
|
||||||
|
void lexer_ReachELSEBlock(void);
|
||||||
|
|
||||||
|
struct CaptureBody {
|
||||||
|
uint32_t lineNo;
|
||||||
|
char *body;
|
||||||
|
size_t size;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct yy_buffer_state {
|
char const *lexer_GetFileName(void);
|
||||||
/* Actual starting address */
|
uint32_t lexer_GetLineNo(void);
|
||||||
char *pBufferRealStart;
|
uint32_t lexer_GetColNo(void);
|
||||||
/* Address where the data is initially written after a safety margin */
|
void lexer_DumpStringExpansions(void);
|
||||||
char *pBufferStart;
|
int yylex(void);
|
||||||
char *pBuffer;
|
void lexer_CaptureRept(struct CaptureBody *capture);
|
||||||
uint32_t nBufferSize;
|
void lexer_CaptureMacroBody(struct CaptureBody *capture);
|
||||||
uint32_t oAtLineStart;
|
|
||||||
|
#define INITIAL_DS_ARG_SIZE 2
|
||||||
|
struct DsArgList {
|
||||||
|
size_t nbArgs;
|
||||||
|
size_t capacity;
|
||||||
|
struct Expression *args;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eLexerState {
|
|
||||||
LEX_STATE_NORMAL,
|
|
||||||
LEX_STATE_MACROARGS
|
|
||||||
};
|
|
||||||
|
|
||||||
#define INITIAL 0
|
|
||||||
#define macroarg 3
|
|
||||||
|
|
||||||
typedef struct yy_buffer_state *YY_BUFFER_STATE;
|
|
||||||
|
|
||||||
void setup_lexer(void);
|
|
||||||
|
|
||||||
void yy_set_state(enum eLexerState i);
|
|
||||||
YY_BUFFER_STATE yy_create_buffer(FILE *f);
|
|
||||||
YY_BUFFER_STATE yy_scan_bytes(char *mem, uint32_t size);
|
|
||||||
void yy_delete_buffer(YY_BUFFER_STATE buf);
|
|
||||||
void yy_switch_to_buffer(YY_BUFFER_STATE buf);
|
|
||||||
uint32_t lex_FloatAlloc(const struct sLexFloat *tok);
|
|
||||||
void lex_FloatAddRange(uint32_t id, uint16_t start, uint16_t end);
|
|
||||||
void lex_FloatDeleteRange(uint32_t id, uint16_t start, uint16_t end);
|
|
||||||
void lex_FloatAddFirstRange(uint32_t id, uint16_t start, uint16_t end);
|
|
||||||
void lex_FloatDeleteFirstRange(uint32_t id, uint16_t start, uint16_t end);
|
|
||||||
void lex_FloatAddSecondRange(uint32_t id, uint16_t start, uint16_t end);
|
|
||||||
void lex_FloatDeleteSecondRange(uint32_t id, uint16_t start, uint16_t end);
|
|
||||||
void lex_Init(void);
|
|
||||||
void lex_AddStrings(const struct sLexInitString *lex);
|
|
||||||
void lex_SetBuffer(char *buffer, uint32_t len);
|
|
||||||
int yywrap(void);
|
|
||||||
uint32_t yylex(void);
|
|
||||||
void yyunput(char c);
|
|
||||||
void yyunputstr(char *s);
|
|
||||||
void yyskipbytes(uint32_t count);
|
|
||||||
void yyunputbytes(uint32_t count);
|
|
||||||
|
|
||||||
extern YY_BUFFER_STATE pCurrentBuffer;
|
|
||||||
|
|
||||||
void upperstring(char *s);
|
|
||||||
void lowerstring(char *s);
|
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_LEXER_H */
|
#endif /* RGBDS_ASM_LEXER_H */
|
||||||
|
|||||||
@@ -1,131 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RGBDS_ASM_LOCALASM_H
|
|
||||||
#define RGBDS_ASM_LOCALASM_H
|
|
||||||
|
|
||||||
/*
|
|
||||||
* GB Z80 instruction groups
|
|
||||||
*
|
|
||||||
* n3 = 3-bit
|
|
||||||
* n = 8-bit
|
|
||||||
* nn = 16-bit
|
|
||||||
*
|
|
||||||
* ADC A,n : 0xCE
|
|
||||||
* ADC A,r : 0x88|r
|
|
||||||
* ADD A,n : 0xC6
|
|
||||||
* ADD A,r : 0x80|r
|
|
||||||
* ADD HL,ss : 0x09|(ss<<4)
|
|
||||||
* ADD SP,n : 0xE8
|
|
||||||
* AND A,n : 0xE6
|
|
||||||
* AND A,r : 0xA0|r
|
|
||||||
* BIT n3,r : 0xCB 0x40|(n3<<3)|r
|
|
||||||
* CALL cc,nn : 0xC4|(cc<<3)
|
|
||||||
* CALL nn : 0xCD
|
|
||||||
* CCF : 0x3F
|
|
||||||
* CP A,n : 0xFE
|
|
||||||
* CP A,r : 0xB8|r
|
|
||||||
* CPL : 0x2F
|
|
||||||
* DAA : 0x27
|
|
||||||
* DEC r : 0x05|(r<<3)
|
|
||||||
* DEC ss : 0x0B|(ss<<4)
|
|
||||||
* DI : 0xF3
|
|
||||||
* EI : 0xFB
|
|
||||||
* HALT : 0x76
|
|
||||||
* INC r : 0x04|(r<<3)
|
|
||||||
* INC ss : 0x03|(ss<<4)
|
|
||||||
* JP HL : 0xE9
|
|
||||||
* JP cc,nn : 0xC2|(cc<<3)
|
|
||||||
* JP nn : 0xC3|(cc<<3)
|
|
||||||
* JR n : 0x18
|
|
||||||
* JR cc,n : 0x20|(cc<<3)
|
|
||||||
* LD (nn),SP : 0x08
|
|
||||||
* LD ($FF00+C),A : 0xE2
|
|
||||||
* LD ($FF00+n),A : 0xE0
|
|
||||||
* LD (nn),A : 0xEA
|
|
||||||
* LD (rr),A : 0x02|(rr<<4) // HL+ and HL- included
|
|
||||||
* LD A,($FF00+C) : 0xF2
|
|
||||||
* LD A,($FF00+n) : 0xF0
|
|
||||||
* LD A,(nn) : 0xFA
|
|
||||||
* LD A,(rr) : 0x0A|(rr<<4) // HL+ and HL- included
|
|
||||||
* LD HL,SP+n : 0xF8
|
|
||||||
* LD SP,HL : 0xF9
|
|
||||||
* LD r,n : 0x06|(r<<3)
|
|
||||||
* LD r,r' : 0x40|(r<<3)|r' // NOTE: LD (HL),(HL) not allowed
|
|
||||||
* LD ss,nn : 0x01|(ss<<4)
|
|
||||||
* NOP : 0x00
|
|
||||||
* OR A,n : 0xF6
|
|
||||||
* OR A,r : 0xB0|r
|
|
||||||
* POP tt : 0xC1|(tt<<4)
|
|
||||||
* PUSH tt : 0xC5|(tt<<4)
|
|
||||||
* RES n3,r : 0xCB 0x80|(n3<<3)|r
|
|
||||||
* RET : 0xC9
|
|
||||||
* RET cc : 0xC0|(cc<<3)
|
|
||||||
* RETI : 0xD9
|
|
||||||
* RL r : 0xCB 0x10|r
|
|
||||||
* RLA : 0x17
|
|
||||||
* RLC r : 0xCB 0x00|r
|
|
||||||
* RLCA : 0x07
|
|
||||||
* RR r : 0xCB 0x18|r
|
|
||||||
* RRA : 0x1F
|
|
||||||
* RRC r : 0xCB 0x08|r
|
|
||||||
* RRCA : 0x0F
|
|
||||||
* RST n : 0xC7|n
|
|
||||||
* SBC A,n : 0xDE
|
|
||||||
* SBC A,r : 0x98|r
|
|
||||||
* SCF : 0x37
|
|
||||||
* SET n3,r : 0xCB 0xC0|(n8<<3)|r
|
|
||||||
* SLA r : 0xCB 0x20|r
|
|
||||||
* SRA r : 0xCB 0x28|r
|
|
||||||
* SRL r : 0xCB 0x38|r
|
|
||||||
* STOP : 0x10 0x00
|
|
||||||
* SUB A,n : 0xD6
|
|
||||||
* SUB A,r : 0x90|r
|
|
||||||
* SWAP r : 0xCB 0x30|r
|
|
||||||
* XOR A,n : 0xEE
|
|
||||||
* XOR A,r : 0xA8|r
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* "r" defs */
|
|
||||||
enum {
|
|
||||||
REG_B = 0,
|
|
||||||
REG_C,
|
|
||||||
REG_D,
|
|
||||||
REG_E,
|
|
||||||
REG_H,
|
|
||||||
REG_L,
|
|
||||||
REG_HL_IND,
|
|
||||||
REG_A
|
|
||||||
};
|
|
||||||
|
|
||||||
/* "rr" defs */
|
|
||||||
enum {
|
|
||||||
REG_BC_IND = 0,
|
|
||||||
REG_DE_IND,
|
|
||||||
REG_HL_INDINC,
|
|
||||||
REG_HL_INDDEC,
|
|
||||||
};
|
|
||||||
|
|
||||||
/* "ss" defs (SP) and "tt" defs (AF) */
|
|
||||||
enum {
|
|
||||||
REG_BC = 0,
|
|
||||||
REG_DE = 1,
|
|
||||||
REG_HL = 2,
|
|
||||||
REG_SP = 3,
|
|
||||||
REG_AF = 3
|
|
||||||
};
|
|
||||||
|
|
||||||
/* "cc" defs */
|
|
||||||
enum {
|
|
||||||
CC_NZ = 0,
|
|
||||||
CC_Z,
|
|
||||||
CC_NC,
|
|
||||||
CC_C
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_LOCALASM_H */
|
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_MACRO_H
|
||||||
|
#define RGBDS_MACRO_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "asm/warning.h"
|
||||||
|
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
struct MacroArgs;
|
||||||
|
|
||||||
|
struct MacroArgs *macro_GetCurrentArgs(void);
|
||||||
|
struct MacroArgs *macro_NewArgs(void);
|
||||||
|
void macro_AppendArg(struct MacroArgs **args, char *s);
|
||||||
|
void macro_UseNewArgs(struct MacroArgs *args);
|
||||||
|
void macro_FreeArgs(struct MacroArgs *args);
|
||||||
|
char const *macro_GetArg(uint32_t i);
|
||||||
|
char *macro_GetAllArgs(void);
|
||||||
|
|
||||||
|
uint32_t macro_GetUniqueID(void);
|
||||||
|
char const *macro_GetUniqueIDStr(void);
|
||||||
|
void macro_SetUniqueID(uint32_t id);
|
||||||
|
uint32_t macro_UseNewUniqueID(void);
|
||||||
|
void macro_ShiftCurrentArgs(int32_t count);
|
||||||
|
uint32_t macro_NbArgs(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
+11
-46
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2021, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
@@ -11,57 +11,22 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
|
|
||||||
struct sOptions {
|
extern bool haltnop;
|
||||||
char binary[2];
|
extern bool optimizeloads;
|
||||||
char gbgfx[4];
|
extern bool verbose;
|
||||||
bool exportall;
|
extern bool warnings; /* True to enable warnings, false to disable them. */
|
||||||
int32_t fillchar;
|
|
||||||
bool haltnop;
|
|
||||||
bool optimizeloads;
|
|
||||||
bool verbose;
|
|
||||||
bool warnings; /* True to enable warnings, false to disable them. */
|
|
||||||
};
|
|
||||||
|
|
||||||
extern char *tzNewMacro;
|
|
||||||
extern uint32_t ulNewMacroSize;
|
|
||||||
extern int32_t nGBGfxID;
|
|
||||||
extern int32_t nBinaryID;
|
|
||||||
|
|
||||||
extern struct sOptions DefaultOptions;
|
|
||||||
extern struct sOptions CurrentOptions;
|
|
||||||
|
|
||||||
extern FILE *dependfile;
|
extern FILE *dependfile;
|
||||||
|
extern char *tzTargetFileName;
|
||||||
|
extern bool oGeneratedMissingIncludes;
|
||||||
|
extern bool oFailedOnMissingInclude;
|
||||||
|
extern bool oGeneratePhonyDeps;
|
||||||
|
|
||||||
void opt_Push(void);
|
/* TODO: are these really needed? */
|
||||||
void opt_Pop(void);
|
|
||||||
void opt_Parse(char *s);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used for errors that compromise the whole assembly process by affecting the
|
|
||||||
* folliwing code, potencially making the assembler generate errors caused by
|
|
||||||
* the first one and unrelated to the code that the assembler complains about.
|
|
||||||
* It is also used when the assembler goes into an invalid state (for example,
|
|
||||||
* when it fails to allocate memory).
|
|
||||||
*/
|
|
||||||
noreturn_ void fatalerror(const char *fmt, ...);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used for errors that make it impossible to assemble correctly, but don't
|
|
||||||
* affect the following code. The code will fail to assemble but the user will
|
|
||||||
* get a list of all errors at the end, making it easier to fix all of them at
|
|
||||||
* once.
|
|
||||||
*/
|
|
||||||
void yyerror(const char *fmt, ...);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Used to warn the user about problems that don't prevent the generation of
|
|
||||||
* valid code.
|
|
||||||
*/
|
|
||||||
void warning(const char *fmt, ...);
|
|
||||||
|
|
||||||
#define YY_FATAL_ERROR fatalerror
|
#define YY_FATAL_ERROR fatalerror
|
||||||
|
|
||||||
#ifdef YYLMAX
|
#ifdef YYLMAX
|
||||||
|
|||||||
@@ -1,29 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RGBDS_ASM_MATH_H
|
|
||||||
#define RGBDS_ASM_MATH_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
void math_DefinePI(void);
|
|
||||||
void math_Print(int32_t i);
|
|
||||||
int32_t math_Sin(int32_t i);
|
|
||||||
int32_t math_Cos(int32_t i);
|
|
||||||
int32_t math_Tan(int32_t i);
|
|
||||||
int32_t math_ASin(int32_t i);
|
|
||||||
int32_t math_ACos(int32_t i);
|
|
||||||
int32_t math_ATan(int32_t i);
|
|
||||||
int32_t math_ATan2(int32_t i, int32_t j);
|
|
||||||
int32_t math_Mul(int32_t i, int32_t j);
|
|
||||||
int32_t math_Div(int32_t i, int32_t j);
|
|
||||||
int32_t math_Round(int32_t i);
|
|
||||||
int32_t math_Ceil(int32_t i);
|
|
||||||
int32_t math_Floor(int32_t i);
|
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_MATH_H */
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2021, Eldred Habert and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_OPT_H
|
||||||
|
#define RGBDS_OPT_H
|
||||||
|
|
||||||
|
|
||||||
|
void opt_B(char chars[2]);
|
||||||
|
void opt_G(char chars[4]);
|
||||||
|
void opt_P(uint8_t fill);
|
||||||
|
void opt_Parse(char const *option);
|
||||||
|
|
||||||
|
void opt_Push(void);
|
||||||
|
void opt_Pop(void);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
+9
-32
@@ -11,43 +11,20 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "asm/rpn.h"
|
#include "linkdefs.h"
|
||||||
|
|
||||||
struct Section {
|
struct Expression;
|
||||||
char *pzName;
|
struct FileStackNode;
|
||||||
uint8_t nType;
|
|
||||||
uint32_t nPC;
|
|
||||||
uint32_t nOrg;
|
|
||||||
uint32_t nBank;
|
|
||||||
uint32_t nAlign;
|
|
||||||
struct Section *pNext;
|
|
||||||
struct Patch *pPatches;
|
|
||||||
struct Charmap *charmap;
|
|
||||||
uint8_t *tData;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern char *tzObjectname;
|
extern char *tzObjectname;
|
||||||
|
extern struct Section *pSectionList, *pCurrentSection;
|
||||||
|
|
||||||
void out_PrepPass2(void);
|
void out_RegisterNode(struct FileStackNode *node);
|
||||||
|
void out_ReplaceNode(struct FileStackNode *node);
|
||||||
void out_SetFileName(char *s);
|
void out_SetFileName(char *s);
|
||||||
void out_NewSection(char *pzName, uint32_t secttype);
|
void out_CreatePatch(uint32_t type, struct Expression const *expr, uint32_t ofs, uint32_t pcShift);
|
||||||
void out_NewAbsSection(char *pzName, uint32_t secttype, int32_t org,
|
bool out_CreateAssert(enum AssertionType type, struct Expression const *expr,
|
||||||
int32_t bank);
|
char const *message, uint32_t ofs);
|
||||||
void out_NewAlignedSection(char *pzName, uint32_t secttype, int32_t alignment,
|
|
||||||
int32_t bank);
|
|
||||||
void out_AbsByte(int32_t b);
|
|
||||||
void out_AbsByteGroup(char *s, int32_t length);
|
|
||||||
void out_RelByte(struct Expression *expr);
|
|
||||||
void out_RelWord(struct Expression *expr);
|
|
||||||
void out_PCRelByte(struct Expression *expr);
|
|
||||||
void out_WriteObject(void);
|
void out_WriteObject(void);
|
||||||
void out_Skip(int32_t skip);
|
|
||||||
void out_BinaryFile(char *s);
|
|
||||||
void out_BinaryFileSlice(char *s, int32_t start_pos, int32_t length);
|
|
||||||
void out_String(char *s);
|
|
||||||
void out_AbsLong(int32_t b);
|
|
||||||
void out_RelLong(struct Expression *expr);
|
|
||||||
void out_PushSection(void);
|
|
||||||
void out_PopSection(void);
|
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_OUTPUT_H */
|
#endif /* RGBDS_ASM_OUTPUT_H */
|
||||||
|
|||||||
+40
-49
@@ -10,66 +10,57 @@
|
|||||||
#define RGBDS_ASM_RPN_H
|
#define RGBDS_ASM_RPN_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "linkdefs.h"
|
||||||
|
|
||||||
|
#define MAXRPNLEN 1048576
|
||||||
|
|
||||||
struct Expression {
|
struct Expression {
|
||||||
int32_t nVal;
|
int32_t nVal; // If the expression's value is known, it's here
|
||||||
uint8_t tRPN[256];
|
char *reason; // Why the expression is not known, if it isn't
|
||||||
uint32_t nRPNLength;
|
bool isKnown; // Whether the expression's value is known
|
||||||
uint32_t nRPNOut;
|
bool isSymbol; // Whether the expression represents a symbol
|
||||||
uint32_t isReloc;
|
uint8_t *tRPN; // Array of bytes serializing the RPN expression
|
||||||
uint32_t isPCRel;
|
uint32_t nRPNCapacity; // Size of the `tRPN` buffer
|
||||||
|
uint32_t nRPNLength; // Used size of the `tRPN` buffer
|
||||||
|
uint32_t nRPNPatchSize; // Size the expression will take in the obj file
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t rpn_isReloc(const struct Expression *expr);
|
/*
|
||||||
uint32_t rpn_isPCRelative(const struct Expression *expr);
|
* Determines if an expression is known at assembly time
|
||||||
void rpn_Symbol(struct Expression *expr, char *tzSym);
|
*/
|
||||||
|
static inline bool rpn_isKnown(const struct Expression *expr)
|
||||||
|
{
|
||||||
|
return expr->isKnown;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determines if an expression is a symbol suitable for const diffing
|
||||||
|
*/
|
||||||
|
static inline bool rpn_isSymbol(const struct Expression *expr)
|
||||||
|
{
|
||||||
|
return expr->isSymbol;
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_Symbol(struct Expression *expr, char const *tzSym);
|
||||||
void rpn_Number(struct Expression *expr, uint32_t i);
|
void rpn_Number(struct Expression *expr, uint32_t i);
|
||||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
|
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src);
|
||||||
void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
|
struct Symbol const *rpn_SymbolOf(struct Expression const *expr);
|
||||||
const struct Expression *src2);
|
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym);
|
||||||
void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
|
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||||
const struct Expression *src2);
|
const struct Expression *src1,
|
||||||
void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
|
const struct Expression *src2);
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_ADD(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_SUB(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_XOR(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_OR(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_AND(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_SHR(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_MUL(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_DIV(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_MOD(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2);
|
|
||||||
void rpn_HIGH(struct Expression *expr, const struct Expression *src);
|
void rpn_HIGH(struct Expression *expr, const struct Expression *src);
|
||||||
void rpn_LOW(struct Expression *expr, const struct Expression *src);
|
void rpn_LOW(struct Expression *expr, const struct Expression *src);
|
||||||
|
void rpn_ISCONST(struct Expression *expr, const struct Expression *src);
|
||||||
void rpn_UNNEG(struct Expression *expr, const struct Expression *src);
|
void rpn_UNNEG(struct Expression *expr, const struct Expression *src);
|
||||||
void rpn_UNNOT(struct Expression *expr, const struct Expression *src);
|
void rpn_UNNOT(struct Expression *expr, const struct Expression *src);
|
||||||
uint16_t rpn_PopByte(struct Expression *expr);
|
void rpn_BankSymbol(struct Expression *expr, char const *tzSym);
|
||||||
void rpn_BankSymbol(struct Expression *expr, char *tzSym);
|
void rpn_BankSection(struct Expression *expr, char const *tzSectionName);
|
||||||
void rpn_BankSection(struct Expression *expr, char *tzSectionName);
|
|
||||||
void rpn_BankSelf(struct Expression *expr);
|
void rpn_BankSelf(struct Expression *expr);
|
||||||
void rpn_Reset(struct Expression *expr);
|
void rpn_Free(struct Expression *expr);
|
||||||
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
|
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src);
|
||||||
|
void rpn_CheckRST(struct Expression *expr, const struct Expression *src);
|
||||||
|
|
||||||
#endif /* RGBDS_ASM_RPN_H */
|
#endif /* RGBDS_ASM_RPN_H */
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_SECTION_H
|
||||||
|
#define RGBDS_SECTION_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "linkdefs.h"
|
||||||
|
|
||||||
|
extern uint8_t fillByte;
|
||||||
|
|
||||||
|
struct Expression;
|
||||||
|
|
||||||
|
struct Section {
|
||||||
|
char *name;
|
||||||
|
enum SectionType type;
|
||||||
|
enum SectionModifier modifier;
|
||||||
|
struct FileStackNode *src; /* Where the section was defined */
|
||||||
|
uint32_t fileLine; /* Line where the section was defined */
|
||||||
|
uint32_t size;
|
||||||
|
uint32_t org;
|
||||||
|
uint32_t bank;
|
||||||
|
uint8_t align;
|
||||||
|
uint16_t alignOfs;
|
||||||
|
struct Section *next;
|
||||||
|
struct Patch *patches;
|
||||||
|
uint8_t *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SectionSpec {
|
||||||
|
uint32_t bank;
|
||||||
|
uint8_t alignment;
|
||||||
|
uint16_t alignOfs;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Section *out_FindSectionByName(const char *name);
|
||||||
|
void out_NewSection(char const *name, uint32_t secttype, uint32_t org,
|
||||||
|
struct SectionSpec const *attributes,
|
||||||
|
enum SectionModifier mod);
|
||||||
|
void out_SetLoadSection(char const *name, uint32_t secttype, uint32_t org,
|
||||||
|
struct SectionSpec const *attributes,
|
||||||
|
enum SectionModifier mod);
|
||||||
|
void out_EndLoadSection(void);
|
||||||
|
|
||||||
|
struct Section *sect_GetSymbolSection(void);
|
||||||
|
uint32_t sect_GetSymbolOffset(void);
|
||||||
|
uint32_t sect_GetOutputOffset(void);
|
||||||
|
void sect_AlignPC(uint8_t alignment, uint16_t offset);
|
||||||
|
|
||||||
|
void sect_StartUnion(void);
|
||||||
|
void sect_NextUnionMember(void);
|
||||||
|
void sect_EndUnion(void);
|
||||||
|
void sect_CheckUnionClosed(void);
|
||||||
|
|
||||||
|
void out_AbsByte(uint8_t b);
|
||||||
|
void out_AbsByteGroup(uint8_t const *s, int32_t length);
|
||||||
|
void out_AbsWordGroup(uint8_t const *s, int32_t length);
|
||||||
|
void out_AbsLongGroup(uint8_t const *s, int32_t length);
|
||||||
|
void out_Skip(int32_t skip, bool ds);
|
||||||
|
void out_String(char const *s);
|
||||||
|
void out_RelByte(struct Expression *expr, uint32_t pcShift);
|
||||||
|
void out_RelBytes(uint32_t n, struct Expression *exprs, size_t size);
|
||||||
|
void out_RelWord(struct Expression *expr, uint32_t pcShift);
|
||||||
|
void out_RelLong(struct Expression *expr, uint32_t pcShift);
|
||||||
|
void out_PCRelByte(struct Expression *expr, uint32_t pcShift);
|
||||||
|
void out_BinaryFile(char const *s, int32_t startPos);
|
||||||
|
void out_BinaryFileSlice(char const *s, int32_t start_pos, int32_t length);
|
||||||
|
|
||||||
|
void out_PushSection(void);
|
||||||
|
void out_PopSection(void);
|
||||||
|
|
||||||
|
#endif
|
||||||
+128
-71
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2020, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
@@ -9,87 +9,144 @@
|
|||||||
#ifndef RGBDS_SYMBOL_H
|
#ifndef RGBDS_SYMBOL_H
|
||||||
#define RGBDS_SYMBOL_H
|
#define RGBDS_SYMBOL_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "asm/section.h"
|
||||||
|
|
||||||
|
#include "platform.h" // MIN_NB_ELMS
|
||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
#define HASHSIZE (1 << 16)
|
#define HASHSIZE (1 << 16)
|
||||||
#define MAXSYMLEN 256
|
#define MAXSYMLEN 256
|
||||||
|
|
||||||
struct sSymbol {
|
enum SymbolType {
|
||||||
char tzName[MAXSYMLEN + 1];
|
SYM_LABEL,
|
||||||
int32_t nValue;
|
SYM_EQU,
|
||||||
uint32_t nType;
|
SYM_SET,
|
||||||
struct sSymbol *pScope;
|
SYM_MACRO,
|
||||||
struct sSymbol *pNext;
|
SYM_EQUS,
|
||||||
struct Section *pSection;
|
SYM_REF // Forward reference to a label
|
||||||
uint32_t ulMacroSize;
|
|
||||||
char *pMacro;
|
|
||||||
int32_t (*Callback)(struct sSymbol *);
|
|
||||||
char tzFileName[_MAX_PATH + 1]; /* File where the symbol was defined. */
|
|
||||||
uint32_t nFileLine; /* Line where the symbol was defined. */
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Symbol will be relocated during linking, it's absolute value is unknown */
|
struct Symbol {
|
||||||
#define SYMF_RELOC 0x001
|
char name[MAXSYMLEN + 1];
|
||||||
/* Symbol is defined using EQU, will not be changed during linking */
|
enum SymbolType type;
|
||||||
#define SYMF_EQU 0x002
|
bool isExported; /* Whether the symbol is to be exported */
|
||||||
/* Symbol is (re)defined using SET, will not be changed during linking */
|
bool isBuiltin; /* Whether the symbol is a built-in */
|
||||||
#define SYMF_SET 0x004
|
struct Section *section;
|
||||||
/* Symbol should be exported */
|
struct FileStackNode *src; /* Where the symbol was defined */
|
||||||
#define SYMF_EXPORT 0x008
|
uint32_t fileLine; /* Line where the symbol was defined */
|
||||||
/* Symbol is imported, it's value is unknown */
|
|
||||||
#define SYMF_IMPORT 0x010
|
|
||||||
/* Symbol is a local symbol */
|
|
||||||
#define SYMF_LOCAL 0x020
|
|
||||||
/* Symbol has been defined, not only referenced */
|
|
||||||
#define SYMF_DEFINED 0x040
|
|
||||||
/* Symbol is a macro */
|
|
||||||
#define SYMF_MACRO 0x080
|
|
||||||
/* Symbol is a stringsymbol */
|
|
||||||
#define SYMF_STRING 0x100
|
|
||||||
/* Symbol has a constant value, will not be changed during linking */
|
|
||||||
#define SYMF_CONST 0x200
|
|
||||||
|
|
||||||
uint32_t calchash(char *s);
|
bool hasCallback;
|
||||||
void sym_SetExportAll(uint8_t set);
|
union {
|
||||||
void sym_PrepPass1(void);
|
/* If sym_IsNumeric */
|
||||||
void sym_PrepPass2(void);
|
int32_t value;
|
||||||
void sym_AddLocalReloc(char *tzSym);
|
int32_t (*numCallback)(void);
|
||||||
void sym_AddReloc(char *tzSym);
|
/* For SYM_MACRO */
|
||||||
void sym_Export(char *tzSym);
|
struct {
|
||||||
void sym_PrintSymbolTable(void);
|
size_t macroSize;
|
||||||
struct sSymbol *sym_FindMacro(char *s);
|
char *macro;
|
||||||
void sym_InitNewMacroArgs(void);
|
};
|
||||||
void sym_AddNewMacroArg(char *s);
|
/* For SYM_EQUS, TODO: separate "base" fields from SYM_MACRO */
|
||||||
void sym_SaveCurrentMacroArgs(char *save[]);
|
char const *(*strCallback)(void); /* For SYM_EQUS */
|
||||||
void sym_RestoreCurrentMacroArgs(char *save[]);
|
};
|
||||||
void sym_UseNewMacroArgs(void);
|
|
||||||
void sym_FreeCurrentMacroArgs(void);
|
uint32_t ID; /* ID of the symbol in the object file (-1 if none) */
|
||||||
void sym_AddEqu(char *tzSym, int32_t value);
|
struct Symbol *next; /* Next object to output in the object file */
|
||||||
void sym_AddSet(char *tzSym, int32_t value);
|
};
|
||||||
void sym_Init(void);
|
|
||||||
uint32_t sym_GetConstantValue(char *s);
|
bool sym_IsPC(struct Symbol const *sym);
|
||||||
uint32_t sym_isConstant(char *s);
|
|
||||||
struct sSymbol *sym_FindSymbol(char *tzName);
|
static inline bool sym_IsDefined(struct Symbol const *sym)
|
||||||
void sym_Global(char *tzSym);
|
{
|
||||||
char *sym_FindMacroArg(int32_t i);
|
return sym->type != SYM_REF;
|
||||||
char *sym_GetStringValue(char *tzSym);
|
}
|
||||||
void sym_UseCurrentMacroArgs(void);
|
|
||||||
void sym_SetMacroArgID(uint32_t nMacroCount);
|
static inline struct Section *sym_GetSection(struct Symbol const *sym)
|
||||||
uint32_t sym_isString(char *tzSym);
|
{
|
||||||
void sym_AddMacro(char *tzSym);
|
return sym_IsPC(sym) ? sect_GetSymbolSection() : sym->section;
|
||||||
void sym_ShiftCurrentMacroArgs(void);
|
}
|
||||||
void sym_AddString(char *tzSym, char *tzValue);
|
|
||||||
uint32_t sym_GetValue(char *s);
|
static inline bool sym_IsConstant(struct Symbol const *sym)
|
||||||
uint32_t sym_GetDefinedValue(char *s);
|
{
|
||||||
uint32_t sym_isDefined(char *tzName);
|
if (sym->type == SYM_LABEL) {
|
||||||
void sym_Purge(char *tzName);
|
struct Section const *sect = sym_GetSection(sym);
|
||||||
uint32_t sym_isConstDefined(char *tzName);
|
|
||||||
int32_t sym_IsRelocDiffDefined(char *tzSym1, char *tzSym2);
|
return sect && sect->org != (uint32_t)-1;
|
||||||
|
}
|
||||||
|
return sym->type == SYM_EQU || sym->type == SYM_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool sym_IsNumeric(struct Symbol const *sym)
|
||||||
|
{
|
||||||
|
return sym->type == SYM_LABEL || sym->type == SYM_EQU
|
||||||
|
|| sym->type == SYM_SET;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool sym_IsLabel(struct Symbol const *sym)
|
||||||
|
{
|
||||||
|
return sym->type == SYM_LABEL || sym->type == SYM_REF;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool sym_IsLocal(struct Symbol const *sym)
|
||||||
|
{
|
||||||
|
return sym_IsLabel(sym) && strchr(sym->name, '.');
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline bool sym_IsExported(struct Symbol const *sym)
|
||||||
|
{
|
||||||
|
return sym->isExported;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Get a string equate's value
|
||||||
|
*/
|
||||||
|
static inline char const *sym_GetStringValue(struct Symbol const *sym)
|
||||||
|
{
|
||||||
|
if (sym->hasCallback)
|
||||||
|
return sym->strCallback();
|
||||||
|
return sym->macro;
|
||||||
|
}
|
||||||
|
|
||||||
|
void sym_ForEach(void (*func)(struct Symbol *, void *), void *arg);
|
||||||
|
|
||||||
|
int32_t sym_GetValue(struct Symbol const *sym);
|
||||||
|
void sym_SetExportAll(bool set);
|
||||||
|
struct Symbol *sym_AddLocalLabel(char const *symName);
|
||||||
|
struct Symbol *sym_AddLabel(char const *symName);
|
||||||
|
struct Symbol *sym_AddAnonLabel(void);
|
||||||
|
void sym_WriteAnonLabelName(char buf[MIN_NB_ELMS(MAXSYMLEN + 1)], uint32_t ofs, bool neg);
|
||||||
|
void sym_Export(char const *symName);
|
||||||
|
struct Symbol *sym_AddEqu(char const *symName, int32_t value);
|
||||||
|
struct Symbol *sym_AddSet(char const *symName, int32_t value);
|
||||||
|
uint32_t sym_GetPCValue(void);
|
||||||
|
uint32_t sym_GetConstantSymValue(struct Symbol const *sym);
|
||||||
|
uint32_t sym_GetConstantValue(char const *s);
|
||||||
|
/*
|
||||||
|
* Find a symbol by exact name, bypassing expansion checks
|
||||||
|
*/
|
||||||
|
struct Symbol *sym_FindExactSymbol(char const *name);
|
||||||
|
/*
|
||||||
|
* Find a symbol by exact name; may not be scoped, produces an error if it is
|
||||||
|
*/
|
||||||
|
struct Symbol *sym_FindUnscopedSymbol(char const *name);
|
||||||
|
/*
|
||||||
|
* Find a symbol, possibly scoped, by name
|
||||||
|
*/
|
||||||
|
struct Symbol *sym_FindScopedSymbol(char const *name);
|
||||||
|
struct Symbol const *sym_GetPC(void);
|
||||||
|
struct Symbol *sym_AddMacro(char const *symName, int32_t defLineNo, char *body, size_t size);
|
||||||
|
struct Symbol *sym_Ref(char const *symName);
|
||||||
|
struct Symbol *sym_AddString(char const *symName, char const *value);
|
||||||
|
struct Symbol *sym_RedefString(char const *symName, char const *value);
|
||||||
|
void sym_Purge(char const *symName);
|
||||||
|
void sym_Init(time_t now);
|
||||||
|
|
||||||
/* Functions to save and restore the current symbol scope. */
|
/* Functions to save and restore the current symbol scope. */
|
||||||
struct sSymbol *sym_GetCurrentSymbolScope(void);
|
char const *sym_GetCurrentSymbolScope(void);
|
||||||
void sym_SetCurrentSymbolScope(struct sSymbol *pNewScope);
|
void sym_SetCurrentSymbolScope(char const *newScope);
|
||||||
|
|
||||||
#endif /* RGBDS_SYMBOL_H */
|
#endif /* RGBDS_SYMBOL_H */
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_UTIL_H
|
||||||
|
#define RGBDS_UTIL_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
uint32_t calchash(const char *s);
|
||||||
|
char const *print(int c);
|
||||||
|
/*
|
||||||
|
* @return The number of bytes read, or 0 if invalid data was found
|
||||||
|
*/
|
||||||
|
size_t readUTF8Char(uint8_t *dest, char const *src);
|
||||||
|
|
||||||
|
#endif /* RGBDS_UTIL_H */
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2019, Eldred Habert and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef WARNING_H
|
||||||
|
#define WARNING_H
|
||||||
|
|
||||||
|
#include "helpers.h"
|
||||||
|
|
||||||
|
extern unsigned int nbErrors;
|
||||||
|
|
||||||
|
enum WarningID {
|
||||||
|
WARNING_ASSERT, /* Assertions */
|
||||||
|
WARNING_BUILTIN_ARG, /* Invalid args to builtins */
|
||||||
|
WARNING_CHARMAP_REDEF, /* Charmap entry re-definition */
|
||||||
|
WARNING_DIV, /* Division undefined behavior */
|
||||||
|
WARNING_EMPTY_DATA_DIRECTIVE, /* `db`, `dw` or `dl` directive without data in ROM */
|
||||||
|
WARNING_EMPTY_MACRO_ARG, /* Empty macro argument */
|
||||||
|
WARNING_EMPTY_STRRPL, /* Empty second argument in `STRRPL` */
|
||||||
|
WARNING_LARGE_CONSTANT, /* Constants too large */
|
||||||
|
WARNING_LONG_STR, /* String too long for internal buffers */
|
||||||
|
WARNING_MACRO_SHIFT, /* Shift past available arguments in macro */
|
||||||
|
WARNING_NESTED_COMMENT, /* Comment-start delimiter in a block comment */
|
||||||
|
WARNING_OBSOLETE, /* Obsolete things */
|
||||||
|
WARNING_SHIFT, /* Shifting undefined behavior */
|
||||||
|
WARNING_SHIFT_AMOUNT, /* Strange shift amount */
|
||||||
|
WARNING_TRUNCATION, /* Implicit truncation loses some bits */
|
||||||
|
WARNING_USER, /* User warnings */
|
||||||
|
|
||||||
|
NB_WARNINGS,
|
||||||
|
|
||||||
|
/* Warnings past this point are "meta" warnings */
|
||||||
|
WARNING_ALL = NB_WARNINGS,
|
||||||
|
WARNING_EXTRA,
|
||||||
|
WARNING_EVERYTHING,
|
||||||
|
|
||||||
|
NB_WARNINGS_ALL
|
||||||
|
#define NB_META_WARNINGS (NB_WARNINGS_ALL - NB_WARNINGS)
|
||||||
|
};
|
||||||
|
|
||||||
|
void processWarningFlag(char const *flag);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used to warn the user about problems that don't prevent the generation of
|
||||||
|
* valid code.
|
||||||
|
*/
|
||||||
|
void warning(enum WarningID id, const char *fmt, ...) format_(printf, 2, 3);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used for errors that compromise the whole assembly process by affecting the
|
||||||
|
* following code, potencially making the assembler generate errors caused by
|
||||||
|
* the first one and unrelated to the code that the assembler complains about.
|
||||||
|
* It is also used when the assembler goes into an invalid state (for example,
|
||||||
|
* when it fails to allocate memory).
|
||||||
|
*/
|
||||||
|
_Noreturn void fatalerror(const char *fmt, ...) format_(printf, 1, 2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Used for errors that make it impossible to assemble correctly, but don't
|
||||||
|
* affect the following code. The code will fail to assemble but the user will
|
||||||
|
* get a list of all errors at the end, making it easier to fix all of them at
|
||||||
|
* once.
|
||||||
|
*/
|
||||||
|
void error(const char *fmt, ...) format_(printf, 1, 2);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RGBDS_COMMON_H
|
|
||||||
#define RGBDS_COMMON_H
|
|
||||||
|
|
||||||
#define RGBDS_OBJECT_VERSION_STRING "RGB6"
|
|
||||||
|
|
||||||
enum eBankCount {
|
|
||||||
BANK_COUNT_ROM0 = 1,
|
|
||||||
BANK_COUNT_ROMX = 511,
|
|
||||||
BANK_COUNT_WRAM0 = 1,
|
|
||||||
BANK_COUNT_WRAMX = 7,
|
|
||||||
BANK_COUNT_VRAM = 2,
|
|
||||||
BANK_COUNT_OAM = 1,
|
|
||||||
BANK_COUNT_HRAM = 1,
|
|
||||||
BANK_COUNT_SRAM = 16
|
|
||||||
};
|
|
||||||
|
|
||||||
enum eBankGBCount {
|
|
||||||
BANK_MIN_ROM0 = 0,
|
|
||||||
BANK_MAX_ROM0 = BANK_COUNT_ROM0 + BANK_MIN_ROM0 - 1,
|
|
||||||
BANK_MIN_ROMX = 1,
|
|
||||||
BANK_MAX_ROMX = BANK_COUNT_ROMX + BANK_MIN_ROMX - 1,
|
|
||||||
BANK_MIN_WRAM0 = 0,
|
|
||||||
BANK_MAX_WRAM0 = BANK_COUNT_WRAM0 + BANK_MIN_WRAM0 - 1,
|
|
||||||
BANK_MIN_WRAMX = 1,
|
|
||||||
BANK_MAX_WRAMX = BANK_COUNT_WRAMX + BANK_MIN_WRAMX - 1,
|
|
||||||
BANK_MIN_VRAM = 0,
|
|
||||||
BANK_MAX_VRAM = BANK_COUNT_VRAM + BANK_MIN_VRAM - 1,
|
|
||||||
BANK_MIN_OAM = 0,
|
|
||||||
BANK_MAX_OAM = BANK_COUNT_OAM + BANK_MIN_OAM - 1,
|
|
||||||
BANK_MIN_HRAM = 0,
|
|
||||||
BANK_MAX_HRAM = BANK_COUNT_HRAM + BANK_MIN_HRAM - 1,
|
|
||||||
BANK_MIN_SRAM = 0,
|
|
||||||
BANK_MAX_SRAM = BANK_COUNT_SRAM + BANK_MIN_SRAM - 1
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* RGBDS_COMMON_H */
|
|
||||||
Vendored
+8
-8
@@ -29,15 +29,15 @@
|
|||||||
#define errx rgbds_errx
|
#define errx rgbds_errx
|
||||||
#define verrx rgbds_verrx
|
#define verrx rgbds_verrx
|
||||||
|
|
||||||
void warn(const char *fmt, ...);
|
void warn(const char *fmt, ...) format_(printf, 1, 2);
|
||||||
void vwarn(const char *fmt, va_list ap);
|
void vwarn(const char *fmt, va_list ap) format_(printf, 1, 0);
|
||||||
void warnx(const char *fmt, ...);
|
void warnx(const char *fmt, ...) format_(printf, 1, 2);
|
||||||
void vwarnx(const char *fmt, va_list ap);
|
void vwarnx(const char *fmt, va_list ap) format_(printf, 1, 0);
|
||||||
|
|
||||||
noreturn_ void err(int status, const char *fmt, ...);
|
_Noreturn void err(int status, const char *fmt, ...) format_(printf, 2, 3);
|
||||||
noreturn_ void verr(int status, const char *fmt, va_list ap);
|
_Noreturn void verr(int status, const char *fmt, va_list ap) format_(printf, 2, 0);
|
||||||
noreturn_ void errx(int status, const char *fmt, ...);
|
_Noreturn void errx(int status, const char *fmt, ...) format_(printf, 2, 3);
|
||||||
noreturn_ void verrx(int status, const char *fmt, va_list ap);
|
_Noreturn void verrx(int status, const char *fmt, va_list ap) format_(printf, 2, 0);
|
||||||
|
|
||||||
#endif /* ERR_IN_LIBC */
|
#endif /* ERR_IN_LIBC */
|
||||||
|
|
||||||
|
|||||||
Vendored
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright © 2005-2020 Rich Felker, et al.
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the
|
||||||
|
* "Software"), to deal in the Software without restriction, including
|
||||||
|
* without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
* distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
* permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
* the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be
|
||||||
|
* included in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This implementation was taken from musl and modified for RGBDS */
|
||||||
|
|
||||||
|
#ifndef RGBDS_EXTERN_GETOPT_H
|
||||||
|
#define RGBDS_EXTERN_GETOPT_H
|
||||||
|
|
||||||
|
extern char *musl_optarg;
|
||||||
|
extern int musl_optind, musl_opterr, musl_optopt, musl_optreset;
|
||||||
|
|
||||||
|
struct option {
|
||||||
|
const char *name;
|
||||||
|
int has_arg;
|
||||||
|
int *flag;
|
||||||
|
int val;
|
||||||
|
};
|
||||||
|
|
||||||
|
int musl_getopt_long_only(int, char **, const char *, const struct option *, int *);
|
||||||
|
|
||||||
|
#define no_argument 0
|
||||||
|
#define required_argument 1
|
||||||
|
#define optional_argument 2
|
||||||
|
|
||||||
|
#endif
|
||||||
Vendored
+1
-1
@@ -9,6 +9,6 @@
|
|||||||
#ifndef EXTERN_UTF8DECODER_H
|
#ifndef EXTERN_UTF8DECODER_H
|
||||||
#define EXTERN_UTF8DECODER_H
|
#define EXTERN_UTF8DECODER_H
|
||||||
|
|
||||||
uint32_t decode(uint32_t *state, uint32_t *codep, uint32_t byte);
|
uint32_t decode(uint32_t *state, uint32_t *codep, uint8_t byte);
|
||||||
|
|
||||||
#endif /* EXTERN_UTF8DECODER_H */
|
#endif /* EXTERN_UTF8DECODER_H */
|
||||||
|
|||||||
+13
-3
@@ -12,14 +12,24 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include "gfx/main.h"
|
#include "gfx/main.h"
|
||||||
|
|
||||||
|
#define XFLIP 0x40
|
||||||
|
#define YFLIP 0x20
|
||||||
|
|
||||||
void raw_to_gb(const struct RawIndexedImage *raw_image, struct GBImage *gb);
|
void raw_to_gb(const struct RawIndexedImage *raw_image, struct GBImage *gb);
|
||||||
void output_file(const struct Options *opts, const struct GBImage *gb);
|
void output_file(const struct Options *opts, const struct GBImage *gb);
|
||||||
int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
int get_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
||||||
int tile_size);
|
int tile_size);
|
||||||
void create_tilemap(const struct Options *opts, struct GBImage *gb,
|
uint8_t reverse_bits(uint8_t b);
|
||||||
struct Tilemap *tilemap);
|
void xflip(uint8_t *tile, uint8_t *tile_xflip, int tile_size);
|
||||||
|
void yflip(uint8_t *tile, uint8_t *tile_yflip, int tile_size);
|
||||||
|
int get_mirrored_tile_index(uint8_t *tile, uint8_t **tiles, int num_tiles,
|
||||||
|
int tile_size, int *flags);
|
||||||
|
void create_mapfiles(const struct Options *opts, struct GBImage *gb,
|
||||||
|
struct Mapfile *tilemap, struct Mapfile *attrmap);
|
||||||
void output_tilemap_file(const struct Options *opts,
|
void output_tilemap_file(const struct Options *opts,
|
||||||
const struct Tilemap *tilemap);
|
const struct Mapfile *tilemap);
|
||||||
|
void output_attrmap_file(const struct Options *opts,
|
||||||
|
const struct Mapfile *attrmap);
|
||||||
void output_palette_file(const struct Options *opts,
|
void output_palette_file(const struct Options *opts,
|
||||||
const struct RawIndexedImage *raw_image);
|
const struct RawIndexedImage *raw_image);
|
||||||
|
|
||||||
|
|||||||
+15
-8
@@ -21,10 +21,14 @@ struct Options {
|
|||||||
bool hardfix;
|
bool hardfix;
|
||||||
bool fix;
|
bool fix;
|
||||||
bool horizontal;
|
bool horizontal;
|
||||||
|
bool mirror;
|
||||||
bool unique;
|
bool unique;
|
||||||
|
bool colorcurve;
|
||||||
int trim;
|
int trim;
|
||||||
char *mapfile;
|
char *tilemapfile;
|
||||||
bool mapout;
|
bool tilemapout;
|
||||||
|
char *attrmapfile;
|
||||||
|
bool attrmapout;
|
||||||
char *palfile;
|
char *palfile;
|
||||||
bool palout;
|
bool palout;
|
||||||
char *outfile;
|
char *outfile;
|
||||||
@@ -40,8 +44,10 @@ struct RGBColor {
|
|||||||
struct ImageOptions {
|
struct ImageOptions {
|
||||||
bool horizontal;
|
bool horizontal;
|
||||||
int trim;
|
int trim;
|
||||||
char *mapfile;
|
char *tilemapfile;
|
||||||
bool mapout;
|
bool tilemapout;
|
||||||
|
char *attrmapfile;
|
||||||
|
bool attrmapout;
|
||||||
char *palfile;
|
char *palfile;
|
||||||
bool palout;
|
bool palout;
|
||||||
};
|
};
|
||||||
@@ -49,6 +55,7 @@ struct ImageOptions {
|
|||||||
struct PNGImage {
|
struct PNGImage {
|
||||||
png_struct *png;
|
png_struct *png;
|
||||||
png_info *info;
|
png_info *info;
|
||||||
|
|
||||||
png_byte **data;
|
png_byte **data;
|
||||||
int width;
|
int width;
|
||||||
int height;
|
int height;
|
||||||
@@ -60,8 +67,8 @@ struct RawIndexedImage {
|
|||||||
uint8_t **data;
|
uint8_t **data;
|
||||||
struct RGBColor *palette;
|
struct RGBColor *palette;
|
||||||
int num_colors;
|
int num_colors;
|
||||||
int width;
|
unsigned int width;
|
||||||
int height;
|
unsigned int height;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBImage {
|
struct GBImage {
|
||||||
@@ -71,12 +78,12 @@ struct GBImage {
|
|||||||
int trim;
|
int trim;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Tilemap {
|
struct Mapfile {
|
||||||
uint8_t *data;
|
uint8_t *data;
|
||||||
int size;
|
int size;
|
||||||
};
|
};
|
||||||
|
|
||||||
int depth, colors;
|
extern int depth, colors;
|
||||||
|
|
||||||
#include "gfx/makepng.h"
|
#include "gfx/makepng.h"
|
||||||
#include "gfx/gb.h"
|
#include "gfx/gb.h"
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Generic hashmap implementation (C++ templates are calling...) */
|
||||||
|
#ifndef RGBDS_LINK_HASHMAP_H
|
||||||
|
#define RGBDS_LINK_HASHMAP_H
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#define HASH_NB_BITS 32
|
||||||
|
#define HALF_HASH_NB_BITS 16
|
||||||
|
static_assert(HALF_HASH_NB_BITS * 2 == HASH_NB_BITS, "");
|
||||||
|
#define HASHMAP_NB_BUCKETS (1 << HALF_HASH_NB_BITS)
|
||||||
|
|
||||||
|
/* HashMapEntry is internal, please do not attempt to use it */
|
||||||
|
typedef struct HashMapEntry *HashMap[HASHMAP_NB_BUCKETS];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an element to a hashmap.
|
||||||
|
* @warning Adding a new element with an already-present key will not cause an
|
||||||
|
* error, this must be handled externally.
|
||||||
|
* @warning Inserting a NULL will make `hash_GetElement`'s return ambiguous!
|
||||||
|
* @param map The HashMap to add the element to
|
||||||
|
* @param key The key with which the element will be stored and retrieved
|
||||||
|
* @param element The element to add
|
||||||
|
* @return True if a collision occurred (for statistics)
|
||||||
|
*/
|
||||||
|
bool hash_AddElement(HashMap map, char const *key, void *element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces an element with an already-present key in a hashmap.
|
||||||
|
* @warning Inserting a NULL will make `hash_GetElement`'s return ambiguous!
|
||||||
|
* @param map The HashMap to replace the element in
|
||||||
|
* @param key The key with which the element will be stored and retrieved
|
||||||
|
* @param element The element to replace
|
||||||
|
* @return True if the element was found and replaced
|
||||||
|
*/
|
||||||
|
bool hash_ReplaceElement(HashMap const map, char const *key, void *element);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an element from a hashmap.
|
||||||
|
* @param map The HashMap to remove the element from
|
||||||
|
* @param key The key to search the element with
|
||||||
|
* @return True if the element was found and removed
|
||||||
|
*/
|
||||||
|
bool hash_RemoveElement(HashMap map, char const *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an element in a hashmap.
|
||||||
|
* @param map The map to consider the elements of
|
||||||
|
* @param key The key to search an element for
|
||||||
|
* @return A pointer to the element, or NULL if not found. (NULL can be returned
|
||||||
|
* if such an element was added, but that sounds pretty silly.)
|
||||||
|
*/
|
||||||
|
void *hash_GetElement(HashMap const map, char const *key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Executes a function on each element in a hashmap.
|
||||||
|
* @param map The map to consider the elements of
|
||||||
|
* @param func The function to run. The first argument will be the element,
|
||||||
|
* the second will be `arg`.
|
||||||
|
* @param arg An argument to be passed to all function calls
|
||||||
|
*/
|
||||||
|
void hash_ForEach(HashMap const map, void (*func)(void *, void *), void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cleanly empties a hashmap from its contents.
|
||||||
|
* This does not `free` the data structure itself!
|
||||||
|
* @param map The map to empty
|
||||||
|
*/
|
||||||
|
void hash_EmptyMap(HashMap map);
|
||||||
|
|
||||||
|
#endif /* RGBDS_LINK_HASHMAP_H */
|
||||||
+78
-9
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014-2018, RGBDS contributors.
|
* Copyright (c) 2014-2020, RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
@@ -9,14 +9,83 @@
|
|||||||
#ifndef HELPERS_H
|
#ifndef HELPERS_H
|
||||||
#define HELPERS_H
|
#define HELPERS_H
|
||||||
|
|
||||||
#ifdef __GNUC__
|
// Of course, MSVC does not support C11, so no _Noreturn there...
|
||||||
/* GCC or compatible */
|
#ifdef _MSC_VER
|
||||||
#define noreturn_ __attribute__ ((noreturn))
|
#define _Noreturn __declspec(noreturn)
|
||||||
#define unused_ __attribute__ ((unused))
|
|
||||||
#else
|
|
||||||
/* Unsupported, but no need to throw a fit */
|
|
||||||
#define noreturn_
|
|
||||||
#define unused_
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Ideally, we'd use `__has_attribute` and `__has_builtin`, but these were only introduced in GCC 9
|
||||||
|
#ifdef __GNUC__ // GCC or compatible
|
||||||
|
#define format_(archetype, str_index, first_arg) \
|
||||||
|
__attribute__ ((format (archetype, str_index, first_arg)))
|
||||||
|
// In release builds, define "unreachable" as such, but trap in debug builds
|
||||||
|
#ifdef NDEBUG
|
||||||
|
#define unreachable_ __builtin_unreachable
|
||||||
|
#else
|
||||||
|
#define unreachable_ __builtin_trap
|
||||||
|
#endif
|
||||||
|
#else
|
||||||
|
// Unsupported, but no need to throw a fit
|
||||||
|
#define format_(archetype, str_index, first_arg)
|
||||||
|
// This seems to generate similar code to __builtin_unreachable, despite different semantics
|
||||||
|
// Note that executing this is undefined behavior (declared _Noreturn, but does return)
|
||||||
|
static inline _Noreturn unreachable_(void) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Use builtins whenever possible, and shim them otherwise
|
||||||
|
#ifdef __GNUC__ // GCC or compatible
|
||||||
|
#define ctz __builtin_ctz
|
||||||
|
#define clz __builtin_clz
|
||||||
|
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
#include <assert.h>
|
||||||
|
#include <intrin.h>
|
||||||
|
#pragma intrinsic(_BitScanReverse, _BitScanForward)
|
||||||
|
static inline int ctz(unsigned int x)
|
||||||
|
{
|
||||||
|
unsigned long cnt;
|
||||||
|
|
||||||
|
assert(x != 0);
|
||||||
|
_BitScanForward(&cnt, x);
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
static inline int clz(unsigned int x)
|
||||||
|
{
|
||||||
|
unsigned long cnt;
|
||||||
|
|
||||||
|
assert(x != 0);
|
||||||
|
_BitScanReverse(&cnt, x);
|
||||||
|
return 31 - cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
// FIXME: these are rarely used, and need testing...
|
||||||
|
#include <limits.h>
|
||||||
|
static inline int ctz(unsigned int x)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
while (!(x & 1)) {
|
||||||
|
x >>= 1;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int clz(unsigned int x)
|
||||||
|
{
|
||||||
|
int cnt = 0;
|
||||||
|
|
||||||
|
while (x <= UINT_MAX / 2) {
|
||||||
|
x <<= 1;
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Macros for stringification
|
||||||
|
#define STR(x) #x
|
||||||
|
#define EXPAND_AND_STR(x) STR(x)
|
||||||
|
|
||||||
#endif /* HELPERS_H */
|
#endif /* HELPERS_H */
|
||||||
|
|||||||
+11
-37
@@ -1,53 +1,27 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Assigning all sections a place */
|
||||||
#ifndef RGBDS_LINK_ASSIGN_H
|
#ifndef RGBDS_LINK_ASSIGN_H
|
||||||
#define RGBDS_LINK_ASSIGN_H
|
#define RGBDS_LINK_ASSIGN_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "common.h"
|
extern uint64_t nbSectionsToAssign;
|
||||||
#include "mylink.h"
|
|
||||||
|
|
||||||
/* Bank numbers as seen by the linker */
|
/**
|
||||||
enum eBankDefine {
|
* Assigns all sections a slice of the address space
|
||||||
BANK_INDEX_ROM0 = 0,
|
*/
|
||||||
BANK_INDEX_ROMX = BANK_INDEX_ROM0 + BANK_COUNT_ROM0,
|
void assign_AssignSections(void);
|
||||||
BANK_INDEX_WRAM0 = BANK_INDEX_ROMX + BANK_COUNT_ROMX,
|
|
||||||
BANK_INDEX_WRAMX = BANK_INDEX_WRAM0 + BANK_COUNT_WRAM0,
|
|
||||||
BANK_INDEX_VRAM = BANK_INDEX_WRAMX + BANK_COUNT_WRAMX,
|
|
||||||
BANK_INDEX_OAM = BANK_INDEX_VRAM + BANK_COUNT_VRAM,
|
|
||||||
BANK_INDEX_HRAM = BANK_INDEX_OAM + BANK_COUNT_OAM,
|
|
||||||
BANK_INDEX_SRAM = BANK_INDEX_HRAM + BANK_COUNT_HRAM,
|
|
||||||
BANK_INDEX_MAX = BANK_INDEX_SRAM + BANK_COUNT_SRAM
|
|
||||||
};
|
|
||||||
|
|
||||||
extern int32_t MaxBankUsed;
|
/**
|
||||||
extern int32_t MaxAvail[BANK_INDEX_MAX];
|
* `free`s all assignment memory that was allocated.
|
||||||
|
*/
|
||||||
int32_t area_Avail(int32_t bank);
|
void assign_Cleanup(void);
|
||||||
void AssignSections(void);
|
|
||||||
void CreateSymbolTable(void);
|
|
||||||
struct sSection *GetSectionByName(const char *name);
|
|
||||||
int32_t IsSectionNameInUse(const char *name);
|
|
||||||
void SetLinkerscriptName(char *tzLinkerscriptFile);
|
|
||||||
int32_t IsSectionSameTypeBankAndFloating(const char *name,
|
|
||||||
enum eSectionType type, int32_t bank);
|
|
||||||
uint32_t AssignSectionAddressAndBankByName(const char *name, uint32_t address,
|
|
||||||
int32_t bank);
|
|
||||||
|
|
||||||
int BankIndexIsROM0(int32_t bank);
|
|
||||||
int BankIndexIsROMX(int32_t bank);
|
|
||||||
int BankIndexIsWRAM0(int32_t bank);
|
|
||||||
int BankIndexIsWRAMX(int32_t bank);
|
|
||||||
int BankIndexIsVRAM(int32_t bank);
|
|
||||||
int BankIndexIsOAM(int32_t bank);
|
|
||||||
int BankIndexIsHRAM(int32_t bank);
|
|
||||||
int BankIndexIsSRAM(int32_t bank);
|
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_ASSIGN_H */
|
#endif /* RGBDS_LINK_ASSIGN_H */
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RGBDS_LINK_LIBRARY_H
|
|
||||||
#define RGBDS_LINK_LIBRARY_H
|
|
||||||
|
|
||||||
void AddNeededModules(void);
|
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_LIBRARY_H */
|
|
||||||
+72
-3
@@ -1,17 +1,86 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Declarations that all modules use, as well as `main` and related */
|
||||||
#ifndef RGBDS_LINK_MAIN_H
|
#ifndef RGBDS_LINK_MAIN_H
|
||||||
#define RGBDS_LINK_MAIN_H
|
#define RGBDS_LINK_MAIN_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
extern int32_t fillchar;
|
#include "helpers.h"
|
||||||
extern char *smartlinkstartsymbol;
|
|
||||||
|
/* Variables related to CLI options */
|
||||||
|
extern bool isDmgMode;
|
||||||
|
extern char *linkerScriptName;
|
||||||
|
extern char const *mapFileName;
|
||||||
|
extern char const *symFileName;
|
||||||
|
extern char const *overlayFileName;
|
||||||
|
extern char const *outputFileName;
|
||||||
|
extern uint8_t padValue;
|
||||||
|
extern bool is32kMode;
|
||||||
|
extern bool beVerbose;
|
||||||
|
extern bool isWRA0Mode;
|
||||||
|
extern bool disablePadding;
|
||||||
|
|
||||||
|
struct FileStackNode {
|
||||||
|
struct FileStackNode *parent;
|
||||||
|
/* Line at which the parent context was exited; meaningless for the root level */
|
||||||
|
uint32_t lineNo;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
NODE_REPT,
|
||||||
|
NODE_FILE,
|
||||||
|
NODE_MACRO,
|
||||||
|
} type;
|
||||||
|
union {
|
||||||
|
char *name; /* NODE_FILE, NODE_MACRO */
|
||||||
|
struct { /* NODE_REPT */
|
||||||
|
uint32_t reptDepth;
|
||||||
|
uint32_t *iters;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Helper macro for printing verbose-mode messages */
|
||||||
|
#define verbosePrint(...) do { \
|
||||||
|
if (beVerbose) \
|
||||||
|
fprintf(stderr, __VA_ARGS__); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dump a file stack to stderr
|
||||||
|
* @param node The leaf node to dump the context of
|
||||||
|
*/
|
||||||
|
char const *dumpFileStack(struct FileStackNode const *node);
|
||||||
|
|
||||||
|
void warning(struct FileStackNode const *where, uint32_t lineNo,
|
||||||
|
char const *fmt, ...) format_(printf, 3, 4);
|
||||||
|
|
||||||
|
void error(struct FileStackNode const *where, uint32_t lineNo,
|
||||||
|
char const *fmt, ...) format_(printf, 3, 4);
|
||||||
|
|
||||||
|
_Noreturn void fatal(struct FileStackNode const *where, uint32_t lineNo,
|
||||||
|
char const *fmt, ...) format_(printf, 3, 4);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a file if specified, and aborts on error.
|
||||||
|
* @param fileName The name of the file to open; if NULL, no file will be opened
|
||||||
|
* @param mode The mode to open the file with
|
||||||
|
* @return A pointer to a valid FILE structure, or NULL if fileName was NULL
|
||||||
|
*/
|
||||||
|
FILE *openFile(char const *fileName, char const *mode);
|
||||||
|
|
||||||
|
#define closeFile(file) do { \
|
||||||
|
FILE *tmp = file; \
|
||||||
|
if (tmp) \
|
||||||
|
fclose(tmp); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_MAIN_H */
|
#endif /* RGBDS_LINK_MAIN_H */
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RGBDS_LINK_MAPFILE_H
|
|
||||||
#define RGBDS_LINK_MAPFILE_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
void SetMapfileName(char *name);
|
|
||||||
void SetSymfileName(char *name);
|
|
||||||
void CloseMapfile(void);
|
|
||||||
void MapfileWriteSection(const struct sSection *pSect);
|
|
||||||
void MapfileInitBank(int32_t bank);
|
|
||||||
void MapfileCloseBank(int32_t slack);
|
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_MAPFILE_H */
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef RGBDS_LINK_LINK_H
|
|
||||||
#define RGBDS_LINK_LINK_H
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#include "linkdefs.h"
|
|
||||||
|
|
||||||
extern int32_t options;
|
|
||||||
|
|
||||||
#define OPT_TINY 0x01
|
|
||||||
#define OPT_SMART_C_LINK 0x02
|
|
||||||
#define OPT_OVERLAY 0x04
|
|
||||||
#define OPT_CONTWRAM 0x08
|
|
||||||
#define OPT_DMG_MODE 0x10
|
|
||||||
|
|
||||||
struct sSection {
|
|
||||||
int32_t nBank;
|
|
||||||
int32_t nOrg;
|
|
||||||
int32_t nAlign;
|
|
||||||
uint8_t oAssigned;
|
|
||||||
|
|
||||||
char *pzName;
|
|
||||||
int32_t nByteSize;
|
|
||||||
enum eSectionType Type;
|
|
||||||
uint8_t *pData;
|
|
||||||
int32_t nNumberOfSymbols;
|
|
||||||
struct sSymbol **tSymbols;
|
|
||||||
struct sPatch *pPatches;
|
|
||||||
struct sSection *pNext;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sSymbol {
|
|
||||||
char *pzName;
|
|
||||||
enum eSymbolType Type;
|
|
||||||
|
|
||||||
/* The following 3 items only valid when Type!=SYM_IMPORT */
|
|
||||||
int32_t nSectionID; /* Internal to object.c */
|
|
||||||
struct sSection *pSection;
|
|
||||||
int32_t nOffset;
|
|
||||||
|
|
||||||
char *pzObjFileName; /* Object file where the symbol is located. */
|
|
||||||
char *pzFileName; /* Source file where the symbol was defined. */
|
|
||||||
uint32_t nFileLine; /* Line where the symbol was defined. */
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sPatch {
|
|
||||||
char *pzFilename;
|
|
||||||
int32_t nLineNo;
|
|
||||||
int32_t nOffset;
|
|
||||||
enum ePatchType Type;
|
|
||||||
int32_t nRPNSize;
|
|
||||||
uint8_t *pRPN;
|
|
||||||
struct sPatch *pNext;
|
|
||||||
uint8_t oRelocPatch;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern struct sSection *pSections;
|
|
||||||
extern struct sSection *pLibSections;
|
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_LINK_H */
|
|
||||||
+30
-2
@@ -1,14 +1,42 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Declarations related to processing of object (.o) files */
|
||||||
|
|
||||||
#ifndef RGBDS_LINK_OBJECT_H
|
#ifndef RGBDS_LINK_OBJECT_H
|
||||||
#define RGBDS_LINK_OBJECT_H
|
#define RGBDS_LINK_OBJECT_H
|
||||||
|
|
||||||
void obj_Readfile(char *tzObjectfile);
|
/**
|
||||||
|
* Read an object (.o) file, and add its info to the data structures.
|
||||||
|
* @param fileName A path to the object file to be read
|
||||||
|
* @param i The ID of the file
|
||||||
|
*/
|
||||||
|
void obj_ReadFile(char const *fileName, unsigned int i);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform validation on the object files' contents
|
||||||
|
*/
|
||||||
|
void obj_DoSanityChecks(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluate all assertions
|
||||||
|
*/
|
||||||
|
void obj_CheckAssertions(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets up object file reading
|
||||||
|
* @param nbFiles The number of object files that will be read
|
||||||
|
*/
|
||||||
|
void obj_Setup(unsigned int nbFiles);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `free`s all object memory that was allocated.
|
||||||
|
*/
|
||||||
|
void obj_Cleanup(void);
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_OBJECT_H */
|
#endif /* RGBDS_LINK_OBJECT_H */
|
||||||
|
|||||||
+23
-4
@@ -1,16 +1,35 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Outputting the result of linking */
|
||||||
#ifndef RGBDS_LINK_OUTPUT_H
|
#ifndef RGBDS_LINK_OUTPUT_H
|
||||||
#define RGBDS_LINK_OUTPUT_H
|
#define RGBDS_LINK_OUTPUT_H
|
||||||
|
|
||||||
void out_Setname(char *tzOutputfile);
|
#include <stdint.h>
|
||||||
void out_SetOverlayname(char *tzOverlayfile);
|
|
||||||
void Output(void);
|
#include "link/section.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a section for output.
|
||||||
|
* @param section The section to add
|
||||||
|
*/
|
||||||
|
void out_AddSection(struct Section const *section);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds an assigned section overlapping another one.
|
||||||
|
* @param section The section that is being overlapped
|
||||||
|
* @return A section overlapping it
|
||||||
|
*/
|
||||||
|
struct Section const *out_OverlappingSection(struct Section const *section);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes all output (bin, sym, map) files.
|
||||||
|
*/
|
||||||
|
void out_WriteFiles(void);
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_OUTPUT_H */
|
#endif /* RGBDS_LINK_OUTPUT_H */
|
||||||
|
|||||||
+30
-3
@@ -1,17 +1,44 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Applying patches to SECTIONs */
|
||||||
#ifndef RGBDS_LINK_PATCH_H
|
#ifndef RGBDS_LINK_PATCH_H
|
||||||
#define RGBDS_LINK_PATCH_H
|
#define RGBDS_LINK_PATCH_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void Patch(void);
|
#include "link/section.h"
|
||||||
extern int32_t nPC;
|
|
||||||
|
#include "linkdefs.h"
|
||||||
|
|
||||||
|
struct Assertion {
|
||||||
|
struct Patch patch;
|
||||||
|
// enum AssertionType type; The `patch`'s field is instead re-used
|
||||||
|
char *message;
|
||||||
|
/*
|
||||||
|
* This would be redundant with `.section->fileSymbols`... but
|
||||||
|
* `section` is sometimes NULL!
|
||||||
|
*/
|
||||||
|
struct Symbol **fileSymbols;
|
||||||
|
|
||||||
|
struct Assertion *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks all assertions
|
||||||
|
* @return true if assertion failed
|
||||||
|
*/
|
||||||
|
void patch_CheckAssertions(struct Assertion *assertion);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies all SECTIONs' patches to them
|
||||||
|
*/
|
||||||
|
void patch_ApplyPatches(void);
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_PATCH_H */
|
#endif /* RGBDS_LINK_PATCH_H */
|
||||||
|
|||||||
+18
-12
@@ -1,30 +1,36 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Parsing a linker script */
|
||||||
#ifndef RGBDS_LINK_SCRIPT_H
|
#ifndef RGBDS_LINK_SCRIPT_H
|
||||||
#define RGBDS_LINK_SCRIPT_H
|
#define RGBDS_LINK_SCRIPT_H
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#include "helpers.h"
|
extern FILE * linkerScript;
|
||||||
|
|
||||||
noreturn_ void script_fatalerror(const char *fmt, ...);
|
struct SectionPlacement {
|
||||||
|
struct Section *section;
|
||||||
|
uint16_t org;
|
||||||
|
uint32_t bank;
|
||||||
|
};
|
||||||
|
|
||||||
void script_Parse(const char *path);
|
extern uint64_t script_lineNo;
|
||||||
|
|
||||||
void script_IncludeFile(const char *path);
|
/**
|
||||||
int32_t script_IncludeDepthGet(void);
|
* Parses the linker script to return the next section constraint
|
||||||
void script_IncludePop(void);
|
* @return A pointer to a struct, or NULL on EOF. The pointer shouldn't be freed
|
||||||
|
*/
|
||||||
|
struct SectionPlacement *script_NextSection(void);
|
||||||
|
|
||||||
void script_InitSections(void);
|
/**
|
||||||
void script_SetCurrentSectionType(const char *type, uint32_t bank);
|
* `free`s all assignment memory that was allocated.
|
||||||
void script_SetAddress(uint32_t addr);
|
*/
|
||||||
void script_SetAlignment(uint32_t alignment);
|
void script_Cleanup(void);
|
||||||
void script_OutputSection(const char *section_name);
|
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_SCRIPT_H */
|
#endif /* RGBDS_LINK_SCRIPT_H */
|
||||||
|
|||||||
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Declarations manipulating symbols */
|
||||||
|
#ifndef RGBDS_LINK_SECTION_H
|
||||||
|
#define RGBDS_LINK_SECTION_H
|
||||||
|
|
||||||
|
/* GUIDELINE: external code MUST NOT BE AWARE of the data structure used!! */
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "link/main.h"
|
||||||
|
|
||||||
|
#include "linkdefs.h"
|
||||||
|
|
||||||
|
struct FileStackNode;
|
||||||
|
struct Section;
|
||||||
|
|
||||||
|
struct AttachedSymbol {
|
||||||
|
struct Symbol *symbol;
|
||||||
|
struct AttachedSymbol *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Patch {
|
||||||
|
struct FileStackNode const *src;
|
||||||
|
uint32_t lineNo;
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t pcSectionID;
|
||||||
|
uint32_t pcOffset;
|
||||||
|
enum PatchType type;
|
||||||
|
uint32_t rpnSize;
|
||||||
|
uint8_t *rpnExpression;
|
||||||
|
|
||||||
|
struct Section const *pcSection;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Section {
|
||||||
|
/* Info contained in the object files */
|
||||||
|
char *name;
|
||||||
|
uint16_t size;
|
||||||
|
uint16_t offset;
|
||||||
|
enum SectionType type;
|
||||||
|
enum SectionModifier modifier;
|
||||||
|
bool isAddressFixed;
|
||||||
|
uint16_t org;
|
||||||
|
bool isBankFixed;
|
||||||
|
uint32_t bank;
|
||||||
|
bool isAlignFixed;
|
||||||
|
uint16_t alignMask;
|
||||||
|
uint16_t alignOfs;
|
||||||
|
uint8_t *data; /* Array of size `size`*/
|
||||||
|
uint32_t nbPatches;
|
||||||
|
struct Patch *patches;
|
||||||
|
/* Extra info computed during linking */
|
||||||
|
struct Symbol **fileSymbols;
|
||||||
|
uint32_t nbSymbols;
|
||||||
|
struct Symbol const **symbols;
|
||||||
|
struct Section *nextu; /* The next "component" of this unionized sect */
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execute a callback for each section currently registered.
|
||||||
|
* This is to avoid exposing the data structure in which sections are stored.
|
||||||
|
* @param callback The function to call for each structure;
|
||||||
|
* the first argument will be a pointer to the structure,
|
||||||
|
* the second argument will be the pointer `arg`.
|
||||||
|
* @param arg A pointer which will be passed to all calls to `callback`.
|
||||||
|
*/
|
||||||
|
void sect_ForEach(void (*callback)(struct Section *, void *), void *arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers a section to be processed.
|
||||||
|
* @param section The section to register.
|
||||||
|
*/
|
||||||
|
void sect_AddSection(struct Section *section);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a section by its name.
|
||||||
|
* @param name The name of the section to look for
|
||||||
|
* @return A pointer to the section, or NULL if it wasn't found
|
||||||
|
*/
|
||||||
|
struct Section *sect_GetSection(char const *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `free`s all section memory that was allocated.
|
||||||
|
*/
|
||||||
|
void sect_CleanupSections(void);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if all sections meet reasonable criteria, such as max size
|
||||||
|
*/
|
||||||
|
void sect_DoSanityChecks(void);
|
||||||
|
|
||||||
|
#endif /* RGBDS_LINK_SECTION_H */
|
||||||
+47
-7
@@ -1,21 +1,61 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
* Copyright (c) 1997-2019, Carsten Sorensen and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* Declarations manipulating symbols */
|
||||||
#ifndef RGBDS_LINK_SYMBOL_H
|
#ifndef RGBDS_LINK_SYMBOL_H
|
||||||
#define RGBDS_LINK_SYMBOL_H
|
#define RGBDS_LINK_SYMBOL_H
|
||||||
|
|
||||||
|
/* GUIDELINE: external code MUST NOT BE AWARE of the data structure used!! */
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
void sym_Init(void);
|
#include "linkdefs.h"
|
||||||
void sym_CreateSymbol(char *tzName, int32_t nValue, int32_t nBank,
|
|
||||||
char *tzObjFileName, char *tzFileName,
|
struct FileStackNode;
|
||||||
uint32_t nFileLine);
|
|
||||||
int32_t sym_GetValue(char *tzName);
|
struct Symbol {
|
||||||
int32_t sym_GetBank(char *tzName);
|
/* Info contained in the object files */
|
||||||
|
char *name;
|
||||||
|
enum ExportLevel type;
|
||||||
|
char const *objFileName;
|
||||||
|
struct FileStackNode const *src;
|
||||||
|
int32_t lineNo;
|
||||||
|
int32_t sectionID;
|
||||||
|
union {
|
||||||
|
int32_t offset;
|
||||||
|
int32_t value;
|
||||||
|
};
|
||||||
|
/* Extra info computed during linking */
|
||||||
|
struct Section *section;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Execute a callback for each symbol currently registered.
|
||||||
|
* This is done to avoid exposing the data structure in which symbol are stored.
|
||||||
|
* @param callback The function to call for each symbol;
|
||||||
|
* the first argument will be a pointer to the symbol,
|
||||||
|
* the second argument will be the pointer `arg`.
|
||||||
|
* @param arg A pointer which will be passed to all calls to `callback`.
|
||||||
|
*/
|
||||||
|
void sym_ForEach(void (*callback)(struct Symbol *, void *), void *arg);
|
||||||
|
|
||||||
|
void sym_AddSymbol(struct Symbol *symbol);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a symbol in all the defined symbols.
|
||||||
|
* @param name The name of the symbol to look for
|
||||||
|
* @return A pointer to the symbol, or NULL if not found.
|
||||||
|
*/
|
||||||
|
struct Symbol *sym_GetSymbol(char const *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `free`s all symbol memory that was allocated.
|
||||||
|
*/
|
||||||
|
void sym_CleanupSymbols(void);
|
||||||
|
|
||||||
#endif /* RGBDS_LINK_SYMBOL_H */
|
#endif /* RGBDS_LINK_SYMBOL_H */
|
||||||
|
|||||||
+98
-19
@@ -9,13 +9,27 @@
|
|||||||
#ifndef RGBDS_LINKDEFS_H
|
#ifndef RGBDS_LINKDEFS_H
|
||||||
#define RGBDS_LINKDEFS_H
|
#define RGBDS_LINKDEFS_H
|
||||||
|
|
||||||
enum eRpnData {
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define RGBDS_OBJECT_VERSION_STRING "RGB%1u"
|
||||||
|
#define RGBDS_OBJECT_VERSION_NUMBER 9U
|
||||||
|
#define RGBDS_OBJECT_REV 7U
|
||||||
|
|
||||||
|
enum AssertionType {
|
||||||
|
ASSERT_WARN,
|
||||||
|
ASSERT_ERROR,
|
||||||
|
ASSERT_FATAL
|
||||||
|
};
|
||||||
|
|
||||||
|
enum RPNCommand {
|
||||||
RPN_ADD = 0x00,
|
RPN_ADD = 0x00,
|
||||||
RPN_SUB = 0x01,
|
RPN_SUB = 0x01,
|
||||||
RPN_MUL = 0x02,
|
RPN_MUL = 0x02,
|
||||||
RPN_DIV = 0x03,
|
RPN_DIV = 0x03,
|
||||||
RPN_MOD = 0x04,
|
RPN_MOD = 0x04,
|
||||||
RPN_UNSUB = 0x05,
|
RPN_UNSUB = 0x05,
|
||||||
|
RPN_EXP = 0x06,
|
||||||
|
|
||||||
RPN_OR = 0x10,
|
RPN_OR = 0x10,
|
||||||
RPN_AND = 0x11,
|
RPN_AND = 0x11,
|
||||||
@@ -41,33 +55,98 @@ enum eRpnData {
|
|||||||
RPN_BANK_SELF = 0x52,
|
RPN_BANK_SELF = 0x52,
|
||||||
|
|
||||||
RPN_HRAM = 0x60,
|
RPN_HRAM = 0x60,
|
||||||
|
RPN_RST = 0x61,
|
||||||
|
|
||||||
RPN_CONST = 0x80,
|
RPN_CONST = 0x80,
|
||||||
RPN_SYM = 0x81
|
RPN_SYM = 0x81
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eSectionType {
|
enum SectionType {
|
||||||
SECT_WRAM0 = 0x00,
|
SECTTYPE_WRAM0,
|
||||||
SECT_VRAM = 0x01,
|
SECTTYPE_VRAM,
|
||||||
SECT_ROMX = 0x02,
|
SECTTYPE_ROMX,
|
||||||
SECT_ROM0 = 0x03,
|
SECTTYPE_ROM0,
|
||||||
SECT_HRAM = 0x04,
|
SECTTYPE_HRAM,
|
||||||
SECT_WRAMX = 0x05,
|
SECTTYPE_WRAMX,
|
||||||
SECT_SRAM = 0x06,
|
SECTTYPE_SRAM,
|
||||||
SECT_OAM = 0x07
|
SECTTYPE_OAM,
|
||||||
|
|
||||||
|
SECTTYPE_INVALID
|
||||||
};
|
};
|
||||||
|
|
||||||
enum eSymbolType {
|
enum SectionModifier {
|
||||||
SYM_LOCAL = 0x00,
|
SECTION_NORMAL,
|
||||||
SYM_IMPORT = 0x01,
|
SECTION_UNION,
|
||||||
SYM_EXPORT = 0x02
|
SECTION_FRAGMENT
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ePatchType {
|
extern char const * const sectionModNames[];
|
||||||
PATCH_BYTE = 0x00,
|
|
||||||
PATCH_WORD_L = 0x01,
|
/**
|
||||||
PATCH_LONG_L = 0x02,
|
* Tells whether a section has data in its object file definition,
|
||||||
PATCH_BYTE_JR = 0x03
|
* depending on type.
|
||||||
|
* @param type The section's type
|
||||||
|
* @return `true` if the section's definition includes data
|
||||||
|
*/
|
||||||
|
static inline bool sect_HasData(enum SectionType type)
|
||||||
|
{
|
||||||
|
return type == SECTTYPE_ROM0 || type == SECTTYPE_ROMX;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum ExportLevel {
|
||||||
|
SYMTYPE_LOCAL,
|
||||||
|
SYMTYPE_IMPORT,
|
||||||
|
SYMTYPE_EXPORT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum PatchType {
|
||||||
|
PATCHTYPE_BYTE,
|
||||||
|
PATCHTYPE_WORD,
|
||||||
|
PATCHTYPE_LONG,
|
||||||
|
PATCHTYPE_JR,
|
||||||
|
|
||||||
|
PATCHTYPE_INVALID
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BANK_MIN_ROM0 0
|
||||||
|
#define BANK_MAX_ROM0 0
|
||||||
|
#define BANK_MIN_ROMX 1
|
||||||
|
#define BANK_MAX_ROMX 511
|
||||||
|
#define BANK_MIN_VRAM 0
|
||||||
|
#define BANK_MAX_VRAM 1
|
||||||
|
#define BANK_MIN_SRAM 0
|
||||||
|
#define BANK_MAX_SRAM 15
|
||||||
|
#define BANK_MIN_WRAM0 0
|
||||||
|
#define BANK_MAX_WRAM0 0
|
||||||
|
#define BANK_MIN_WRAMX 1
|
||||||
|
#define BANK_MAX_WRAMX 7
|
||||||
|
#define BANK_MIN_OAM 0
|
||||||
|
#define BANK_MAX_OAM 0
|
||||||
|
#define BANK_MIN_HRAM 0
|
||||||
|
#define BANK_MAX_HRAM 0
|
||||||
|
|
||||||
|
extern uint16_t startaddr[];
|
||||||
|
extern uint16_t maxsize[];
|
||||||
|
extern uint32_t bankranges[][2];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a memory region's end address (last byte), eg. 0x7FFF
|
||||||
|
* @return The address of the last byte in that memory region
|
||||||
|
*/
|
||||||
|
static inline uint16_t endaddr(enum SectionType type)
|
||||||
|
{
|
||||||
|
return startaddr[type] + maxsize[type] - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a memory region's number of banks
|
||||||
|
* @return The number of banks, 1 for regions without banking
|
||||||
|
*/
|
||||||
|
static inline uint32_t nbbanks(enum SectionType type)
|
||||||
|
{
|
||||||
|
return bankranges[type][1] - bankranges[type][0] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern char const * const typeNames[SECTTYPE_INVALID];
|
||||||
|
|
||||||
#endif /* RGBDS_LINKDEFS_H */
|
#endif /* RGBDS_LINKDEFS_H */
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 1997-2021, RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef RGBDS_OP_MATH_H
|
||||||
|
#define RGBDS_OP_MATH_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
int32_t op_divide(int32_t dividend, int32_t divisor);
|
||||||
|
int32_t op_modulo(int32_t dividend, int32_t divisor);
|
||||||
|
int32_t op_exponent(int32_t base, uint32_t power);
|
||||||
|
int32_t op_shift_left(int32_t value, int32_t amount);
|
||||||
|
int32_t op_shift_right(int32_t value, int32_t amount);
|
||||||
|
|
||||||
|
#endif /* RGBDS_OP_MATH_H */
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020 RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* platform-specific hacks */
|
||||||
|
|
||||||
|
#ifndef RGBDS_PLATFORM_H
|
||||||
|
#define RGBDS_PLATFORM_H
|
||||||
|
|
||||||
|
/* MSVC doesn't have strncasecmp, use a suitable replacement */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# include <string.h>
|
||||||
|
# define strncasecmp _strnicmp
|
||||||
|
#else
|
||||||
|
# include <strings.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MSVC has deprecated strdup in favor of _strdup */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# define strdup _strdup
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MSVC prefixes the names of S_* macros with underscores,
|
||||||
|
and doesn't define any S_IS* macros. Define them ourselves */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# define S_IFMT _S_IFMT
|
||||||
|
# define S_IFDIR _S_IFDIR
|
||||||
|
# define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MSVC doesn't use POSIX types or defines for `read` */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# include <io.h>
|
||||||
|
# define STDIN_FILENO 0
|
||||||
|
# define STDOUT_FILENO 1
|
||||||
|
# define STDERR_FILENO 2
|
||||||
|
# define ssize_t int
|
||||||
|
# define SSIZE_MAX INT_MAX
|
||||||
|
#else
|
||||||
|
# include <fcntl.h>
|
||||||
|
# include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* MSVC doesn't support `[static N]` for array arguments from C99 */
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# define MIN_NB_ELMS(N)
|
||||||
|
#else
|
||||||
|
# define MIN_NB_ELMS(N) static (N)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// MSVC uses a different name for O_RDWR, and needs an additional _O_BINARY flag
|
||||||
|
#ifdef _MSC_VER
|
||||||
|
# include <fcntl.h>
|
||||||
|
# define O_RDWR _O_RDWR
|
||||||
|
# define S_ISREG(field) ((field) & _S_IFREG)
|
||||||
|
# define O_BINARY _O_BINARY
|
||||||
|
#elif !defined(O_BINARY) // Cross-compilers define O_BINARY
|
||||||
|
# define O_BINARY 0 // POSIX says we shouldn't care!
|
||||||
|
#endif // _MSC_VER
|
||||||
|
|
||||||
|
// Windows has stdin and stdout open as text by default, which we may not want
|
||||||
|
#if defined(_MSC_VER) || defined(__MINGW32__)
|
||||||
|
# include <io.h>
|
||||||
|
# define setmode(fd, mode) _setmode(fd, mode)
|
||||||
|
#else
|
||||||
|
# define setmode(fd, mode) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* RGBDS_PLATFORM_H */
|
||||||
+5
-4
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RGBDS.
|
* This file is part of RGBDS.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017-2018, Antonio Nino Diaz and RGBDS contributors.
|
* Copyright (c) 2017-2021, Antonio Nino Diaz and RGBDS contributors.
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
@@ -9,9 +9,10 @@
|
|||||||
#ifndef EXTERN_VERSION_H
|
#ifndef EXTERN_VERSION_H
|
||||||
#define EXTERN_VERSION_H
|
#define EXTERN_VERSION_H
|
||||||
|
|
||||||
#define PACKAGE_VERSION_MAJOR (0)
|
#define PACKAGE_VERSION_MAJOR 0
|
||||||
#define PACKAGE_VERSION_MINOR (3)
|
#define PACKAGE_VERSION_MINOR 5
|
||||||
#define PACKAGE_VERSION_PATCH (7)
|
#define PACKAGE_VERSION_PATCH 0
|
||||||
|
#define PACKAGE_VERSION_RC 2
|
||||||
|
|
||||||
const char *get_package_version_string(void);
|
const char *get_package_version_string(void);
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,128 @@
|
|||||||
|
#
|
||||||
|
# This file is part of RGBDS.
|
||||||
|
#
|
||||||
|
# Copyright (c) 2020 RGBDS contributors.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
|
||||||
|
set(common_src
|
||||||
|
"extern/err.c"
|
||||||
|
"extern/getopt.c"
|
||||||
|
"version.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
find_package(PkgConfig)
|
||||||
|
if(MSVC OR NOT PKG_CONFIG_FOUND)
|
||||||
|
# fallback to find_package
|
||||||
|
find_package(PNG REQUIRED)
|
||||||
|
else()
|
||||||
|
pkg_check_modules(LIBPNG REQUIRED libpng)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
find_package(BISON REQUIRED)
|
||||||
|
set(BISON_FLAGS "-Wall")
|
||||||
|
# Set sompe optimization flags on versions that support them
|
||||||
|
if(BISON_VERSION VERSION_GREATER_EQUAL "3.5")
|
||||||
|
set(BISON_FLAGS "${BISON_FLAGS} -Dapi.token.raw=true")
|
||||||
|
endif()
|
||||||
|
if(BISON_VERSION VERSION_GREATER_EQUAL "3.6")
|
||||||
|
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=detailed")
|
||||||
|
elseif(BISON_VERSION VERSION_GREATER_EQUAL "3.0")
|
||||||
|
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.error=verbose")
|
||||||
|
endif()
|
||||||
|
if(BISON_VERSION VERSION_GREATER_EQUAL "3.0")
|
||||||
|
set(BISON_FLAGS "${BISON_FLAGS} -Dparse.lac=full")
|
||||||
|
set(BISON_FLAGS "${BISON_FLAGS} -Dlr.type=ielr")
|
||||||
|
endif()
|
||||||
|
BISON_TARGET(PARSER "asm/parser.y"
|
||||||
|
"${PROJECT_SOURCE_DIR}/src/asm/parser.c"
|
||||||
|
COMPILE_FLAGS "${BISON_FLAGS}"
|
||||||
|
DEFINES_FILE "${PROJECT_SOURCE_DIR}/src/asm/parser.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(rgbasm_src
|
||||||
|
"${BISON_PARSER_OUTPUT_SOURCE}"
|
||||||
|
"asm/charmap.c"
|
||||||
|
"asm/fixpoint.c"
|
||||||
|
"asm/format.c"
|
||||||
|
"asm/fstack.c"
|
||||||
|
"asm/lexer.c"
|
||||||
|
"asm/macro.c"
|
||||||
|
"asm/main.c"
|
||||||
|
"asm/opt.c"
|
||||||
|
"asm/output.c"
|
||||||
|
"asm/rpn.c"
|
||||||
|
"asm/section.c"
|
||||||
|
"asm/symbol.c"
|
||||||
|
"asm/util.c"
|
||||||
|
"asm/warning.c"
|
||||||
|
"extern/utf8decoder.c"
|
||||||
|
"hashmap.c"
|
||||||
|
"linkdefs.c"
|
||||||
|
"opmath.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(rgbfix_src
|
||||||
|
"fix/main.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(rgbgfx_src
|
||||||
|
"gfx/gb.c"
|
||||||
|
"gfx/main.c"
|
||||||
|
"gfx/makepng.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(rgblink_src
|
||||||
|
"link/assign.c"
|
||||||
|
"link/main.c"
|
||||||
|
"link/object.c"
|
||||||
|
"link/output.c"
|
||||||
|
"link/patch.c"
|
||||||
|
"link/script.c"
|
||||||
|
"link/section.c"
|
||||||
|
"link/symbol.c"
|
||||||
|
"hashmap.c"
|
||||||
|
"linkdefs.c"
|
||||||
|
"opmath.c"
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach(PROG "asm" "fix" "gfx" "link")
|
||||||
|
add_executable(rgb${PROG}
|
||||||
|
${rgb${PROG}_src}
|
||||||
|
${common_src}
|
||||||
|
)
|
||||||
|
install(TARGETS rgb${PROG} RUNTIME DESTINATION bin)
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
set(MANDIR "share/man")
|
||||||
|
set(man1 "asm/rgbasm.1"
|
||||||
|
"fix/rgbfix.1"
|
||||||
|
"gfx/rgbgfx.1"
|
||||||
|
"link/rgblink.1")
|
||||||
|
set(man5 "asm/rgbasm.5"
|
||||||
|
"link/rgblink.5"
|
||||||
|
"rgbds.5")
|
||||||
|
set(man7 "gbz80.7"
|
||||||
|
"rgbds.7")
|
||||||
|
|
||||||
|
foreach(SECTION "man1" "man5" "man7")
|
||||||
|
set(DEST "${MANDIR}/${SECTION}")
|
||||||
|
install(FILES ${${SECTION}} DESTINATION ${DEST})
|
||||||
|
endforeach()
|
||||||
|
|
||||||
|
if(LIBPNG_FOUND) # pkg-config
|
||||||
|
target_include_directories(rgbgfx PRIVATE ${LIBPNG_INCLUDE_DIRS})
|
||||||
|
target_link_directories(rgbgfx PRIVATE ${LIBPNG_LIBRARY_DIRS})
|
||||||
|
target_link_libraries(rgbgfx PRIVATE ${LIBPNG_LIBRARIES})
|
||||||
|
else()
|
||||||
|
target_compile_definitions(rgbgfx PRIVATE ${PNG_DEFINITIONS})
|
||||||
|
target_include_directories(rgbgfx PRIVATE ${PNG_INCLUDE_DIRS})
|
||||||
|
target_link_libraries(rgbgfx PRIVATE ${PNG_LIBRARIES})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
include(CheckLibraryExists)
|
||||||
|
check_library_exists("m" "sin" "" HAS_LIBM)
|
||||||
|
if(HAS_LIBM)
|
||||||
|
target_link_libraries(rgbasm PRIVATE "m")
|
||||||
|
endif()
|
||||||
+2
-2
@@ -1,2 +1,2 @@
|
|||||||
asmy.c
|
/parser.c
|
||||||
asmy.h
|
/parser.h
|
||||||
|
|||||||
-2118
File diff suppressed because it is too large
Load Diff
+215
-119
@@ -6,145 +6,241 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "asm/asm.h"
|
|
||||||
#include "asm/charmap.h"
|
#include "asm/charmap.h"
|
||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
#include "asm/output.h"
|
#include "asm/output.h"
|
||||||
|
#include "asm/util.h"
|
||||||
|
#include "asm/warning.h"
|
||||||
|
|
||||||
#include "extern/utf8decoder.h"
|
#include "hashmap.h"
|
||||||
|
|
||||||
struct Charmap globalCharmap = {0};
|
/*
|
||||||
|
* Charmaps are stored using a structure known as "trie".
|
||||||
|
* Essentially a tree, where each nodes stores a single character's worth of info:
|
||||||
|
* whether there exists a mapping that ends at the current character,
|
||||||
|
*/
|
||||||
|
struct Charnode {
|
||||||
|
bool isTerminal; /* Whether there exists a mapping that ends here */
|
||||||
|
uint8_t value; /* If the above is true, its corresponding value */
|
||||||
|
/* This MUST be indexes and not pointers, because pointers get invalidated by `realloc`!! */
|
||||||
|
size_t next[255]; /* Indexes of where to go next, 0 = nowhere */
|
||||||
|
};
|
||||||
|
|
||||||
int32_t readUTF8Char(char *dest, char *src)
|
#define INITIAL_CAPACITY 32
|
||||||
|
|
||||||
|
struct Charmap {
|
||||||
|
char *name;
|
||||||
|
size_t usedNodes; /* How many nodes are being used */
|
||||||
|
size_t capacity; /* How many nodes have been allocated */
|
||||||
|
struct Charnode nodes[]; /* first node is reserved for the root node */
|
||||||
|
};
|
||||||
|
|
||||||
|
static HashMap charmaps;
|
||||||
|
|
||||||
|
static struct Charmap *currentCharmap;
|
||||||
|
|
||||||
|
struct CharmapStackEntry {
|
||||||
|
struct Charmap *charmap;
|
||||||
|
struct CharmapStackEntry *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CharmapStackEntry *charmapStack;
|
||||||
|
|
||||||
|
static inline struct Charmap *charmap_Get(const char *name)
|
||||||
{
|
{
|
||||||
uint32_t state;
|
return hash_GetElement(charmaps, name);
|
||||||
uint32_t codep;
|
|
||||||
int32_t i;
|
|
||||||
|
|
||||||
for (i = 0, state = 0;; i++) {
|
|
||||||
if (decode(&state, &codep, (uint8_t)src[i]) == 1)
|
|
||||||
fatalerror("invalid UTF-8 character");
|
|
||||||
|
|
||||||
dest[i] = src[i];
|
|
||||||
|
|
||||||
i++;
|
|
||||||
if (state == 0) {
|
|
||||||
dest[i] = '\0';
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
dest[i] = src[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t charmap_Add(char *input, uint8_t output)
|
static inline struct Charmap *resizeCharmap(struct Charmap *map, size_t capacity)
|
||||||
{
|
{
|
||||||
int32_t i;
|
struct Charmap *new = realloc(map, sizeof(*map) + sizeof(*map->nodes) * capacity);
|
||||||
size_t input_length;
|
|
||||||
char temp1i[CHARMAPLENGTH + 1], temp2i[CHARMAPLENGTH + 1];
|
|
||||||
char temp1o = 0, temp2o = 0;
|
|
||||||
|
|
||||||
struct Charmap *charmap;
|
if (!new)
|
||||||
|
fatalerror("Failed to %s charmap: %s\n",
|
||||||
if (pCurrentSection) {
|
map ? "create" : "resize", strerror(errno));
|
||||||
if (pCurrentSection->charmap) {
|
new->capacity = capacity;
|
||||||
charmap = pCurrentSection->charmap;
|
return new;
|
||||||
} else {
|
|
||||||
charmap = calloc(1, sizeof(struct Charmap));
|
|
||||||
if (charmap == NULL)
|
|
||||||
fatalerror("Not enough memory for charmap");
|
|
||||||
|
|
||||||
pCurrentSection->charmap = charmap;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
charmap = &globalCharmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nPass == 2)
|
|
||||||
return charmap->count;
|
|
||||||
|
|
||||||
if (charmap->count > MAXCHARMAPS || strlen(input) > CHARMAPLENGTH)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
input_length = strlen(input);
|
|
||||||
if (input_length > 1) {
|
|
||||||
i = 0;
|
|
||||||
while (i < charmap->count + 1) {
|
|
||||||
if (input_length > strlen(charmap->input[i])) {
|
|
||||||
memcpy(temp1i, charmap->input[i],
|
|
||||||
CHARMAPLENGTH + 1);
|
|
||||||
memcpy(charmap->input[i], input, input_length);
|
|
||||||
temp1o = charmap->output[i];
|
|
||||||
charmap->output[i] = output;
|
|
||||||
i++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
while (i < charmap->count + 1) {
|
|
||||||
memcpy(temp2i, charmap->input[i], CHARMAPLENGTH + 1);
|
|
||||||
memcpy(charmap->input[i], temp1i, CHARMAPLENGTH + 1);
|
|
||||||
memcpy(temp1i, temp2i, CHARMAPLENGTH + 1);
|
|
||||||
temp2o = charmap->output[i];
|
|
||||||
charmap->output[i] = temp1o;
|
|
||||||
temp1o = temp2o;
|
|
||||||
i++;
|
|
||||||
}
|
|
||||||
memcpy(charmap->input[charmap->count + 1], temp1i,
|
|
||||||
CHARMAPLENGTH + 1);
|
|
||||||
charmap->output[charmap->count + 1] = temp1o;
|
|
||||||
} else {
|
|
||||||
memcpy(charmap->input[charmap->count], input, input_length);
|
|
||||||
charmap->output[charmap->count] = output;
|
|
||||||
}
|
|
||||||
return ++charmap->count;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t charmap_Convert(char **input)
|
static inline void initNode(struct Charnode *node)
|
||||||
{
|
{
|
||||||
struct Charmap *charmap;
|
node->isTerminal = false;
|
||||||
|
memset(node->next, 0, sizeof(node->next));
|
||||||
|
}
|
||||||
|
|
||||||
char outchar[CHARMAPLENGTH + 1];
|
struct Charmap *charmap_New(const char *name, const char *baseName)
|
||||||
char *buffer;
|
{
|
||||||
int32_t i, j, length;
|
struct Charmap *base = NULL;
|
||||||
|
|
||||||
if (pCurrentSection && pCurrentSection->charmap)
|
if (baseName != NULL) {
|
||||||
charmap = pCurrentSection->charmap;
|
base = charmap_Get(baseName);
|
||||||
|
|
||||||
|
if (base == NULL)
|
||||||
|
error("Base charmap '%s' doesn't exist\n", baseName);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Charmap *charmap = charmap_Get(name);
|
||||||
|
|
||||||
|
if (charmap) {
|
||||||
|
error("Charmap '%s' already exists\n", name);
|
||||||
|
return charmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Init the new charmap's fields */
|
||||||
|
if (base) {
|
||||||
|
charmap = resizeCharmap(NULL, base->capacity);
|
||||||
|
charmap->usedNodes = base->usedNodes;
|
||||||
|
|
||||||
|
memcpy(charmap->nodes, base->nodes, sizeof(base->nodes[0]) * charmap->usedNodes);
|
||||||
|
} else {
|
||||||
|
charmap = resizeCharmap(NULL, INITIAL_CAPACITY);
|
||||||
|
charmap->usedNodes = 1;
|
||||||
|
initNode(&charmap->nodes[0]); /* Init the root node */
|
||||||
|
}
|
||||||
|
charmap->name = strdup(name);
|
||||||
|
|
||||||
|
hash_AddElement(charmaps, charmap->name, charmap);
|
||||||
|
currentCharmap = charmap;
|
||||||
|
|
||||||
|
return charmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
void charmap_Delete(struct Charmap *charmap)
|
||||||
|
{
|
||||||
|
free(charmap->name);
|
||||||
|
free(charmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
void charmap_Set(const char *name)
|
||||||
|
{
|
||||||
|
struct Charmap *charmap = charmap_Get(name);
|
||||||
|
|
||||||
|
if (charmap == NULL)
|
||||||
|
error("Charmap '%s' doesn't exist\n", name);
|
||||||
else
|
else
|
||||||
charmap = &globalCharmap;
|
currentCharmap = charmap;
|
||||||
|
}
|
||||||
buffer = malloc(strlen(*input));
|
|
||||||
if (buffer == NULL)
|
void charmap_Push(void)
|
||||||
fatalerror("Not enough memory for buffer");
|
{
|
||||||
|
struct CharmapStackEntry *stackEntry;
|
||||||
length = 0;
|
|
||||||
while (**input) {
|
stackEntry = malloc(sizeof(*stackEntry));
|
||||||
j = 0;
|
if (stackEntry == NULL)
|
||||||
for (i = 0; i < charmap->count; i++) {
|
fatalerror("Failed to alloc charmap stack entry: %s\n", strerror(errno));
|
||||||
j = strlen(charmap->input[i]);
|
|
||||||
if (memcmp(*input, charmap->input[i], j) == 0) {
|
stackEntry->charmap = currentCharmap;
|
||||||
outchar[0] = charmap->output[i];
|
stackEntry->next = charmapStack;
|
||||||
outchar[1] = 0;
|
|
||||||
break;
|
charmapStack = stackEntry;
|
||||||
}
|
}
|
||||||
j = 0;
|
|
||||||
}
|
void charmap_Pop(void)
|
||||||
|
{
|
||||||
if (!j)
|
if (charmapStack == NULL) {
|
||||||
j = readUTF8Char(outchar, *input);
|
error("No entries in the charmap stack\n");
|
||||||
|
return;
|
||||||
if (!outchar[0]) {
|
}
|
||||||
buffer[length++] = 0;
|
|
||||||
} else {
|
struct CharmapStackEntry *top = charmapStack;
|
||||||
for (i = 0; outchar[i]; i++)
|
|
||||||
buffer[length++] = outchar[i];
|
currentCharmap = top->charmap;
|
||||||
}
|
charmapStack = top->next;
|
||||||
*input += j;
|
free(top);
|
||||||
}
|
}
|
||||||
*input = buffer;
|
|
||||||
return length;
|
void charmap_Add(char *mapping, uint8_t value)
|
||||||
|
{
|
||||||
|
struct Charnode *node = ¤tCharmap->nodes[0];
|
||||||
|
|
||||||
|
for (uint8_t c; *mapping; mapping++) {
|
||||||
|
c = *mapping - 1;
|
||||||
|
|
||||||
|
if (node->next[c]) {
|
||||||
|
node = ¤tCharmap->nodes[node->next[c]];
|
||||||
|
} else {
|
||||||
|
/* Register next available node */
|
||||||
|
node->next[c] = currentCharmap->usedNodes;
|
||||||
|
/* If no more nodes are available, get new ones */
|
||||||
|
if (currentCharmap->usedNodes == currentCharmap->capacity) {
|
||||||
|
currentCharmap->capacity *= 2;
|
||||||
|
currentCharmap = resizeCharmap(currentCharmap, currentCharmap->capacity);
|
||||||
|
hash_ReplaceElement(charmaps, currentCharmap->name, currentCharmap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Switch to and init new node */
|
||||||
|
node = ¤tCharmap->nodes[currentCharmap->usedNodes++];
|
||||||
|
initNode(node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node->isTerminal)
|
||||||
|
warning(WARNING_CHARMAP_REDEF, "Overriding charmap mapping\n");
|
||||||
|
|
||||||
|
node->isTerminal = true;
|
||||||
|
node->value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t charmap_Convert(char const *input, uint8_t *output)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* The goal is to match the longest mapping possible.
|
||||||
|
* For that, advance through the trie with each character read.
|
||||||
|
* If that would lead to a dead end, rewind characters until the last match, and output.
|
||||||
|
* If no match, read a UTF-8 codepoint and output that.
|
||||||
|
*/
|
||||||
|
size_t outputLen = 0;
|
||||||
|
struct Charnode const *node = ¤tCharmap->nodes[0];
|
||||||
|
struct Charnode const *match = NULL;
|
||||||
|
size_t rewindDistance = 0;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
/* We still want NULs to reach the `else` path, to give a chance to rewind */
|
||||||
|
uint8_t c = *input - 1;
|
||||||
|
|
||||||
|
if (*input && node->next[c]) {
|
||||||
|
input++; /* Consume that char */
|
||||||
|
rewindDistance++;
|
||||||
|
|
||||||
|
node = ¤tCharmap->nodes[node->next[c]];
|
||||||
|
if (node->isTerminal) {
|
||||||
|
match = node;
|
||||||
|
rewindDistance = 0; /* Rewind from after the match */
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
input -= rewindDistance; /* Rewind */
|
||||||
|
rewindDistance = 0;
|
||||||
|
node = ¤tCharmap->nodes[0];
|
||||||
|
|
||||||
|
if (match) { /* Arrived at a dead end with a match found */
|
||||||
|
*output++ = match->value;
|
||||||
|
outputLen++;
|
||||||
|
match = NULL; /* Reset match for next round */
|
||||||
|
|
||||||
|
} else if (*input) { /* No match found */
|
||||||
|
size_t codepointLen = readUTF8Char(output, input);
|
||||||
|
|
||||||
|
if (codepointLen == 0) {
|
||||||
|
error("Input string is not valid UTF-8!\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
input += codepointLen; /* OK because UTF-8 has no NUL in multi-byte chars */
|
||||||
|
output += codepointLen;
|
||||||
|
outputLen += codepointLen;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*input)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return outputLen;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 1997-2021, Carsten Sorensen and RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Fixed-point math routines
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
#include "asm/fixpoint.h"
|
||||||
|
#include "asm/symbol.h"
|
||||||
|
#include "asm/warning.h"
|
||||||
|
|
||||||
|
#define fix2double(i) ((double)((i) / 65536.0))
|
||||||
|
#define double2fix(d) ((int32_t)round((d) * 65536.0))
|
||||||
|
|
||||||
|
// pi radians == 32768 fixed-point "degrees"
|
||||||
|
#define fdeg2rad(f) ((f) * (M_PI / 32768.0))
|
||||||
|
#define rad2fdeg(r) ((r) * (32768.0 / M_PI))
|
||||||
|
|
||||||
|
#ifndef M_PI
|
||||||
|
#define M_PI 3.14159265358979323846
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the _PI symbol value
|
||||||
|
*/
|
||||||
|
int32_t fix_Callback_PI(void)
|
||||||
|
{
|
||||||
|
warning(WARNING_OBSOLETE, "`_PI` is deprecated; use 3.14159\n");
|
||||||
|
|
||||||
|
return double2fix(M_PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Print a fixed point value
|
||||||
|
*/
|
||||||
|
void fix_Print(int32_t i)
|
||||||
|
{
|
||||||
|
uint32_t u = i;
|
||||||
|
const char *sign = "";
|
||||||
|
|
||||||
|
if (i < 0) {
|
||||||
|
u = -u;
|
||||||
|
sign = "-";
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("%s%" PRIu32 ".%05" PRIu32, sign, u >> 16,
|
||||||
|
((uint32_t)(fix2double(u) * 100000 + 0.5)) % 100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate sine
|
||||||
|
*/
|
||||||
|
int32_t fix_Sin(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(sin(fdeg2rad(fix2double(i))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate cosine
|
||||||
|
*/
|
||||||
|
int32_t fix_Cos(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(cos(fdeg2rad(fix2double(i))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate tangent
|
||||||
|
*/
|
||||||
|
int32_t fix_Tan(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(tan(fdeg2rad(fix2double(i))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate arcsine
|
||||||
|
*/
|
||||||
|
int32_t fix_ASin(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(rad2fdeg(asin(fix2double(i))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate arccosine
|
||||||
|
*/
|
||||||
|
int32_t fix_ACos(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(rad2fdeg(acos(fix2double(i))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate arctangent
|
||||||
|
*/
|
||||||
|
int32_t fix_ATan(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(rad2fdeg(atan(fix2double(i))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Calculate atan2
|
||||||
|
*/
|
||||||
|
int32_t fix_ATan2(int32_t i, int32_t j)
|
||||||
|
{
|
||||||
|
return double2fix(rad2fdeg(atan2(fix2double(i), fix2double(j))));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Multiplication
|
||||||
|
*/
|
||||||
|
int32_t fix_Mul(int32_t i, int32_t j)
|
||||||
|
{
|
||||||
|
return double2fix(fix2double(i) * fix2double(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Division
|
||||||
|
*/
|
||||||
|
int32_t fix_Div(int32_t i, int32_t j)
|
||||||
|
{
|
||||||
|
return double2fix(fix2double(i) / fix2double(j));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Power
|
||||||
|
*/
|
||||||
|
int32_t fix_Pow(int32_t i, int32_t j)
|
||||||
|
{
|
||||||
|
return double2fix(pow(fix2double(i), fix2double(j)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Logarithm
|
||||||
|
*/
|
||||||
|
int32_t fix_Log(int32_t i, int32_t j)
|
||||||
|
{
|
||||||
|
return double2fix(log(fix2double(i)) / log(fix2double(j)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Round
|
||||||
|
*/
|
||||||
|
int32_t fix_Round(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(round(fix2double(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ceil
|
||||||
|
*/
|
||||||
|
int32_t fix_Ceil(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(ceil(fix2double(i)));
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Floor
|
||||||
|
*/
|
||||||
|
int32_t fix_Floor(int32_t i)
|
||||||
|
{
|
||||||
|
return double2fix(floor(fix2double(i)));
|
||||||
|
}
|
||||||
@@ -0,0 +1,299 @@
|
|||||||
|
/*
|
||||||
|
* This file is part of RGBDS.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020, RGBDS contributors.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "asm/format.h"
|
||||||
|
#include "asm/warning.h"
|
||||||
|
|
||||||
|
struct FormatSpec fmt_NewSpec(void)
|
||||||
|
{
|
||||||
|
struct FormatSpec fmt = {0};
|
||||||
|
|
||||||
|
return fmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fmt_IsEmpty(struct FormatSpec const *fmt)
|
||||||
|
{
|
||||||
|
return !fmt->state;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fmt_IsValid(struct FormatSpec const *fmt)
|
||||||
|
{
|
||||||
|
return fmt->valid || fmt->state == FORMAT_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fmt_IsFinished(struct FormatSpec const *fmt)
|
||||||
|
{
|
||||||
|
return fmt->state >= FORMAT_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmt_UseCharacter(struct FormatSpec *fmt, int c)
|
||||||
|
{
|
||||||
|
if (fmt->state == FORMAT_INVALID)
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
/* sign */
|
||||||
|
case ' ':
|
||||||
|
case '+':
|
||||||
|
if (fmt->state > FORMAT_SIGN)
|
||||||
|
goto invalid;
|
||||||
|
fmt->state = FORMAT_PREFIX;
|
||||||
|
fmt->sign = c;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* prefix */
|
||||||
|
case '#':
|
||||||
|
if (fmt->state > FORMAT_PREFIX)
|
||||||
|
goto invalid;
|
||||||
|
fmt->state = FORMAT_ALIGN;
|
||||||
|
fmt->prefix = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* align */
|
||||||
|
case '-':
|
||||||
|
if (fmt->state > FORMAT_ALIGN)
|
||||||
|
goto invalid;
|
||||||
|
fmt->state = FORMAT_WIDTH;
|
||||||
|
fmt->alignLeft = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* pad and width */
|
||||||
|
case '0':
|
||||||
|
if (fmt->state < FORMAT_WIDTH)
|
||||||
|
fmt->padZero = true;
|
||||||
|
/* fallthrough */
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
case '7':
|
||||||
|
case '8':
|
||||||
|
case '9':
|
||||||
|
if (fmt->state < FORMAT_WIDTH) {
|
||||||
|
fmt->state = FORMAT_WIDTH;
|
||||||
|
fmt->width = c - '0';
|
||||||
|
} else if (fmt->state == FORMAT_WIDTH) {
|
||||||
|
fmt->width = fmt->width * 10 + (c - '0');
|
||||||
|
} else if (fmt->state == FORMAT_FRAC) {
|
||||||
|
fmt->fracWidth = fmt->fracWidth * 10 + (c - '0');
|
||||||
|
} else {
|
||||||
|
goto invalid;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '.':
|
||||||
|
if (fmt->state > FORMAT_WIDTH)
|
||||||
|
goto invalid;
|
||||||
|
fmt->state = FORMAT_FRAC;
|
||||||
|
fmt->hasFrac = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* type */
|
||||||
|
case 'd':
|
||||||
|
case 'u':
|
||||||
|
case 'X':
|
||||||
|
case 'x':
|
||||||
|
case 'b':
|
||||||
|
case 'o':
|
||||||
|
case 'f':
|
||||||
|
case 's':
|
||||||
|
if (fmt->state >= FORMAT_DONE)
|
||||||
|
goto invalid;
|
||||||
|
fmt->state = FORMAT_DONE;
|
||||||
|
fmt->valid = true;
|
||||||
|
fmt->type = c;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
invalid:
|
||||||
|
fmt->state = FORMAT_INVALID;
|
||||||
|
fmt->valid = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmt_FinishCharacters(struct FormatSpec *fmt)
|
||||||
|
{
|
||||||
|
if (!fmt_IsValid(fmt))
|
||||||
|
fmt->state = FORMAT_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmt_PrintString(char *buf, size_t bufLen, struct FormatSpec const *fmt, char const *value)
|
||||||
|
{
|
||||||
|
if (fmt->sign)
|
||||||
|
error("Formatting string with sign flag '%c'\n", fmt->sign);
|
||||||
|
if (fmt->prefix)
|
||||||
|
error("Formatting string with prefix flag '#'\n");
|
||||||
|
if (fmt->padZero)
|
||||||
|
error("Formatting string with padding flag '0'\n");
|
||||||
|
if (fmt->hasFrac)
|
||||||
|
error("Formatting string with fractional width\n");
|
||||||
|
if (fmt->type != 's')
|
||||||
|
error("Formatting string as type '%c'\n", fmt->type);
|
||||||
|
|
||||||
|
size_t len = strlen(value);
|
||||||
|
size_t totalLen = fmt->width > len ? fmt->width : len;
|
||||||
|
|
||||||
|
if (totalLen + 1 > bufLen) /* bufLen includes terminator */
|
||||||
|
error("Formatted string value too long\n");
|
||||||
|
|
||||||
|
size_t padLen = fmt->width > len ? fmt->width - len : 0;
|
||||||
|
|
||||||
|
if (fmt->alignLeft) {
|
||||||
|
strncpy(buf, value, len < bufLen ? len : bufLen);
|
||||||
|
for (size_t i = 0; i < totalLen && len + i < bufLen; i++)
|
||||||
|
buf[len + i] = ' ';
|
||||||
|
} else {
|
||||||
|
for (size_t i = 0; i < padLen && i < bufLen; i++)
|
||||||
|
buf[i] = ' ';
|
||||||
|
if (bufLen > padLen)
|
||||||
|
strncpy(buf + padLen, value, bufLen - padLen - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[totalLen] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void fmt_PrintNumber(char *buf, size_t bufLen, struct FormatSpec const *fmt, uint32_t value)
|
||||||
|
{
|
||||||
|
if (fmt->type != 'X' && fmt->type != 'x' && fmt->type != 'b' && fmt->type != 'o'
|
||||||
|
&& fmt->prefix)
|
||||||
|
error("Formatting type '%c' with prefix flag '#'\n", fmt->type);
|
||||||
|
if (fmt->type != 'f' && fmt->hasFrac)
|
||||||
|
error("Formatting type '%c' with fractional width\n", fmt->type);
|
||||||
|
if (fmt->type == 's')
|
||||||
|
error("Formatting number as type 's'\n");
|
||||||
|
|
||||||
|
char sign = fmt->sign; /* 0 or ' ' or '+' */
|
||||||
|
|
||||||
|
if (fmt->type == 'd' || fmt->type == 'f') {
|
||||||
|
int32_t v = value;
|
||||||
|
|
||||||
|
if (v < 0 && v != INT32_MIN) {
|
||||||
|
sign = '-';
|
||||||
|
value = -v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char prefix = !fmt->prefix ? 0
|
||||||
|
: fmt->type == 'X' ? '$'
|
||||||
|
: fmt->type == 'x' ? '$'
|
||||||
|
: fmt->type == 'b' ? '%'
|
||||||
|
: fmt->type == 'o' ? '&'
|
||||||
|
: 0;
|
||||||
|
|
||||||
|
char valueBuf[262]; /* Max 5 digits + decimal + 255 fraction digits + terminator */
|
||||||
|
|
||||||
|
if (fmt->type == 'b') {
|
||||||
|
/* Special case for binary */
|
||||||
|
char *ptr = valueBuf;
|
||||||
|
|
||||||
|
do {
|
||||||
|
*ptr++ = (value & 1) + '0';
|
||||||
|
value >>= 1;
|
||||||
|
} while (value);
|
||||||
|
|
||||||
|
*ptr = '\0';
|
||||||
|
|
||||||
|
/* Reverse the digits */
|
||||||
|
size_t valueLen = ptr - valueBuf;
|
||||||
|
|
||||||
|
for (size_t i = 0, j = valueLen - 1; i < j; i++, j--) {
|
||||||
|
char c = valueBuf[i];
|
||||||
|
|
||||||
|
valueBuf[i] = valueBuf[j];
|
||||||
|
valueBuf[j] = c;
|
||||||
|
}
|
||||||
|
} else if (fmt->type == 'f') {
|
||||||
|
/* Special case for fixed-point */
|
||||||
|
|
||||||
|
/* Default fractional width (C's is 6 for "%f"; here 5 is enough) */
|
||||||
|
uint8_t fracWidth = fmt->hasFrac ? fmt->fracWidth : 5;
|
||||||
|
|
||||||
|
if (fracWidth) {
|
||||||
|
char spec[16]; /* Max "%" + 5-char PRIu32 + ".%0255.f" + terminator */
|
||||||
|
|
||||||
|
snprintf(spec, sizeof(spec), "%%" PRIu32 ".%%0%d.f", fracWidth);
|
||||||
|
snprintf(valueBuf, sizeof(valueBuf), spec, value >> 16,
|
||||||
|
(value % 65536) / 65536.0 * pow(10, fracWidth) + 0.5);
|
||||||
|
} else {
|
||||||
|
snprintf(valueBuf, sizeof(valueBuf), "%" PRIu32, value >> 16);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
char const *spec = fmt->type == 'd' ? "%" PRId32
|
||||||
|
: fmt->type == 'u' ? "%" PRIu32
|
||||||
|
: fmt->type == 'X' ? "%" PRIX32
|
||||||
|
: fmt->type == 'x' ? "%" PRIx32
|
||||||
|
: fmt->type == 'o' ? "%" PRIo32
|
||||||
|
: "%" PRId32;
|
||||||
|
|
||||||
|
snprintf(valueBuf, sizeof(valueBuf), spec, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t len = strlen(valueBuf);
|
||||||
|
size_t numLen = len;
|
||||||
|
|
||||||
|
if (sign)
|
||||||
|
numLen++;
|
||||||
|
if (prefix)
|
||||||
|
numLen++;
|
||||||
|
|
||||||
|
size_t totalLen = fmt->width > numLen ? fmt->width : numLen;
|
||||||
|
|
||||||
|
if (totalLen + 1 > bufLen) /* bufLen includes terminator */
|
||||||
|
error("Formatted numeric value too long\n");
|
||||||
|
|
||||||
|
size_t padLen = fmt->width > numLen ? fmt->width - numLen : 0;
|
||||||
|
|
||||||
|
if (fmt->alignLeft) {
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
if (sign && pos < bufLen)
|
||||||
|
buf[pos++] = sign;
|
||||||
|
if (prefix && pos < bufLen)
|
||||||
|
buf[pos++] = prefix;
|
||||||
|
|
||||||
|
strcpy(buf + pos, valueBuf);
|
||||||
|
pos += len;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < totalLen && pos + i < bufLen; i++)
|
||||||
|
buf[pos + i] = ' ';
|
||||||
|
} else {
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
|
if (fmt->padZero) {
|
||||||
|
/* sign, then prefix, then zero padding */
|
||||||
|
if (sign && pos < bufLen)
|
||||||
|
buf[pos++] = sign;
|
||||||
|
if (prefix && pos < bufLen)
|
||||||
|
buf[pos++] = prefix;
|
||||||
|
for (size_t i = 0; i < padLen && pos < bufLen; i++)
|
||||||
|
buf[pos++] = '0';
|
||||||
|
} else {
|
||||||
|
/* space padding, then sign, then prefix */
|
||||||
|
for (size_t i = 0; i < padLen && pos < bufLen; i++)
|
||||||
|
buf[pos++] = ' ';
|
||||||
|
if (sign && pos < bufLen)
|
||||||
|
buf[pos++] = sign;
|
||||||
|
if (prefix && pos < bufLen)
|
||||||
|
buf[pos++] = prefix;
|
||||||
|
}
|
||||||
|
if (bufLen > pos)
|
||||||
|
strcpy(buf + pos, valueBuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
buf[totalLen] = '\0';
|
||||||
|
}
|
||||||
+499
-350
@@ -6,420 +6,569 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
#include <sys/stat.h>
|
||||||
* FileStack routines
|
#include <assert.h>
|
||||||
*/
|
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
#include <inttypes.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "asm/fstack.h"
|
#include "asm/fstack.h"
|
||||||
#include "asm/lexer.h"
|
#include "asm/macro.h"
|
||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
#include "asm/output.h"
|
|
||||||
#include "asm/symbol.h"
|
#include "asm/symbol.h"
|
||||||
|
#include "asm/warning.h"
|
||||||
|
#include "platform.h" /* S_ISDIR (stat macro) */
|
||||||
|
|
||||||
#include "extern/err.h"
|
#define MAXINCPATHS 128
|
||||||
|
|
||||||
#include "types.h"
|
#ifdef LEXER_DEBUG
|
||||||
|
#define dbgPrint(...) fprintf(stderr, "[fstack] " __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define dbgPrint(...)
|
||||||
|
#endif
|
||||||
|
|
||||||
static struct sContext *pFileStack;
|
struct Context {
|
||||||
static struct sSymbol *pCurrentMacro;
|
struct Context *parent;
|
||||||
static YY_BUFFER_STATE CurrentFlexHandle;
|
struct FileStackNode *fileInfo;
|
||||||
static FILE *pCurrentFile;
|
struct LexerState *lexerState;
|
||||||
static uint32_t nCurrentStatus;
|
uint32_t uniqueID;
|
||||||
char tzCurrentFileName[_MAX_PATH + 1];
|
struct MacroArgs *macroArgs; /* Macro args are *saved* here */
|
||||||
static char IncludePaths[MAXINCPATHS][_MAX_PATH + 1];
|
uint32_t nbReptIters;
|
||||||
static int32_t NextIncPath;
|
int32_t forValue;
|
||||||
static uint32_t nMacroCount;
|
int32_t forStep;
|
||||||
|
char *forName;
|
||||||
|
};
|
||||||
|
|
||||||
static char *pCurrentREPTBlock;
|
static struct Context *contextStack;
|
||||||
static uint32_t nCurrentREPTBlockSize;
|
static size_t contextDepth = 0;
|
||||||
static uint32_t nCurrentREPTBlockCount;
|
#define DEFAULT_MAX_DEPTH 64
|
||||||
|
size_t nMaxRecursionDepth;
|
||||||
|
|
||||||
uint32_t ulMacroReturnValue;
|
static unsigned int nbIncPaths = 0;
|
||||||
|
static char const *includePaths[MAXINCPATHS];
|
||||||
|
|
||||||
/*
|
static const char *dumpNodeAndParents(struct FileStackNode const *node)
|
||||||
* defines for nCurrentStatus
|
|
||||||
*/
|
|
||||||
#define STAT_isInclude 0 /* 'Normal' state as well */
|
|
||||||
#define STAT_isMacro 1
|
|
||||||
#define STAT_isMacroArg 2
|
|
||||||
#define STAT_isREPTBlock 3
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Context push and pop
|
|
||||||
*/
|
|
||||||
static void pushcontext(void)
|
|
||||||
{
|
{
|
||||||
struct sContext **ppFileStack;
|
char const *name;
|
||||||
|
|
||||||
ppFileStack = &pFileStack;
|
if (node->type == NODE_REPT) {
|
||||||
while (*ppFileStack)
|
assert(node->parent); /* REPT nodes should always have a parent */
|
||||||
ppFileStack = &((*ppFileStack)->pNext);
|
struct FileStackReptNode const *reptInfo = (struct FileStackReptNode const *)node;
|
||||||
|
|
||||||
*ppFileStack = malloc(sizeof(struct sContext));
|
name = dumpNodeAndParents(node->parent);
|
||||||
|
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, name);
|
||||||
if (*ppFileStack == NULL)
|
for (uint32_t i = reptInfo->reptDepth; i--; )
|
||||||
fatalerror("No memory for context");
|
fprintf(stderr, "::REPT~%" PRIu32, reptInfo->iters[i]);
|
||||||
|
} else {
|
||||||
(*ppFileStack)->FlexHandle = CurrentFlexHandle;
|
name = ((struct FileStackNamedNode const *)node)->name;
|
||||||
(*ppFileStack)->pNext = NULL;
|
if (node->parent) {
|
||||||
strcpy((char *)(*ppFileStack)->tzFileName, (char *)tzCurrentFileName);
|
dumpNodeAndParents(node->parent);
|
||||||
(*ppFileStack)->nLine = nLineNo;
|
fprintf(stderr, "(%" PRIu32 ") -> %s", node->lineNo, name);
|
||||||
|
} else {
|
||||||
switch ((*ppFileStack)->nStatus = nCurrentStatus) {
|
fputs(name, stderr);
|
||||||
case STAT_isMacroArg:
|
|
||||||
case STAT_isMacro:
|
|
||||||
sym_SaveCurrentMacroArgs((*ppFileStack)->tzMacroArgs);
|
|
||||||
(*ppFileStack)->pMacro = pCurrentMacro;
|
|
||||||
break;
|
|
||||||
case STAT_isInclude:
|
|
||||||
(*ppFileStack)->pFile = pCurrentFile;
|
|
||||||
break;
|
|
||||||
case STAT_isREPTBlock:
|
|
||||||
sym_SaveCurrentMacroArgs((*ppFileStack)->tzMacroArgs);
|
|
||||||
(*ppFileStack)->pREPTBlock = pCurrentREPTBlock;
|
|
||||||
(*ppFileStack)->nREPTBlockSize = nCurrentREPTBlockSize;
|
|
||||||
(*ppFileStack)->nREPTBlockCount = nCurrentREPTBlockCount;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fatalerror("%s: Internal error.", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
nLineNo = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t popcontext(void)
|
|
||||||
{
|
|
||||||
struct sContext *pLastFile, **ppLastFile;
|
|
||||||
|
|
||||||
if (nCurrentStatus == STAT_isREPTBlock) {
|
|
||||||
if (--nCurrentREPTBlockCount) {
|
|
||||||
yy_delete_buffer(CurrentFlexHandle);
|
|
||||||
CurrentFlexHandle =
|
|
||||||
yy_scan_bytes(pCurrentREPTBlock,
|
|
||||||
nCurrentREPTBlockSize);
|
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
|
||||||
sym_UseCurrentMacroArgs();
|
|
||||||
sym_SetMacroArgID(nMacroCount++);
|
|
||||||
sym_UseNewMacroArgs();
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return name;
|
||||||
pLastFile = pFileStack;
|
|
||||||
if (pLastFile == NULL)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
ppLastFile = &pFileStack;
|
|
||||||
while (pLastFile->pNext) {
|
|
||||||
ppLastFile = &(pLastFile->pNext);
|
|
||||||
pLastFile = *ppLastFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
yy_delete_buffer(CurrentFlexHandle);
|
|
||||||
nLineNo = pLastFile->nLine;
|
|
||||||
|
|
||||||
if (nCurrentStatus == STAT_isInclude)
|
|
||||||
fclose(pCurrentFile);
|
|
||||||
|
|
||||||
if (nCurrentStatus == STAT_isMacro) {
|
|
||||||
sym_FreeCurrentMacroArgs();
|
|
||||||
nLineNo += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nCurrentStatus == STAT_isREPTBlock)
|
|
||||||
nLineNo += 1;
|
|
||||||
|
|
||||||
CurrentFlexHandle = pLastFile->FlexHandle;
|
|
||||||
strcpy((char *)tzCurrentFileName, (char *)pLastFile->tzFileName);
|
|
||||||
|
|
||||||
switch (nCurrentStatus = pLastFile->nStatus) {
|
|
||||||
case STAT_isMacroArg:
|
|
||||||
case STAT_isMacro:
|
|
||||||
sym_RestoreCurrentMacroArgs(pLastFile->tzMacroArgs);
|
|
||||||
pCurrentMacro = pLastFile->pMacro;
|
|
||||||
break;
|
|
||||||
case STAT_isInclude:
|
|
||||||
pCurrentFile = pLastFile->pFile;
|
|
||||||
break;
|
|
||||||
case STAT_isREPTBlock:
|
|
||||||
sym_RestoreCurrentMacroArgs(pLastFile->tzMacroArgs);
|
|
||||||
pCurrentREPTBlock = pLastFile->pREPTBlock;
|
|
||||||
nCurrentREPTBlockSize = pLastFile->nREPTBlockSize;
|
|
||||||
nCurrentREPTBlockCount = pLastFile->nREPTBlockCount;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fatalerror("%s: Internal error.", __func__);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(*ppLastFile);
|
|
||||||
*ppLastFile = NULL;
|
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int32_t fstk_GetLine(void)
|
void fstk_Dump(struct FileStackNode const *node, uint32_t lineNo)
|
||||||
{
|
{
|
||||||
struct sContext *pLastFile, **ppLastFile;
|
dumpNodeAndParents(node);
|
||||||
|
fprintf(stderr, "(%" PRIu32 ")", lineNo);
|
||||||
|
}
|
||||||
|
|
||||||
switch (nCurrentStatus) {
|
void fstk_DumpCurrent(void)
|
||||||
case STAT_isInclude:
|
{
|
||||||
/* This is the normal mode, also used when including a file. */
|
if (!contextStack) {
|
||||||
return nLineNo;
|
fputs("at top level", stderr);
|
||||||
case STAT_isMacro:
|
return;
|
||||||
break; /* Peek top file of the stack */
|
|
||||||
case STAT_isMacroArg:
|
|
||||||
return nLineNo; /* ??? */
|
|
||||||
case STAT_isREPTBlock:
|
|
||||||
break; /* Peek top file of the stack */
|
|
||||||
default:
|
|
||||||
fatalerror("%s: Internal error.", __func__);
|
|
||||||
}
|
}
|
||||||
|
fstk_Dump(contextStack->fileInfo, lexer_GetLineNo());
|
||||||
pLastFile = pFileStack;
|
|
||||||
|
|
||||||
if (pLastFile != NULL) {
|
|
||||||
ppLastFile = &pFileStack;
|
|
||||||
while (pLastFile->pNext) {
|
|
||||||
ppLastFile = &(pLastFile->pNext);
|
|
||||||
pLastFile = *ppLastFile;
|
|
||||||
}
|
|
||||||
return pLastFile->nLine;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is only reached if the lexer is in REPT or MACRO mode but there
|
|
||||||
* are no saved contexts with the origin of said REPT or MACRO.
|
|
||||||
*/
|
|
||||||
fatalerror("%s: Internal error.", __func__);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int yywrap(void)
|
struct FileStackNode *fstk_GetFileStack(void)
|
||||||
{
|
{
|
||||||
return popcontext();
|
if (!contextStack)
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dump the context stack to stderr
|
|
||||||
*/
|
|
||||||
void fstk_Dump(void)
|
|
||||||
{
|
|
||||||
const struct sContext *pLastFile;
|
|
||||||
|
|
||||||
pLastFile = pFileStack;
|
|
||||||
|
|
||||||
while (pLastFile) {
|
|
||||||
fprintf(stderr, "%s(%d) -> ", pLastFile->tzFileName,
|
|
||||||
pLastFile->nLine);
|
|
||||||
pLastFile = pLastFile->pNext;
|
|
||||||
}
|
|
||||||
|
|
||||||
fprintf(stderr, "%s(%d)", tzCurrentFileName, nLineNo);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Extra includepath stuff
|
|
||||||
*/
|
|
||||||
void fstk_AddIncludePath(char *s)
|
|
||||||
{
|
|
||||||
if (NextIncPath == MAXINCPATHS)
|
|
||||||
fatalerror("Too many include directories passed from command line");
|
|
||||||
|
|
||||||
if (snprintf(IncludePaths[NextIncPath++], _MAX_PATH, "%s", s) >= _MAX_PATH)
|
|
||||||
fatalerror("Include path too long '%s'", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
FILE *fstk_FindFile(char *fname)
|
|
||||||
{
|
|
||||||
char path[_MAX_PATH];
|
|
||||||
int32_t i;
|
|
||||||
FILE *f;
|
|
||||||
|
|
||||||
if (fname == NULL)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
f = fopen(fname, "rb");
|
struct FileStackNode *node = contextStack->fileInfo;
|
||||||
|
|
||||||
if (f != NULL || errno != ENOENT) {
|
/* Mark node and all of its parents as referenced if not already so they don't get freed */
|
||||||
if (dependfile)
|
while (node && !node->referenced) {
|
||||||
fprintf(dependfile, "%s: %s\n", tzObjectname, fname);
|
node->ID = -1;
|
||||||
|
node->referenced = true;
|
||||||
|
node = node->parent;
|
||||||
|
}
|
||||||
|
return contextStack->fileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
return f;
|
char const *fstk_GetFileName(void)
|
||||||
|
{
|
||||||
|
/* Iterating via the nodes themselves skips nested REPTs */
|
||||||
|
struct FileStackNode const *node = contextStack->fileInfo;
|
||||||
|
|
||||||
|
while (node->type != NODE_FILE)
|
||||||
|
node = node->parent;
|
||||||
|
return ((struct FileStackNamedNode const *)node)->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fstk_AddIncludePath(char const *path)
|
||||||
|
{
|
||||||
|
if (path[0] == '\0')
|
||||||
|
return;
|
||||||
|
if (nbIncPaths >= MAXINCPATHS) {
|
||||||
|
error("Too many include directories passed from command line\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t len = strlen(path);
|
||||||
|
size_t allocSize = len + (path[len - 1] != '/') + 1;
|
||||||
|
char *str = malloc(allocSize);
|
||||||
|
|
||||||
|
if (!str) {
|
||||||
|
/* Attempt to continue without that path */
|
||||||
|
error("Failed to allocate new include path: %s\n", strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memcpy(str, path, len);
|
||||||
|
char *end = str + len - 1;
|
||||||
|
|
||||||
|
if (*end++ != '/')
|
||||||
|
*end++ = '/';
|
||||||
|
*end = '\0';
|
||||||
|
includePaths[nbIncPaths++] = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printDep(char const *path)
|
||||||
|
{
|
||||||
|
if (dependfile) {
|
||||||
|
fprintf(dependfile, "%s: %s\n", tzTargetFileName, path);
|
||||||
|
if (oGeneratePhonyDeps)
|
||||||
|
fprintf(dependfile, "%s:\n", path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isPathValid(char const *path)
|
||||||
|
{
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
if (stat(path, &statbuf) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
/* Reject directories */
|
||||||
|
return !S_ISDIR(statbuf.st_mode);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fstk_FindFile(char const *path, char **fullPath, size_t *size)
|
||||||
|
{
|
||||||
|
if (!*size) {
|
||||||
|
*size = 64; /* This is arbitrary, really */
|
||||||
|
*fullPath = realloc(*fullPath, *size);
|
||||||
|
if (!*fullPath)
|
||||||
|
error("realloc error during include path search: %s\n",
|
||||||
|
strerror(errno));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < NextIncPath; ++i) {
|
if (*fullPath) {
|
||||||
/*
|
for (size_t i = 0; i <= nbIncPaths; ++i) {
|
||||||
* The function snprintf() does not write more than `size` bytes
|
char const *incPath = i ? includePaths[i - 1] : "";
|
||||||
* (including the terminating null byte ('\0')). If the output
|
int len = snprintf(*fullPath, *size, "%s%s", incPath, path);
|
||||||
* was truncated due to this limit, the return value is the
|
|
||||||
* number of characters (excluding the terminating null byte)
|
|
||||||
* which would have been written to the final string if enough
|
|
||||||
* space had been available. Thus, a return value of `size` or
|
|
||||||
* more means that the output was truncated.
|
|
||||||
*/
|
|
||||||
int fullpathlen = snprintf(path, sizeof(path), "%s%s",
|
|
||||||
IncludePaths[i], fname);
|
|
||||||
|
|
||||||
if (fullpathlen >= (int)sizeof(path))
|
if (len < 0) {
|
||||||
continue;
|
error("snprintf error during include path search: %s\n",
|
||||||
|
strerror(errno));
|
||||||
f = fopen(path, "rb");
|
break;
|
||||||
|
}
|
||||||
if (f != NULL || errno != ENOENT) {
|
|
||||||
if (dependfile) {
|
/* Oh how I wish `asnprintf` was standard... */
|
||||||
fprintf(dependfile, "%s: %s\n", tzObjectname,
|
if ((size_t)len >= *size) { /* `len` doesn't include the terminator, `size` does */
|
||||||
path);
|
*size = len + 1;
|
||||||
|
*fullPath = realloc(*fullPath, *size);
|
||||||
|
if (!*fullPath) {
|
||||||
|
error("realloc error during include path search: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
len = sprintf(*fullPath, "%s%s", incPath, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPathValid(*fullPath)) {
|
||||||
|
printDep(*fullPath);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
errno = ENOENT;
|
errno = ENOENT;
|
||||||
return NULL;
|
if (oGeneratedMissingIncludes)
|
||||||
|
printDep(path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool yywrap(void)
|
||||||
|
{
|
||||||
|
uint32_t nIFDepth = lexer_GetIFDepth();
|
||||||
|
|
||||||
|
if (nIFDepth != 0)
|
||||||
|
fatalerror("Ended block with %" PRIu32 " unterminated IF construct%s\n",
|
||||||
|
nIFDepth, nIFDepth == 1 ? "" : "s");
|
||||||
|
|
||||||
|
if (contextStack->fileInfo->type == NODE_REPT) { /* The context is a REPT block, which may loop */
|
||||||
|
struct FileStackReptNode *fileInfo = (struct FileStackReptNode *)contextStack->fileInfo;
|
||||||
|
|
||||||
|
/* If the node is referenced, we can't edit it; duplicate it */
|
||||||
|
if (contextStack->fileInfo->referenced) {
|
||||||
|
size_t size = sizeof(*fileInfo) + sizeof(fileInfo->iters[0]) * fileInfo->reptDepth;
|
||||||
|
struct FileStackReptNode *copy = malloc(size);
|
||||||
|
|
||||||
|
if (!copy)
|
||||||
|
fatalerror("Failed to duplicate REPT file node: %s\n", strerror(errno));
|
||||||
|
/* Copy all info but the referencing */
|
||||||
|
memcpy(copy, fileInfo, size);
|
||||||
|
copy->node.next = NULL;
|
||||||
|
copy->node.referenced = false;
|
||||||
|
|
||||||
|
fileInfo = copy;
|
||||||
|
contextStack->fileInfo = (struct FileStackNode *)fileInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If this is a FOR, update the symbol value */
|
||||||
|
if (contextStack->forName && fileInfo->iters[0] <= contextStack->nbReptIters) {
|
||||||
|
contextStack->forValue += contextStack->forStep;
|
||||||
|
struct Symbol *sym = sym_AddSet(contextStack->forName,
|
||||||
|
contextStack->forValue);
|
||||||
|
|
||||||
|
/* This error message will refer to the current iteration */
|
||||||
|
if (sym->type != SYM_SET)
|
||||||
|
fatalerror("Failed to update FOR symbol value\n");
|
||||||
|
}
|
||||||
|
/* Advance to the next iteration */
|
||||||
|
fileInfo->iters[0]++;
|
||||||
|
/* If this wasn't the last iteration, wrap instead of popping */
|
||||||
|
if (fileInfo->iters[0] <= contextStack->nbReptIters) {
|
||||||
|
lexer_RestartRept(contextStack->fileInfo->lineNo);
|
||||||
|
contextStack->uniqueID = macro_UseNewUniqueID();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (!contextStack->parent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
dbgPrint("Popping context\n");
|
||||||
|
|
||||||
|
struct Context *context = contextStack;
|
||||||
|
|
||||||
|
contextStack = contextStack->parent;
|
||||||
|
assert(contextDepth != 0); // This is never supposed to underflow
|
||||||
|
contextDepth--;
|
||||||
|
|
||||||
|
lexer_DeleteState(context->lexerState);
|
||||||
|
/* Restore args if a macro (not REPT) saved them */
|
||||||
|
if (context->fileInfo->type == NODE_MACRO) {
|
||||||
|
dbgPrint("Restoring macro args %p\n", (void *)contextStack->macroArgs);
|
||||||
|
macro_UseNewArgs(contextStack->macroArgs);
|
||||||
|
}
|
||||||
|
/* Free the file stack node */
|
||||||
|
if (!context->fileInfo->referenced)
|
||||||
|
free(context->fileInfo);
|
||||||
|
/* Free the FOR symbol name */
|
||||||
|
free(context->forName);
|
||||||
|
/* Free the entry and make its parent the current entry */
|
||||||
|
free(context);
|
||||||
|
|
||||||
|
lexer_SetState(contextStack->lexerState);
|
||||||
|
macro_SetUniqueID(contextStack->uniqueID);
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up an include file for parsing
|
* Make sure not to switch the lexer state before calling this, so the saved line no is correct
|
||||||
|
* BE CAREFUL!! This modifies the file stack directly, you should have set up the file info first
|
||||||
|
* Callers should set contextStack->lexerState after this so it is not NULL
|
||||||
*/
|
*/
|
||||||
void fstk_RunInclude(char *tzFileName)
|
static void newContext(struct FileStackNode *fileInfo)
|
||||||
{
|
{
|
||||||
FILE *f = fstk_FindFile(tzFileName);
|
if (++contextDepth >= nMaxRecursionDepth)
|
||||||
|
fatalerror("Recursion limit (%zu) exceeded\n", nMaxRecursionDepth);
|
||||||
|
struct Context *context = malloc(sizeof(*context));
|
||||||
|
|
||||||
if (f == NULL)
|
if (!context)
|
||||||
err(1, "Unable to open included file '%s'", tzFileName);
|
fatalerror("Failed to allocate memory for new context: %s\n", strerror(errno));
|
||||||
|
fileInfo->parent = contextStack->fileInfo;
|
||||||
pushcontext();
|
fileInfo->lineNo = 0; /* Init to a default value, see struct definition for info */
|
||||||
nLineNo = 1;
|
fileInfo->referenced = false;
|
||||||
nCurrentStatus = STAT_isInclude;
|
fileInfo->lineNo = lexer_GetLineNo();
|
||||||
strcpy(tzCurrentFileName, tzFileName);
|
context->fileInfo = fileInfo;
|
||||||
pCurrentFile = f;
|
context->forName = NULL;
|
||||||
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
|
/*
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
* Link new entry to its parent so it's reachable later
|
||||||
|
* ERRORS SHOULD NOT OCCUR AFTER THIS!!
|
||||||
/* Dirty hack to give the INCLUDE directive a linefeed */
|
*/
|
||||||
|
context->parent = contextStack;
|
||||||
yyunput('\n');
|
contextStack = context;
|
||||||
nLineNo -= 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void fstk_RunInclude(char const *path)
|
||||||
* Set up a macro for parsing
|
|
||||||
*/
|
|
||||||
uint32_t fstk_RunMacro(char *s)
|
|
||||||
{
|
{
|
||||||
struct sSymbol *sym = sym_FindMacro(s);
|
dbgPrint("Including path \"%s\"\n", path);
|
||||||
|
|
||||||
if (sym == NULL)
|
char *fullPath = NULL;
|
||||||
return 0;
|
size_t size = 0;
|
||||||
|
|
||||||
pushcontext();
|
if (!fstk_FindFile(path, &fullPath, &size)) {
|
||||||
sym_SetMacroArgID(nMacroCount++);
|
free(fullPath);
|
||||||
nLineNo = -1;
|
if (oGeneratedMissingIncludes) {
|
||||||
sym_UseNewMacroArgs();
|
if (verbose)
|
||||||
nCurrentStatus = STAT_isMacro;
|
printf("Aborting (-MG) on INCLUDE file '%s' (%s)\n",
|
||||||
strcpy(tzCurrentFileName, s);
|
path, strerror(errno));
|
||||||
|
oFailedOnMissingInclude = true;
|
||||||
|
} else {
|
||||||
|
error("Unable to open included file '%s': %s\n", path, strerror(errno));
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
dbgPrint("Full path: \"%s\"\n", fullPath);
|
||||||
|
|
||||||
if (sym->pMacro == NULL)
|
struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + size);
|
||||||
return 0;
|
|
||||||
|
|
||||||
pCurrentMacro = sym;
|
if (!fileInfo) {
|
||||||
CurrentFlexHandle = yy_scan_bytes(pCurrentMacro->pMacro,
|
error("Failed to alloc file info for INCLUDE: %s\n", strerror(errno));
|
||||||
strlen(pCurrentMacro->pMacro));
|
return;
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
}
|
||||||
|
fileInfo->node.type = NODE_FILE;
|
||||||
|
strcpy(fileInfo->name, fullPath);
|
||||||
|
free(fullPath);
|
||||||
|
|
||||||
return 1;
|
newContext((struct FileStackNode *)fileInfo);
|
||||||
|
contextStack->lexerState = lexer_OpenFile(fileInfo->name);
|
||||||
|
if (!contextStack->lexerState)
|
||||||
|
fatalerror("Failed to set up lexer for file include\n");
|
||||||
|
lexer_SetStateAtEOL(contextStack->lexerState);
|
||||||
|
/* We're back at top-level, so most things are reset */
|
||||||
|
contextStack->uniqueID = 0;
|
||||||
|
macro_SetUniqueID(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
void fstk_RunMacro(char const *macroName, struct MacroArgs *args)
|
||||||
* Set up a macroargument for parsing
|
|
||||||
*/
|
|
||||||
void fstk_RunMacroArg(int32_t s)
|
|
||||||
{
|
{
|
||||||
char *sym;
|
dbgPrint("Running macro \"%s\"\n", macroName);
|
||||||
|
|
||||||
if (s == '@')
|
struct Symbol *macro = sym_FindExactSymbol(macroName);
|
||||||
s = -1;
|
|
||||||
else
|
|
||||||
s -= '0';
|
|
||||||
|
|
||||||
sym = sym_FindMacroArg(s);
|
if (!macro) {
|
||||||
|
error("Macro \"%s\" not defined\n", macroName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (macro->type != SYM_MACRO) {
|
||||||
|
error("\"%s\" is not a macro\n", macroName);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
contextStack->macroArgs = macro_GetCurrentArgs();
|
||||||
|
|
||||||
if (sym == NULL)
|
/* Compute total length of this node's name: <base name>::<macro> */
|
||||||
fatalerror("No such macroargument");
|
size_t reptNameLen = 0;
|
||||||
|
struct FileStackNode const *node = macro->src;
|
||||||
|
|
||||||
pushcontext();
|
if (node->type == NODE_REPT) {
|
||||||
nCurrentStatus = STAT_isMacroArg;
|
struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node;
|
||||||
snprintf(tzCurrentFileName, _MAX_PATH + 1, "%c", (uint8_t)s);
|
|
||||||
CurrentFlexHandle = yy_scan_bytes(sym, strlen(sym));
|
/* 4294967295 = 2^32 - 1, aka UINT32_MAX */
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
reptNameLen += reptNode->reptDepth * strlen("::REPT~4294967295");
|
||||||
|
/* Look for next named node */
|
||||||
|
do {
|
||||||
|
node = node->parent;
|
||||||
|
} while (node->type == NODE_REPT);
|
||||||
|
}
|
||||||
|
struct FileStackNamedNode const *baseNode = (struct FileStackNamedNode const *)node;
|
||||||
|
size_t baseLen = strlen(baseNode->name);
|
||||||
|
size_t macroNameLen = strlen(macro->name);
|
||||||
|
struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + baseLen
|
||||||
|
+ reptNameLen + 2 + macroNameLen + 1);
|
||||||
|
|
||||||
|
if (!fileInfo) {
|
||||||
|
error("Failed to alloc file info for \"%s\": %s\n", macro->name, strerror(errno));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fileInfo->node.type = NODE_MACRO;
|
||||||
|
/* Print the name... */
|
||||||
|
char *dest = fileInfo->name;
|
||||||
|
|
||||||
|
memcpy(dest, baseNode->name, baseLen);
|
||||||
|
dest += baseLen;
|
||||||
|
if (node->type == NODE_REPT) {
|
||||||
|
struct FileStackReptNode const *reptNode = (struct FileStackReptNode const *)node;
|
||||||
|
|
||||||
|
for (uint32_t i = reptNode->reptDepth; i--; ) {
|
||||||
|
int nbChars = sprintf(dest, "::REPT~%" PRIu32, reptNode->iters[i]);
|
||||||
|
|
||||||
|
if (nbChars < 0)
|
||||||
|
fatalerror("Failed to write macro invocation info: %s\n",
|
||||||
|
strerror(errno));
|
||||||
|
dest += nbChars;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*dest++ = ':';
|
||||||
|
*dest++ = ':';
|
||||||
|
memcpy(dest, macro->name, macroNameLen + 1);
|
||||||
|
|
||||||
|
newContext((struct FileStackNode *)fileInfo);
|
||||||
|
contextStack->lexerState = lexer_OpenFileView(macro->macro, macro->macroSize,
|
||||||
|
macro->fileLine);
|
||||||
|
if (!contextStack->lexerState)
|
||||||
|
fatalerror("Failed to set up lexer for macro invocation\n");
|
||||||
|
lexer_SetStateAtEOL(contextStack->lexerState);
|
||||||
|
contextStack->uniqueID = macro_UseNewUniqueID();
|
||||||
|
macro_UseNewArgs(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
static bool newReptContext(int32_t reptLineNo, char *body, size_t size)
|
||||||
* Set up a stringequate for parsing
|
|
||||||
*/
|
|
||||||
void fstk_RunString(char *s)
|
|
||||||
{
|
{
|
||||||
const struct sSymbol *pSym = sym_FindSymbol(s);
|
uint32_t reptDepth = contextStack->fileInfo->type == NODE_REPT
|
||||||
|
? ((struct FileStackReptNode *)contextStack->fileInfo)->reptDepth
|
||||||
|
: 0;
|
||||||
|
struct FileStackReptNode *fileInfo = malloc(sizeof(*fileInfo)
|
||||||
|
+ (reptDepth + 1) * sizeof(fileInfo->iters[0]));
|
||||||
|
|
||||||
if (pSym != NULL) {
|
if (!fileInfo) {
|
||||||
pushcontext();
|
error("Failed to alloc file info for REPT: %s\n", strerror(errno));
|
||||||
nCurrentStatus = STAT_isMacroArg;
|
return false;
|
||||||
strcpy(tzCurrentFileName, s);
|
}
|
||||||
CurrentFlexHandle =
|
fileInfo->node.type = NODE_REPT;
|
||||||
yy_scan_bytes(pSym->pMacro, strlen(pSym->pMacro));
|
fileInfo->reptDepth = reptDepth + 1;
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
fileInfo->iters[0] = 1;
|
||||||
|
if (reptDepth)
|
||||||
|
/* Copy all parent iter counts */
|
||||||
|
memcpy(&fileInfo->iters[1],
|
||||||
|
((struct FileStackReptNode *)contextStack->fileInfo)->iters,
|
||||||
|
reptDepth * sizeof(fileInfo->iters[0]));
|
||||||
|
|
||||||
|
newContext((struct FileStackNode *)fileInfo);
|
||||||
|
/* Correct our line number, which currently points to the `ENDR` line */
|
||||||
|
contextStack->fileInfo->lineNo = reptLineNo;
|
||||||
|
|
||||||
|
contextStack->lexerState = lexer_OpenFileView(body, size, reptLineNo);
|
||||||
|
if (!contextStack->lexerState)
|
||||||
|
fatalerror("Failed to set up lexer for REPT block\n");
|
||||||
|
lexer_SetStateAtEOL(contextStack->lexerState);
|
||||||
|
contextStack->uniqueID = macro_UseNewUniqueID();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fstk_RunRept(uint32_t count, int32_t reptLineNo, char *body, size_t size)
|
||||||
|
{
|
||||||
|
dbgPrint("Running REPT(%" PRIu32 ")\n", count);
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
return;
|
||||||
|
if (!newReptContext(reptLineNo, body, size))
|
||||||
|
return;
|
||||||
|
|
||||||
|
contextStack->nbReptIters = count;
|
||||||
|
contextStack->forName = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fstk_RunFor(char const *symName, int32_t start, int32_t stop, int32_t step,
|
||||||
|
int32_t reptLineNo, char *body, size_t size)
|
||||||
|
{
|
||||||
|
dbgPrint("Running FOR(\"%s\", %" PRId32 ", %" PRId32 ", %" PRId32 ")\n",
|
||||||
|
symName, start, stop, step);
|
||||||
|
|
||||||
|
struct Symbol *sym = sym_AddSet(symName, start);
|
||||||
|
|
||||||
|
if (sym->type != SYM_SET)
|
||||||
|
return;
|
||||||
|
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
if (step > 0 && start < stop)
|
||||||
|
count = (stop - start - 1) / step + 1;
|
||||||
|
else if (step < 0 && stop < start)
|
||||||
|
count = (start - stop - 1) / -step + 1;
|
||||||
|
else if (step == 0)
|
||||||
|
error("FOR cannot have a step value of 0\n");
|
||||||
|
|
||||||
|
if (count == 0)
|
||||||
|
return;
|
||||||
|
if (!newReptContext(reptLineNo, body, size))
|
||||||
|
return;
|
||||||
|
|
||||||
|
contextStack->nbReptIters = count;
|
||||||
|
contextStack->forValue = start;
|
||||||
|
contextStack->forStep = step;
|
||||||
|
contextStack->forName = strdup(symName);
|
||||||
|
if (!contextStack->forName)
|
||||||
|
fatalerror("Not enough memory for FOR symbol name: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
void fstk_StopRept(void)
|
||||||
|
{
|
||||||
|
/* Prevent more iterations */
|
||||||
|
contextStack->nbReptIters = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool fstk_Break(void)
|
||||||
|
{
|
||||||
|
dbgPrint("Breaking out of REPT/FOR\n");
|
||||||
|
|
||||||
|
if (contextStack->fileInfo->type != NODE_REPT) {
|
||||||
|
error("BREAK can only be used inside a REPT/FOR block\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fstk_StopRept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fstk_Init(char const *mainPath, size_t maxRecursionDepth)
|
||||||
|
{
|
||||||
|
struct LexerState *state = lexer_OpenFile(mainPath);
|
||||||
|
|
||||||
|
if (!state)
|
||||||
|
fatalerror("Failed to open main file!\n");
|
||||||
|
lexer_SetState(state);
|
||||||
|
char const *fileName = lexer_GetFileName();
|
||||||
|
size_t len = strlen(fileName);
|
||||||
|
struct Context *context = malloc(sizeof(*contextStack));
|
||||||
|
struct FileStackNamedNode *fileInfo = malloc(sizeof(*fileInfo) + len + 1);
|
||||||
|
|
||||||
|
if (!context)
|
||||||
|
fatalerror("Failed to allocate memory for main context: %s\n", strerror(errno));
|
||||||
|
if (!fileInfo)
|
||||||
|
fatalerror("Failed to allocate memory for main file info: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
context->fileInfo = (struct FileStackNode *)fileInfo;
|
||||||
|
/* lineNo and reptIter are unused on the top-level context */
|
||||||
|
context->fileInfo->parent = NULL;
|
||||||
|
context->fileInfo->lineNo = 0; // This still gets written to the object file, so init it
|
||||||
|
context->fileInfo->referenced = false;
|
||||||
|
context->fileInfo->type = NODE_FILE;
|
||||||
|
memcpy(fileInfo->name, fileName, len + 1);
|
||||||
|
|
||||||
|
context->parent = NULL;
|
||||||
|
context->lexerState = state;
|
||||||
|
context->uniqueID = 0;
|
||||||
|
macro_SetUniqueID(0);
|
||||||
|
context->nbReptIters = 0;
|
||||||
|
context->forValue = 0;
|
||||||
|
context->forStep = 0;
|
||||||
|
context->forName = NULL;
|
||||||
|
|
||||||
|
/* Now that it's set up properly, register the context */
|
||||||
|
contextStack = context;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Check that max recursion depth won't allow overflowing node `malloc`s
|
||||||
|
* This assumes that the rept node is larger
|
||||||
|
*/
|
||||||
|
#define DEPTH_LIMIT ((SIZE_MAX - sizeof(struct FileStackReptNode)) / sizeof(uint32_t))
|
||||||
|
if (maxRecursionDepth > DEPTH_LIMIT) {
|
||||||
|
error("Recursion depth may not be higher than %zu, defaulting to "
|
||||||
|
EXPAND_AND_STR(DEFAULT_MAX_DEPTH) "\n", DEPTH_LIMIT);
|
||||||
|
nMaxRecursionDepth = DEFAULT_MAX_DEPTH;
|
||||||
} else {
|
} else {
|
||||||
yyerror("No such string symbol '%s'", s);
|
nMaxRecursionDepth = maxRecursionDepth;
|
||||||
}
|
}
|
||||||
}
|
/* Make sure that the default of 64 is OK, though */
|
||||||
|
assert(DEPTH_LIMIT >= DEFAULT_MAX_DEPTH);
|
||||||
/*
|
#undef DEPTH_LIMIT
|
||||||
* Set up a repeat block for parsing
|
|
||||||
*/
|
|
||||||
void fstk_RunRept(uint32_t count)
|
|
||||||
{
|
|
||||||
if (count) {
|
|
||||||
pushcontext();
|
|
||||||
sym_UseCurrentMacroArgs();
|
|
||||||
sym_SetMacroArgID(nMacroCount++);
|
|
||||||
sym_UseNewMacroArgs();
|
|
||||||
nCurrentREPTBlockCount = count;
|
|
||||||
nCurrentStatus = STAT_isREPTBlock;
|
|
||||||
nCurrentREPTBlockSize = ulNewMacroSize;
|
|
||||||
pCurrentREPTBlock = tzNewMacro;
|
|
||||||
CurrentFlexHandle =
|
|
||||||
yy_scan_bytes(pCurrentREPTBlock, nCurrentREPTBlockSize);
|
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Initialize the filestack routines
|
|
||||||
*/
|
|
||||||
void fstk_Init(char *s)
|
|
||||||
{
|
|
||||||
char tzFileName[_MAX_PATH + 1];
|
|
||||||
char tzSymFileName[_MAX_PATH + 1 + 2];
|
|
||||||
|
|
||||||
snprintf(tzSymFileName, sizeof(tzSymFileName), "\"%s\"", s);
|
|
||||||
sym_AddString("__FILE__", tzSymFileName);
|
|
||||||
|
|
||||||
strcpy(tzFileName, s);
|
|
||||||
pFileStack = NULL;
|
|
||||||
pCurrentFile = fopen(tzFileName, "rb");
|
|
||||||
if (pCurrentFile == NULL)
|
|
||||||
err(1, "Unable to open file '%s'", tzFileName);
|
|
||||||
|
|
||||||
nMacroCount = 0;
|
|
||||||
nCurrentStatus = STAT_isInclude;
|
|
||||||
snprintf(tzCurrentFileName, _MAX_PATH + 1, "%s", tzFileName);
|
|
||||||
CurrentFlexHandle = yy_create_buffer(pCurrentFile);
|
|
||||||
yy_switch_to_buffer(CurrentFlexHandle);
|
|
||||||
nLineNo = 1;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,601 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include "asm/asm.h"
|
|
||||||
#include "asm/lexer.h"
|
|
||||||
#include "asm/main.h"
|
|
||||||
#include "asm/rpn.h"
|
|
||||||
#include "asm/symbol.h"
|
|
||||||
#include "asm/symbol.h"
|
|
||||||
|
|
||||||
#include "helpers.h"
|
|
||||||
|
|
||||||
#include "asmy.h"
|
|
||||||
|
|
||||||
bool oDontExpandStrings;
|
|
||||||
int32_t nGBGfxID = -1;
|
|
||||||
int32_t nBinaryID = -1;
|
|
||||||
|
|
||||||
static int32_t gbgfx2bin(char ch)
|
|
||||||
{
|
|
||||||
int32_t i;
|
|
||||||
|
|
||||||
for (i = 0; i <= 3; i += 1) {
|
|
||||||
if (CurrentOptions.gbgfx[i] == ch)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t binary2bin(char ch)
|
|
||||||
{
|
|
||||||
int32_t i;
|
|
||||||
|
|
||||||
for (i = 0; i <= 1; i += 1) {
|
|
||||||
if (CurrentOptions.binary[i] == ch)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int32_t char2bin(char ch)
|
|
||||||
{
|
|
||||||
if (ch >= 'a' && ch <= 'f')
|
|
||||||
return (ch - 'a' + 10);
|
|
||||||
|
|
||||||
if (ch >= 'A' && ch <= 'F')
|
|
||||||
return (ch - 'A' + 10);
|
|
||||||
|
|
||||||
if (ch >= '0' && ch <= '9')
|
|
||||||
return (ch - '0');
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef int32_t(*x2bin) (char ch);
|
|
||||||
|
|
||||||
static int32_t ascii2bin(char *s)
|
|
||||||
{
|
|
||||||
int32_t radix = 10;
|
|
||||||
int32_t result = 0;
|
|
||||||
x2bin convertfunc = char2bin;
|
|
||||||
|
|
||||||
switch (*s) {
|
|
||||||
case '$':
|
|
||||||
radix = 16;
|
|
||||||
s += 1;
|
|
||||||
convertfunc = char2bin;
|
|
||||||
break;
|
|
||||||
case '&':
|
|
||||||
radix = 8;
|
|
||||||
s += 1;
|
|
||||||
convertfunc = char2bin;
|
|
||||||
break;
|
|
||||||
case '`':
|
|
||||||
radix = 4;
|
|
||||||
s += 1;
|
|
||||||
convertfunc = gbgfx2bin;
|
|
||||||
break;
|
|
||||||
case '%':
|
|
||||||
radix = 2;
|
|
||||||
s += 1;
|
|
||||||
convertfunc = binary2bin;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
/* Handle below */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (radix == 4) {
|
|
||||||
int32_t c;
|
|
||||||
|
|
||||||
while (*s != '\0') {
|
|
||||||
c = convertfunc(*s++);
|
|
||||||
result = result * 2 + ((c & 2) << 7) + (c & 1);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
while (*s != '\0')
|
|
||||||
result = result * radix + convertfunc(*s++);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ParseFixedPoint(char *s, uint32_t size)
|
|
||||||
{
|
|
||||||
uint32_t i = 0, dot = 0;
|
|
||||||
|
|
||||||
while (size && dot != 2) {
|
|
||||||
if (s[i] == '.')
|
|
||||||
dot += 1;
|
|
||||||
|
|
||||||
if (dot < 2) {
|
|
||||||
size -= 1;
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
yyunputbytes(size);
|
|
||||||
|
|
||||||
yylval.nConstValue = (int32_t)(atof(s) * 65536);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ParseNumber(char *s, uint32_t size)
|
|
||||||
{
|
|
||||||
char dest[256];
|
|
||||||
|
|
||||||
strncpy(dest, s, size);
|
|
||||||
dest[size] = 0;
|
|
||||||
yylval.nConstValue = ascii2bin(dest);
|
|
||||||
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t ParseSymbol(char *src, uint32_t size)
|
|
||||||
{
|
|
||||||
char dest[MAXSYMLEN + 1];
|
|
||||||
int32_t copied = 0, size_backup = size;
|
|
||||||
|
|
||||||
while (size && copied < MAXSYMLEN) {
|
|
||||||
if (*src == '\\') {
|
|
||||||
char *marg;
|
|
||||||
|
|
||||||
src += 1;
|
|
||||||
size -= 1;
|
|
||||||
|
|
||||||
if (*src == '@') {
|
|
||||||
marg = sym_FindMacroArg(-1);
|
|
||||||
} else if (*src >= '0' && *src <= '9') {
|
|
||||||
marg = sym_FindMacroArg(*src - '0');
|
|
||||||
} else {
|
|
||||||
fatalerror("Malformed ID");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
src += 1;
|
|
||||||
size -= 1;
|
|
||||||
|
|
||||||
if (marg) {
|
|
||||||
while (*marg)
|
|
||||||
dest[copied++] = *marg++;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
dest[copied++] = *src++;
|
|
||||||
size -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (copied > MAXSYMLEN)
|
|
||||||
fatalerror("Symbol too long");
|
|
||||||
|
|
||||||
dest[copied] = 0;
|
|
||||||
|
|
||||||
if (!oDontExpandStrings && sym_isString(dest)) {
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
yyskipbytes(size_backup);
|
|
||||||
yyunputstr(s = sym_GetStringValue(dest));
|
|
||||||
|
|
||||||
while (*s) {
|
|
||||||
if (*s++ == '\n')
|
|
||||||
nLineNo -= 1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
strcpy(yylval.tzString, dest);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PutMacroArg(char *src, uint32_t size)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
yyskipbytes(size);
|
|
||||||
if ((size == 2 && src[1] >= '1' && src[1] <= '9')) {
|
|
||||||
s = sym_FindMacroArg(src[1] - '0');
|
|
||||||
|
|
||||||
if (s != NULL)
|
|
||||||
yyunputstr(s);
|
|
||||||
else
|
|
||||||
yyerror("Macro argument not defined");
|
|
||||||
} else {
|
|
||||||
yyerror("Invalid macro argument");
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t PutUniqueArg(unused_ char *src, uint32_t size)
|
|
||||||
{
|
|
||||||
char *s;
|
|
||||||
|
|
||||||
yyskipbytes(size);
|
|
||||||
|
|
||||||
s = sym_FindMacroArg(-1);
|
|
||||||
|
|
||||||
if (s != NULL)
|
|
||||||
yyunputstr(s);
|
|
||||||
else
|
|
||||||
yyerror("Macro unique label string not defined");
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum {
|
|
||||||
T_LEX_MACROARG = 3000,
|
|
||||||
T_LEX_MACROUNIQUE
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct sLexInitString lexer_strings[] = {
|
|
||||||
{"adc", T_Z80_ADC},
|
|
||||||
{"add", T_Z80_ADD},
|
|
||||||
{"and", T_Z80_AND},
|
|
||||||
{"bit", T_Z80_BIT},
|
|
||||||
{"call", T_Z80_CALL},
|
|
||||||
{"ccf", T_Z80_CCF},
|
|
||||||
{"cpl", T_Z80_CPL},
|
|
||||||
{"cp", T_Z80_CP},
|
|
||||||
{"daa", T_Z80_DAA},
|
|
||||||
{"dec", T_Z80_DEC},
|
|
||||||
{"di", T_Z80_DI},
|
|
||||||
{"ei", T_Z80_EI},
|
|
||||||
{"halt", T_Z80_HALT},
|
|
||||||
{"inc", T_Z80_INC},
|
|
||||||
{"jp", T_Z80_JP},
|
|
||||||
{"jr", T_Z80_JR},
|
|
||||||
{"ld", T_Z80_LD},
|
|
||||||
{"ldi", T_Z80_LDI},
|
|
||||||
{"ldd", T_Z80_LDD},
|
|
||||||
{"ldio", T_Z80_LDIO},
|
|
||||||
{"ldh", T_Z80_LDIO},
|
|
||||||
{"nop", T_Z80_NOP},
|
|
||||||
{"or", T_Z80_OR},
|
|
||||||
{"pop", T_Z80_POP},
|
|
||||||
{"push", T_Z80_PUSH},
|
|
||||||
{"res", T_Z80_RES},
|
|
||||||
{"reti", T_Z80_RETI},
|
|
||||||
{"ret", T_Z80_RET},
|
|
||||||
{"rlca", T_Z80_RLCA},
|
|
||||||
{"rlc", T_Z80_RLC},
|
|
||||||
{"rla", T_Z80_RLA},
|
|
||||||
{"rl", T_Z80_RL},
|
|
||||||
{"rrc", T_Z80_RRC},
|
|
||||||
{"rrca", T_Z80_RRCA},
|
|
||||||
{"rra", T_Z80_RRA},
|
|
||||||
{"rr", T_Z80_RR},
|
|
||||||
{"rst", T_Z80_RST},
|
|
||||||
{"sbc", T_Z80_SBC},
|
|
||||||
{"scf", T_Z80_SCF},
|
|
||||||
{"set", T_POP_SET},
|
|
||||||
{"sla", T_Z80_SLA},
|
|
||||||
{"sra", T_Z80_SRA},
|
|
||||||
{"srl", T_Z80_SRL},
|
|
||||||
{"stop", T_Z80_STOP},
|
|
||||||
{"sub", T_Z80_SUB},
|
|
||||||
{"swap", T_Z80_SWAP},
|
|
||||||
{"xor", T_Z80_XOR},
|
|
||||||
|
|
||||||
{"nz", T_CC_NZ},
|
|
||||||
{"z", T_CC_Z},
|
|
||||||
{"nc", T_CC_NC},
|
|
||||||
/* Handled in list of registers */
|
|
||||||
/* { "c", T_TOKEN_C }, */
|
|
||||||
|
|
||||||
{"[bc]", T_MODE_BC_IND},
|
|
||||||
{"[de]", T_MODE_DE_IND},
|
|
||||||
{"[hl]", T_MODE_HL_IND},
|
|
||||||
{"[hl+]", T_MODE_HL_INDINC},
|
|
||||||
{"[hl-]", T_MODE_HL_INDDEC},
|
|
||||||
{"[hli]", T_MODE_HL_INDINC},
|
|
||||||
{"[hld]", T_MODE_HL_INDDEC},
|
|
||||||
{"[sp]", T_MODE_SP_IND},
|
|
||||||
{"af", T_MODE_AF},
|
|
||||||
{"bc", T_MODE_BC},
|
|
||||||
{"de", T_MODE_DE},
|
|
||||||
{"hl", T_MODE_HL},
|
|
||||||
{"sp", T_MODE_SP},
|
|
||||||
{"[c]", T_MODE_C_IND},
|
|
||||||
{"[$ff00+c]", T_MODE_C_IND},
|
|
||||||
|
|
||||||
{"a", T_TOKEN_A},
|
|
||||||
{"b", T_TOKEN_B},
|
|
||||||
{"c", T_TOKEN_C},
|
|
||||||
{"d", T_TOKEN_D},
|
|
||||||
{"e", T_TOKEN_E},
|
|
||||||
{"h", T_TOKEN_H},
|
|
||||||
{"l", T_TOKEN_L},
|
|
||||||
|
|
||||||
{"||", T_OP_LOGICOR},
|
|
||||||
{"&&", T_OP_LOGICAND},
|
|
||||||
{"==", T_OP_LOGICEQU},
|
|
||||||
{">", T_OP_LOGICGT},
|
|
||||||
{"<", T_OP_LOGICLT},
|
|
||||||
{">=", T_OP_LOGICGE},
|
|
||||||
{"<=", T_OP_LOGICLE},
|
|
||||||
{"!=", T_OP_LOGICNE},
|
|
||||||
{"!", T_OP_LOGICNOT},
|
|
||||||
{"|", T_OP_OR},
|
|
||||||
{"^", T_OP_XOR},
|
|
||||||
{"&", T_OP_AND},
|
|
||||||
{"<<", T_OP_SHL},
|
|
||||||
{">>", T_OP_SHR},
|
|
||||||
{"+", T_OP_ADD},
|
|
||||||
{"-", T_OP_SUB},
|
|
||||||
{"*", T_OP_MUL},
|
|
||||||
{"/", T_OP_DIV},
|
|
||||||
{"%", T_OP_MOD},
|
|
||||||
{"~", T_OP_NOT},
|
|
||||||
|
|
||||||
{"def", T_OP_DEF},
|
|
||||||
|
|
||||||
{"bank", T_OP_BANK},
|
|
||||||
{"align", T_OP_ALIGN},
|
|
||||||
|
|
||||||
{"round", T_OP_ROUND},
|
|
||||||
{"ceil", T_OP_CEIL},
|
|
||||||
{"floor", T_OP_FLOOR},
|
|
||||||
{"div", T_OP_FDIV},
|
|
||||||
{"mul", T_OP_FMUL},
|
|
||||||
{"sin", T_OP_SIN},
|
|
||||||
{"cos", T_OP_COS},
|
|
||||||
{"tan", T_OP_TAN},
|
|
||||||
{"asin", T_OP_ASIN},
|
|
||||||
{"acos", T_OP_ACOS},
|
|
||||||
{"atan", T_OP_ATAN},
|
|
||||||
{"atan2", T_OP_ATAN2},
|
|
||||||
|
|
||||||
{"high", T_OP_HIGH},
|
|
||||||
{"low", T_OP_LOW},
|
|
||||||
|
|
||||||
{"strcmp", T_OP_STRCMP},
|
|
||||||
{"strin", T_OP_STRIN},
|
|
||||||
{"strsub", T_OP_STRSUB},
|
|
||||||
{"strlen", T_OP_STRLEN},
|
|
||||||
{"strcat", T_OP_STRCAT},
|
|
||||||
{"strupr", T_OP_STRUPR},
|
|
||||||
{"strlwr", T_OP_STRLWR},
|
|
||||||
|
|
||||||
{"include", T_POP_INCLUDE},
|
|
||||||
{"printt", T_POP_PRINTT},
|
|
||||||
{"printi", T_POP_PRINTI},
|
|
||||||
{"printv", T_POP_PRINTV},
|
|
||||||
{"printf", T_POP_PRINTF},
|
|
||||||
{"export", T_POP_EXPORT},
|
|
||||||
{"xdef", T_POP_EXPORT},
|
|
||||||
{"import", T_POP_IMPORT},
|
|
||||||
{"xref", T_POP_IMPORT},
|
|
||||||
{"global", T_POP_GLOBAL},
|
|
||||||
{"ds", T_POP_DS},
|
|
||||||
{"db", T_POP_DB},
|
|
||||||
{"dw", T_POP_DW},
|
|
||||||
{"dl", T_POP_DL},
|
|
||||||
{"section", T_POP_SECTION},
|
|
||||||
{"purge", T_POP_PURGE},
|
|
||||||
|
|
||||||
{"rsreset", T_POP_RSRESET},
|
|
||||||
{"rsset", T_POP_RSSET},
|
|
||||||
|
|
||||||
{"incbin", T_POP_INCBIN},
|
|
||||||
{"charmap", T_POP_CHARMAP},
|
|
||||||
|
|
||||||
{"fail", T_POP_FAIL},
|
|
||||||
{"warn", T_POP_WARN},
|
|
||||||
|
|
||||||
{"macro", T_POP_MACRO},
|
|
||||||
/* Not needed but we have it here just to protect the name */
|
|
||||||
{"endm", T_POP_ENDM},
|
|
||||||
{"shift", T_POP_SHIFT},
|
|
||||||
|
|
||||||
{"rept", T_POP_REPT},
|
|
||||||
/* Not needed but we have it here just to protect the name */
|
|
||||||
{"endr", T_POP_ENDR},
|
|
||||||
|
|
||||||
{"if", T_POP_IF},
|
|
||||||
{"else", T_POP_ELSE},
|
|
||||||
{"elif", T_POP_ELIF},
|
|
||||||
{"endc", T_POP_ENDC},
|
|
||||||
|
|
||||||
{"union", T_POP_UNION},
|
|
||||||
{"nextu", T_POP_NEXTU},
|
|
||||||
{"endu", T_POP_ENDU},
|
|
||||||
|
|
||||||
{"wram0", T_SECT_WRAM0},
|
|
||||||
{"vram", T_SECT_VRAM},
|
|
||||||
{"romx", T_SECT_ROMX},
|
|
||||||
{"rom0", T_SECT_ROM0},
|
|
||||||
{"hram", T_SECT_HRAM},
|
|
||||||
{"wramx", T_SECT_WRAMX},
|
|
||||||
{"sram", T_SECT_SRAM},
|
|
||||||
{"oam", T_SECT_OAM},
|
|
||||||
|
|
||||||
/* Deprecated section type names */
|
|
||||||
{"home", T_SECT_HOME},
|
|
||||||
{"code", T_SECT_CODE},
|
|
||||||
{"data", T_SECT_DATA},
|
|
||||||
{"bss", T_SECT_BSS},
|
|
||||||
|
|
||||||
{"rb", T_POP_RB},
|
|
||||||
{"rw", T_POP_RW},
|
|
||||||
{"equ", T_POP_EQU},
|
|
||||||
{"equs", T_POP_EQUS},
|
|
||||||
|
|
||||||
/* Handled before in list of CPU instructions */
|
|
||||||
/* {"set", T_POP_SET}, */
|
|
||||||
{"=", T_POP_SET},
|
|
||||||
|
|
||||||
{"pushs", T_POP_PUSHS},
|
|
||||||
{"pops", T_POP_POPS},
|
|
||||||
{"pusho", T_POP_PUSHO},
|
|
||||||
{"popo", T_POP_POPO},
|
|
||||||
|
|
||||||
{"opt", T_POP_OPT},
|
|
||||||
|
|
||||||
{NULL, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct sLexFloat tNumberToken = {
|
|
||||||
ParseNumber,
|
|
||||||
T_NUMBER
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct sLexFloat tFixedPointToken = {
|
|
||||||
ParseFixedPoint,
|
|
||||||
T_NUMBER
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct sLexFloat tIDToken = {
|
|
||||||
ParseSymbol,
|
|
||||||
T_ID
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct sLexFloat tMacroArgToken = {
|
|
||||||
PutMacroArg,
|
|
||||||
T_LEX_MACROARG
|
|
||||||
};
|
|
||||||
|
|
||||||
const struct sLexFloat tMacroUniqueToken = {
|
|
||||||
PutUniqueArg,
|
|
||||||
T_LEX_MACROUNIQUE
|
|
||||||
};
|
|
||||||
|
|
||||||
void setup_lexer(void)
|
|
||||||
{
|
|
||||||
uint32_t id;
|
|
||||||
|
|
||||||
lex_Init();
|
|
||||||
lex_AddStrings(lexer_strings);
|
|
||||||
|
|
||||||
//Macro arguments
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tMacroArgToken);
|
|
||||||
lex_FloatAddFirstRange(id, '\\', '\\');
|
|
||||||
lex_FloatAddSecondRange(id, '1', '9');
|
|
||||||
id = lex_FloatAlloc(&tMacroUniqueToken);
|
|
||||||
lex_FloatAddFirstRange(id, '\\', '\\');
|
|
||||||
lex_FloatAddSecondRange(id, '@', '@');
|
|
||||||
|
|
||||||
//Decimal constants
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tNumberToken);
|
|
||||||
lex_FloatAddFirstRange(id, '0', '9');
|
|
||||||
lex_FloatAddSecondRange(id, '0', '9');
|
|
||||||
lex_FloatAddRange(id, '0', '9');
|
|
||||||
|
|
||||||
//Binary constants
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tNumberToken);
|
|
||||||
nBinaryID = id;
|
|
||||||
lex_FloatAddFirstRange(id, '%', '%');
|
|
||||||
lex_FloatAddSecondRange(id, CurrentOptions.binary[0],
|
|
||||||
CurrentOptions.binary[0]);
|
|
||||||
lex_FloatAddSecondRange(id, CurrentOptions.binary[1],
|
|
||||||
CurrentOptions.binary[1]);
|
|
||||||
lex_FloatAddRange(id, CurrentOptions.binary[0],
|
|
||||||
CurrentOptions.binary[0]);
|
|
||||||
lex_FloatAddRange(id, CurrentOptions.binary[1],
|
|
||||||
CurrentOptions.binary[1]);
|
|
||||||
|
|
||||||
//Octal constants
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tNumberToken);
|
|
||||||
lex_FloatAddFirstRange(id, '&', '&');
|
|
||||||
lex_FloatAddSecondRange(id, '0', '7');
|
|
||||||
lex_FloatAddRange(id, '0', '7');
|
|
||||||
|
|
||||||
//Gameboy gfx constants
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tNumberToken);
|
|
||||||
nGBGfxID = id;
|
|
||||||
lex_FloatAddFirstRange(id, '`', '`');
|
|
||||||
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[0],
|
|
||||||
CurrentOptions.gbgfx[0]);
|
|
||||||
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[1],
|
|
||||||
CurrentOptions.gbgfx[1]);
|
|
||||||
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[2],
|
|
||||||
CurrentOptions.gbgfx[2]);
|
|
||||||
lex_FloatAddSecondRange(id, CurrentOptions.gbgfx[3],
|
|
||||||
CurrentOptions.gbgfx[3]);
|
|
||||||
lex_FloatAddRange(id, CurrentOptions.gbgfx[0], CurrentOptions.gbgfx[0]);
|
|
||||||
lex_FloatAddRange(id, CurrentOptions.gbgfx[1], CurrentOptions.gbgfx[1]);
|
|
||||||
lex_FloatAddRange(id, CurrentOptions.gbgfx[2], CurrentOptions.gbgfx[2]);
|
|
||||||
lex_FloatAddRange(id, CurrentOptions.gbgfx[3], CurrentOptions.gbgfx[3]);
|
|
||||||
|
|
||||||
//Hex constants
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tNumberToken);
|
|
||||||
lex_FloatAddFirstRange(id, '$', '$');
|
|
||||||
lex_FloatAddSecondRange(id, '0', '9');
|
|
||||||
lex_FloatAddSecondRange(id, 'A', 'F');
|
|
||||||
lex_FloatAddSecondRange(id, 'a', 'f');
|
|
||||||
lex_FloatAddRange(id, '0', '9');
|
|
||||||
lex_FloatAddRange(id, 'A', 'F');
|
|
||||||
lex_FloatAddRange(id, 'a', 'f');
|
|
||||||
|
|
||||||
//ID 's
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tIDToken);
|
|
||||||
lex_FloatAddFirstRange(id, 'a', 'z');
|
|
||||||
lex_FloatAddFirstRange(id, 'A', 'Z');
|
|
||||||
lex_FloatAddFirstRange(id, '_', '_');
|
|
||||||
lex_FloatAddSecondRange(id, 'a', 'z');
|
|
||||||
lex_FloatAddSecondRange(id, 'A', 'Z');
|
|
||||||
lex_FloatAddSecondRange(id, '0', '9');
|
|
||||||
lex_FloatAddSecondRange(id, '_', '_');
|
|
||||||
lex_FloatAddSecondRange(id, '\\', '\\');
|
|
||||||
lex_FloatAddSecondRange(id, '@', '@');
|
|
||||||
lex_FloatAddSecondRange(id, '#', '#');
|
|
||||||
lex_FloatAddRange(id, '.', '.');
|
|
||||||
lex_FloatAddRange(id, 'a', 'z');
|
|
||||||
lex_FloatAddRange(id, 'A', 'Z');
|
|
||||||
lex_FloatAddRange(id, '0', '9');
|
|
||||||
lex_FloatAddRange(id, '_', '_');
|
|
||||||
lex_FloatAddRange(id, '\\', '\\');
|
|
||||||
lex_FloatAddRange(id, '@', '@');
|
|
||||||
lex_FloatAddRange(id, '#', '#');
|
|
||||||
|
|
||||||
//Local ID
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tIDToken);
|
|
||||||
lex_FloatAddFirstRange(id, '.', '.');
|
|
||||||
lex_FloatAddSecondRange(id, 'a', 'z');
|
|
||||||
lex_FloatAddSecondRange(id, 'A', 'Z');
|
|
||||||
lex_FloatAddSecondRange(id, '_', '_');
|
|
||||||
lex_FloatAddRange(id, 'a', 'z');
|
|
||||||
lex_FloatAddRange(id, 'A', 'Z');
|
|
||||||
lex_FloatAddRange(id, '0', '9');
|
|
||||||
lex_FloatAddRange(id, '_', '_');
|
|
||||||
lex_FloatAddRange(id, '\\', '\\');
|
|
||||||
lex_FloatAddRange(id, '@', '@');
|
|
||||||
lex_FloatAddRange(id, '#', '#');
|
|
||||||
|
|
||||||
// "@"
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tIDToken);
|
|
||||||
lex_FloatAddFirstRange(id, '@', '@');
|
|
||||||
|
|
||||||
//Fixed point constants
|
|
||||||
|
|
||||||
id = lex_FloatAlloc(&tFixedPointToken);
|
|
||||||
lex_FloatAddFirstRange(id, '.', '.');
|
|
||||||
lex_FloatAddFirstRange(id, '0', '9');
|
|
||||||
lex_FloatAddSecondRange(id, '.', '.');
|
|
||||||
lex_FloatAddSecondRange(id, '0', '9');
|
|
||||||
lex_FloatAddRange(id, '.', '.');
|
|
||||||
lex_FloatAddRange(id, '0', '9');
|
|
||||||
}
|
|
||||||
+2571
-731
File diff suppressed because it is too large
Load Diff
+190
@@ -0,0 +1,190 @@
|
|||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "asm/macro.h"
|
||||||
|
#include "asm/warning.h"
|
||||||
|
|
||||||
|
#define MAXMACROARGS 99999
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Your average macro invocation does not go past the tens, but some go further
|
||||||
|
* This ensures that sane and slightly insane invocations suffer no penalties,
|
||||||
|
* and the rest is insane and thus will assume responsibility.
|
||||||
|
* Additionally, ~300 bytes (on x64) of memory per level of nesting has been
|
||||||
|
* deemed reasonable. (Halve that on x86.)
|
||||||
|
*/
|
||||||
|
#define INITIAL_ARG_SIZE 32
|
||||||
|
struct MacroArgs {
|
||||||
|
unsigned int nbArgs;
|
||||||
|
unsigned int shift;
|
||||||
|
unsigned int capacity;
|
||||||
|
char *args[];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define SIZEOF_ARGS(nbArgs) (sizeof(struct MacroArgs) + \
|
||||||
|
sizeof(((struct MacroArgs){0}).args[0]) * (nbArgs))
|
||||||
|
|
||||||
|
static struct MacroArgs *macroArgs = NULL;
|
||||||
|
static uint32_t uniqueID = 0;
|
||||||
|
static uint32_t maxUniqueID = 0;
|
||||||
|
/*
|
||||||
|
* The initialization is somewhat harmful, since it is never used, but it
|
||||||
|
* guarantees the size of the buffer will be correct. I was unable to find a
|
||||||
|
* better solution, but if you have one, please feel free!
|
||||||
|
*/
|
||||||
|
static char uniqueIDBuf[] = "_u4294967295"; // UINT32_MAX
|
||||||
|
static char *uniqueIDPtr = NULL;
|
||||||
|
|
||||||
|
struct MacroArgs *macro_GetCurrentArgs(void)
|
||||||
|
{
|
||||||
|
return macroArgs;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MacroArgs *macro_NewArgs(void)
|
||||||
|
{
|
||||||
|
struct MacroArgs *args = malloc(SIZEOF_ARGS(INITIAL_ARG_SIZE));
|
||||||
|
|
||||||
|
if (!args)
|
||||||
|
fatalerror("Unable to register macro arguments: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
args->nbArgs = 0;
|
||||||
|
args->shift = 0;
|
||||||
|
args->capacity = INITIAL_ARG_SIZE;
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void macro_AppendArg(struct MacroArgs **argPtr, char *s)
|
||||||
|
{
|
||||||
|
#define macArgs (*argPtr)
|
||||||
|
if (s[0] == '\0')
|
||||||
|
warning(WARNING_EMPTY_MACRO_ARG, "Empty macro argument\n");
|
||||||
|
if (macArgs->nbArgs == MAXMACROARGS)
|
||||||
|
error("A maximum of " EXPAND_AND_STR(MAXMACROARGS) " arguments is allowed\n");
|
||||||
|
if (macArgs->nbArgs >= macArgs->capacity) {
|
||||||
|
macArgs->capacity *= 2;
|
||||||
|
/* Check that overflow didn't roll us back */
|
||||||
|
if (macArgs->capacity <= macArgs->nbArgs)
|
||||||
|
fatalerror("Failed to add new macro argument: capacity overflow\n");
|
||||||
|
macArgs = realloc(macArgs, SIZEOF_ARGS(macArgs->capacity));
|
||||||
|
if (!macArgs)
|
||||||
|
fatalerror("Error adding new macro argument: %s\n", strerror(errno));
|
||||||
|
}
|
||||||
|
macArgs->args[macArgs->nbArgs++] = s;
|
||||||
|
#undef macArgs
|
||||||
|
}
|
||||||
|
|
||||||
|
void macro_UseNewArgs(struct MacroArgs *args)
|
||||||
|
{
|
||||||
|
macroArgs = args;
|
||||||
|
}
|
||||||
|
|
||||||
|
void macro_FreeArgs(struct MacroArgs *args)
|
||||||
|
{
|
||||||
|
for (uint32_t i = 0; i < macroArgs->nbArgs; i++)
|
||||||
|
free(args->args[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
char const *macro_GetArg(uint32_t i)
|
||||||
|
{
|
||||||
|
if (!macroArgs)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
uint32_t realIndex = i + macroArgs->shift - 1;
|
||||||
|
|
||||||
|
return realIndex >= macroArgs->nbArgs ? NULL
|
||||||
|
: macroArgs->args[realIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
char *macro_GetAllArgs(void)
|
||||||
|
{
|
||||||
|
if (!macroArgs)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (macroArgs->shift >= macroArgs->nbArgs)
|
||||||
|
return "";
|
||||||
|
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
for (uint32_t i = macroArgs->shift; i < macroArgs->nbArgs; i++)
|
||||||
|
len += strlen(macroArgs->args[i]) + 1; /* 1 for comma */
|
||||||
|
|
||||||
|
char *str = malloc(len + 1); /* 1 for '\0' */
|
||||||
|
char *ptr = str;
|
||||||
|
|
||||||
|
if (!str)
|
||||||
|
fatalerror("Failed to allocate memory for expanding '\\#': %s\n", strerror(errno));
|
||||||
|
|
||||||
|
for (uint32_t i = macroArgs->shift; i < macroArgs->nbArgs; i++) {
|
||||||
|
size_t n = strlen(macroArgs->args[i]);
|
||||||
|
|
||||||
|
memcpy(ptr, macroArgs->args[i], n);
|
||||||
|
ptr += n;
|
||||||
|
|
||||||
|
/* Commas go between args and after a last empty arg */
|
||||||
|
if (i < macroArgs->nbArgs - 1 || n == 0)
|
||||||
|
*ptr++ = ','; /* no space after comma */
|
||||||
|
}
|
||||||
|
*ptr = '\0';
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t macro_GetUniqueID(void)
|
||||||
|
{
|
||||||
|
return uniqueID;
|
||||||
|
}
|
||||||
|
|
||||||
|
char const *macro_GetUniqueIDStr(void)
|
||||||
|
{
|
||||||
|
return uniqueIDPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void macro_SetUniqueID(uint32_t id)
|
||||||
|
{
|
||||||
|
uniqueID = id;
|
||||||
|
if (id == 0) {
|
||||||
|
uniqueIDPtr = NULL;
|
||||||
|
} else {
|
||||||
|
if (uniqueID > maxUniqueID)
|
||||||
|
maxUniqueID = uniqueID;
|
||||||
|
/* The buffer is guaranteed to be the correct size */
|
||||||
|
/* This is a valid label fragment, but not a valid numeric */
|
||||||
|
sprintf(uniqueIDBuf, "_u%" PRIu32, id);
|
||||||
|
uniqueIDPtr = uniqueIDBuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t macro_UseNewUniqueID(void)
|
||||||
|
{
|
||||||
|
macro_SetUniqueID(++maxUniqueID);
|
||||||
|
return maxUniqueID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void macro_ShiftCurrentArgs(int32_t count)
|
||||||
|
{
|
||||||
|
if (!macroArgs) {
|
||||||
|
error("Cannot shift macro arguments outside of a macro\n");
|
||||||
|
} else if (count > 0 && ((uint32_t)count > macroArgs->nbArgs
|
||||||
|
|| macroArgs->shift > macroArgs->nbArgs - count)) {
|
||||||
|
warning(WARNING_MACRO_SHIFT,
|
||||||
|
"Cannot shift macro arguments past their end\n");
|
||||||
|
macroArgs->shift = macroArgs->nbArgs;
|
||||||
|
} else if (count < 0 && macroArgs->shift < (uint32_t)-count) {
|
||||||
|
warning(WARNING_MACRO_SHIFT,
|
||||||
|
"Cannot shift macro arguments past their beginning\n");
|
||||||
|
macroArgs->shift = 0;
|
||||||
|
} else {
|
||||||
|
macroArgs->shift += count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t macro_NbArgs(void)
|
||||||
|
{
|
||||||
|
return macroArgs->nbArgs - macroArgs->shift;
|
||||||
|
}
|
||||||
+257
-386
@@ -6,7 +6,10 @@
|
|||||||
* SPDX-License-Identifier: MIT
|
* SPDX-License-Identifier: MIT
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <float.h>
|
#include <float.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@@ -14,281 +17,118 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
#include "asm/symbol.h"
|
#include "asm/charmap.h"
|
||||||
|
#include "asm/format.h"
|
||||||
#include "asm/fstack.h"
|
#include "asm/fstack.h"
|
||||||
#include "asm/lexer.h"
|
#include "asm/lexer.h"
|
||||||
#include "asm/output.h"
|
|
||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
|
#include "asm/opt.h"
|
||||||
|
#include "asm/output.h"
|
||||||
|
#include "asm/rpn.h"
|
||||||
|
#include "asm/symbol.h"
|
||||||
|
#include "asm/warning.h"
|
||||||
|
#include "parser.h"
|
||||||
|
|
||||||
#include "extern/err.h"
|
#include "extern/err.h"
|
||||||
|
#include "extern/getopt.h"
|
||||||
|
|
||||||
#include "helpers.h"
|
#include "helpers.h"
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
|
|
||||||
extern int yyparse(void);
|
// Old Bison versions (confirmed for 2.3) do not forward-declare `yyparse` in the generated header
|
||||||
|
// Unfortunately, macOS still ships 2.3, which is from 2008...
|
||||||
|
int yyparse(void);
|
||||||
|
|
||||||
size_t cldefines_index;
|
#if defined(YYDEBUG) && YYDEBUG
|
||||||
size_t cldefines_numindices;
|
extern int yydebug;
|
||||||
size_t cldefines_bufsize;
|
#endif
|
||||||
const size_t cldefine_entrysize = 2 * sizeof(void *);
|
|
||||||
char **cldefines;
|
|
||||||
|
|
||||||
clock_t nStartClock, nEndClock;
|
FILE * dependfile;
|
||||||
int32_t nLineNo;
|
bool oGeneratedMissingIncludes;
|
||||||
uint32_t nTotalLines, nPass, nPC, nIFDepth, nUnionDepth, nErrors;
|
bool oFailedOnMissingInclude;
|
||||||
bool skipElif;
|
bool oGeneratePhonyDeps;
|
||||||
uint32_t unionStart[128], unionSize[128];
|
char *tzTargetFileName;
|
||||||
|
|
||||||
/* extern int yydebug; */
|
bool haltnop;
|
||||||
|
bool optimizeloads;
|
||||||
|
bool verbose;
|
||||||
|
bool warnings; /* True to enable warnings, false to disable them. */
|
||||||
|
|
||||||
FILE *dependfile;
|
/* Escapes Make-special chars from a string */
|
||||||
|
static char *make_escape(const char *str)
|
||||||
|
{
|
||||||
|
char * const escaped_str = malloc(strlen(str) * 2 + 1);
|
||||||
|
char *dest = escaped_str;
|
||||||
|
|
||||||
|
if (escaped_str == NULL)
|
||||||
|
err(1, "%s: Failed to allocate memory", __func__);
|
||||||
|
|
||||||
|
while (*str) {
|
||||||
|
/* All dollars needs to be doubled */
|
||||||
|
if (*str == '$')
|
||||||
|
*dest++ = '$';
|
||||||
|
*dest++ = *str++;
|
||||||
|
}
|
||||||
|
*dest = '\0';
|
||||||
|
|
||||||
|
return escaped_str;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Short options */
|
||||||
|
static const char *optstring = "b:D:Eg:hi:LM:o:p:r:VvW:w";
|
||||||
|
|
||||||
|
/* Variables for the long-only options */
|
||||||
|
static int depType; /* Variants of `-M` */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Option stack
|
* Equivalent long options
|
||||||
|
* Please keep in the same order as short opts
|
||||||
|
*
|
||||||
|
* Also, make sure long opts don't create ambiguity:
|
||||||
|
* A long opt's name should start with the same letter as its short opt,
|
||||||
|
* except if it doesn't create any ambiguity (`verbose` versus `version`).
|
||||||
|
* This is because long opt matching, even to a single char, is prioritized
|
||||||
|
* over short opt matching
|
||||||
*/
|
*/
|
||||||
|
static struct option const longopts[] = {
|
||||||
struct sOptions DefaultOptions;
|
{ "binary-digits", required_argument, NULL, 'b' },
|
||||||
struct sOptions CurrentOptions;
|
{ "define", required_argument, NULL, 'D' },
|
||||||
|
{ "export-all", no_argument, NULL, 'E' },
|
||||||
struct sOptionStackEntry {
|
{ "gfx-chars", required_argument, NULL, 'g' },
|
||||||
struct sOptions Options;
|
{ "halt-without-nop", no_argument, NULL, 'h' },
|
||||||
struct sOptionStackEntry *pNext;
|
{ "include", required_argument, NULL, 'i' },
|
||||||
|
{ "preserve-ld", no_argument, NULL, 'L' },
|
||||||
|
{ "dependfile", required_argument, NULL, 'M' },
|
||||||
|
{ "MG", no_argument, &depType, 'G' },
|
||||||
|
{ "MP", no_argument, &depType, 'P' },
|
||||||
|
{ "MT", required_argument, &depType, 'T' },
|
||||||
|
{ "MQ", required_argument, &depType, 'Q' },
|
||||||
|
{ "output", required_argument, NULL, 'o' },
|
||||||
|
{ "pad-value", required_argument, NULL, 'p' },
|
||||||
|
{ "recursion-depth", required_argument, NULL, 'r' },
|
||||||
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
{ "verbose", no_argument, NULL, 'v' },
|
||||||
|
{ "warning", required_argument, NULL, 'W' },
|
||||||
|
{ NULL, no_argument, NULL, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sOptionStackEntry *pOptionStack;
|
|
||||||
|
|
||||||
void opt_SetCurrentOptions(struct sOptions *pOpt)
|
|
||||||
{
|
|
||||||
if (nGBGfxID != -1) {
|
|
||||||
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[0],
|
|
||||||
CurrentOptions.gbgfx[0]);
|
|
||||||
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[1],
|
|
||||||
CurrentOptions.gbgfx[1]);
|
|
||||||
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[2],
|
|
||||||
CurrentOptions.gbgfx[2]);
|
|
||||||
lex_FloatDeleteRange(nGBGfxID, CurrentOptions.gbgfx[3],
|
|
||||||
CurrentOptions.gbgfx[3]);
|
|
||||||
lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[0],
|
|
||||||
CurrentOptions.gbgfx[0]);
|
|
||||||
lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[1],
|
|
||||||
CurrentOptions.gbgfx[1]);
|
|
||||||
lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[2],
|
|
||||||
CurrentOptions.gbgfx[2]);
|
|
||||||
lex_FloatDeleteSecondRange(nGBGfxID, CurrentOptions.gbgfx[3],
|
|
||||||
CurrentOptions.gbgfx[3]);
|
|
||||||
}
|
|
||||||
if (nBinaryID != -1) {
|
|
||||||
lex_FloatDeleteRange(nBinaryID, CurrentOptions.binary[0],
|
|
||||||
CurrentOptions.binary[0]);
|
|
||||||
lex_FloatDeleteRange(nBinaryID, CurrentOptions.binary[1],
|
|
||||||
CurrentOptions.binary[1]);
|
|
||||||
lex_FloatDeleteSecondRange(nBinaryID, CurrentOptions.binary[0],
|
|
||||||
CurrentOptions.binary[0]);
|
|
||||||
lex_FloatDeleteSecondRange(nBinaryID, CurrentOptions.binary[1],
|
|
||||||
CurrentOptions.binary[1]);
|
|
||||||
}
|
|
||||||
CurrentOptions = *pOpt;
|
|
||||||
|
|
||||||
if (nGBGfxID != -1) {
|
|
||||||
lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[0],
|
|
||||||
CurrentOptions.gbgfx[0]);
|
|
||||||
lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[1],
|
|
||||||
CurrentOptions.gbgfx[1]);
|
|
||||||
lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[2],
|
|
||||||
CurrentOptions.gbgfx[2]);
|
|
||||||
lex_FloatAddRange(nGBGfxID, CurrentOptions.gbgfx[3],
|
|
||||||
CurrentOptions.gbgfx[3]);
|
|
||||||
lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[0],
|
|
||||||
CurrentOptions.gbgfx[0]);
|
|
||||||
lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[1],
|
|
||||||
CurrentOptions.gbgfx[1]);
|
|
||||||
lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[2],
|
|
||||||
CurrentOptions.gbgfx[2]);
|
|
||||||
lex_FloatAddSecondRange(nGBGfxID, CurrentOptions.gbgfx[3],
|
|
||||||
CurrentOptions.gbgfx[3]);
|
|
||||||
}
|
|
||||||
if (nBinaryID != -1) {
|
|
||||||
lex_FloatAddRange(nBinaryID, CurrentOptions.binary[0],
|
|
||||||
CurrentOptions.binary[0]);
|
|
||||||
lex_FloatAddRange(nBinaryID, CurrentOptions.binary[1],
|
|
||||||
CurrentOptions.binary[1]);
|
|
||||||
lex_FloatAddSecondRange(nBinaryID, CurrentOptions.binary[0],
|
|
||||||
CurrentOptions.binary[0]);
|
|
||||||
lex_FloatAddSecondRange(nBinaryID, CurrentOptions.binary[1],
|
|
||||||
CurrentOptions.binary[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void opt_Parse(char *s)
|
|
||||||
{
|
|
||||||
struct sOptions newopt;
|
|
||||||
|
|
||||||
newopt = CurrentOptions;
|
|
||||||
|
|
||||||
switch (s[0]) {
|
|
||||||
case 'g':
|
|
||||||
if (strlen(&s[1]) == 4) {
|
|
||||||
newopt.gbgfx[0] = s[1];
|
|
||||||
newopt.gbgfx[1] = s[2];
|
|
||||||
newopt.gbgfx[2] = s[3];
|
|
||||||
newopt.gbgfx[3] = s[4];
|
|
||||||
} else {
|
|
||||||
errx(1, "Must specify exactly 4 characters for option 'g'");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'b':
|
|
||||||
if (strlen(&s[1]) == 2) {
|
|
||||||
newopt.binary[0] = s[1];
|
|
||||||
newopt.binary[1] = s[2];
|
|
||||||
} else {
|
|
||||||
errx(1, "Must specify exactly 2 characters for option 'b'");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
if (strlen(&s[1]) <= 2) {
|
|
||||||
int32_t result;
|
|
||||||
unsigned int fillchar;
|
|
||||||
|
|
||||||
result = sscanf(&s[1], "%x", &fillchar);
|
|
||||||
if (!((result == EOF) || (result == 1)))
|
|
||||||
errx(1, "Invalid argument for option 'z'");
|
|
||||||
|
|
||||||
newopt.fillchar = fillchar;
|
|
||||||
} else {
|
|
||||||
errx(1, "Invalid argument for option 'z'");
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
fatalerror("Unknown option");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
opt_SetCurrentOptions(&newopt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void opt_Push(void)
|
|
||||||
{
|
|
||||||
struct sOptionStackEntry *pOpt;
|
|
||||||
|
|
||||||
pOpt = malloc(sizeof(struct sOptionStackEntry));
|
|
||||||
|
|
||||||
if (pOpt == NULL)
|
|
||||||
fatalerror("No memory for option stack");
|
|
||||||
|
|
||||||
pOpt->Options = CurrentOptions;
|
|
||||||
pOpt->pNext = pOptionStack;
|
|
||||||
pOptionStack = pOpt;
|
|
||||||
}
|
|
||||||
|
|
||||||
void opt_Pop(void)
|
|
||||||
{
|
|
||||||
if (pOptionStack == NULL)
|
|
||||||
fatalerror("No entries in the option stack");
|
|
||||||
|
|
||||||
struct sOptionStackEntry *pOpt;
|
|
||||||
|
|
||||||
pOpt = pOptionStack;
|
|
||||||
opt_SetCurrentOptions(&(pOpt->Options));
|
|
||||||
pOptionStack = pOpt->pNext;
|
|
||||||
free(pOpt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void opt_AddDefine(char *s)
|
|
||||||
{
|
|
||||||
char *value, *equals;
|
|
||||||
|
|
||||||
if (cldefines_index >= cldefines_numindices) {
|
|
||||||
/* Check for overflows */
|
|
||||||
if ((cldefines_numindices * 2) < cldefines_numindices)
|
|
||||||
fatalerror("No memory for command line defines");
|
|
||||||
|
|
||||||
if ((cldefines_bufsize * 2) < cldefines_bufsize)
|
|
||||||
fatalerror("No memory for command line defines");
|
|
||||||
|
|
||||||
cldefines_numindices *= 2;
|
|
||||||
cldefines_bufsize *= 2;
|
|
||||||
|
|
||||||
cldefines = realloc(cldefines, cldefines_bufsize);
|
|
||||||
if (!cldefines)
|
|
||||||
fatalerror("No memory for command line defines");
|
|
||||||
}
|
|
||||||
equals = strchr(s, '=');
|
|
||||||
if (equals) {
|
|
||||||
*equals = '\0';
|
|
||||||
value = equals + 1;
|
|
||||||
} else {
|
|
||||||
value = "1";
|
|
||||||
}
|
|
||||||
cldefines[cldefines_index++] = s;
|
|
||||||
cldefines[cldefines_index++] = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void opt_ParseDefines(void)
|
|
||||||
{
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < cldefines_index; i += 2)
|
|
||||||
sym_AddString(cldefines[i], cldefines[i + 1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Error handling
|
|
||||||
*/
|
|
||||||
void verror(const char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
fprintf(stderr, "ERROR: ");
|
|
||||||
fstk_Dump();
|
|
||||||
fprintf(stderr, ":\n ");
|
|
||||||
vfprintf(stderr, fmt, args);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
nErrors += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void yyerror(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
verror(fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
noreturn_ void fatalerror(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
verror(fmt, args);
|
|
||||||
va_end(args);
|
|
||||||
|
|
||||||
exit(5);
|
|
||||||
}
|
|
||||||
|
|
||||||
void warning(const char *fmt, ...)
|
|
||||||
{
|
|
||||||
if (!CurrentOptions.warnings)
|
|
||||||
return;
|
|
||||||
|
|
||||||
va_list args;
|
|
||||||
|
|
||||||
va_start(args, fmt);
|
|
||||||
|
|
||||||
fprintf(stderr, "warning: ");
|
|
||||||
fstk_Dump();
|
|
||||||
fprintf(stderr, ":\n ");
|
|
||||||
vfprintf(stderr, fmt, args);
|
|
||||||
fprintf(stderr, "\n");
|
|
||||||
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void print_usage(void)
|
static void print_usage(void)
|
||||||
{
|
{
|
||||||
printf(
|
fputs(
|
||||||
"usage: rgbasm [-EhLVvw] [-b chars] [-Dname[=value]] [-g chars] [-i path]\n"
|
"Usage: rgbasm [-EhLVvw] [-b chars] [-D name[=value]] [-g chars] [-i path]\n"
|
||||||
" [-M dependfile] [-o outfile] [-p pad_value] file.asm\n");
|
" [-M depend_file] [-MG] [-MP] [-MT target_file] [-MQ target_file]\n"
|
||||||
|
" [-o out_file] [-p pad_value] [-r depth] [-W warning] <file>\n"
|
||||||
|
"Useful options:\n"
|
||||||
|
" -E, --export-all export all labels\n"
|
||||||
|
" -M, --dependfile <path> set the output dependency file\n"
|
||||||
|
" -o, --output <path> set the output object file\n"
|
||||||
|
" -p, --pad-value <value> set the value to use for `ds'\n"
|
||||||
|
" -V, --version print RGBASM version and exit\n"
|
||||||
|
" -W, --warning <warning> enable or disable warnings\n"
|
||||||
|
"\n"
|
||||||
|
"For help, use `man rgbasm' or go to https://rgbds.gbdev.io/docs/\n",
|
||||||
|
stderr);
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -297,200 +137,231 @@ int main(int argc, char *argv[])
|
|||||||
int ch;
|
int ch;
|
||||||
char *ep;
|
char *ep;
|
||||||
|
|
||||||
struct sOptions newopt;
|
time_t now = time(NULL);
|
||||||
|
char const *sourceDateEpoch = getenv("SOURCE_DATE_EPOCH");
|
||||||
|
|
||||||
char *tzMainfile;
|
/*
|
||||||
|
* Support SOURCE_DATE_EPOCH for reproducible builds
|
||||||
|
* https://reproducible-builds.org/docs/source-date-epoch/
|
||||||
|
*/
|
||||||
|
if (sourceDateEpoch)
|
||||||
|
now = (time_t)strtoul(sourceDateEpoch, NULL, 0);
|
||||||
|
|
||||||
dependfile = NULL;
|
dependfile = NULL;
|
||||||
|
|
||||||
/* Initial number of allocated elements in array */
|
#if defined(YYDEBUG) && YYDEBUG
|
||||||
cldefines_numindices = 32;
|
yydebug = 1;
|
||||||
cldefines_bufsize = cldefines_numindices * cldefine_entrysize;
|
#endif
|
||||||
cldefines = malloc(cldefines_bufsize);
|
|
||||||
if (!cldefines)
|
|
||||||
fatalerror("No memory for command line defines");
|
|
||||||
|
|
||||||
if (argc == 1)
|
// Perform some init for below
|
||||||
print_usage();
|
sym_Init(now);
|
||||||
|
|
||||||
/* yydebug=1; */
|
// Set defaults
|
||||||
|
|
||||||
DefaultOptions.gbgfx[0] = '0';
|
oGeneratePhonyDeps = false;
|
||||||
DefaultOptions.gbgfx[1] = '1';
|
oGeneratedMissingIncludes = false;
|
||||||
DefaultOptions.gbgfx[2] = '2';
|
oFailedOnMissingInclude = false;
|
||||||
DefaultOptions.gbgfx[3] = '3';
|
tzTargetFileName = NULL;
|
||||||
DefaultOptions.binary[0] = '0';
|
|
||||||
DefaultOptions.binary[1] = '1';
|
|
||||||
DefaultOptions.exportall = false;
|
|
||||||
DefaultOptions.fillchar = 0;
|
|
||||||
DefaultOptions.optimizeloads = true;
|
|
||||||
DefaultOptions.haltnop = true;
|
|
||||||
DefaultOptions.verbose = false;
|
|
||||||
DefaultOptions.warnings = true;
|
|
||||||
|
|
||||||
opt_SetCurrentOptions(&DefaultOptions);
|
opt_B("01");
|
||||||
|
opt_G("0123");
|
||||||
|
opt_P(0);
|
||||||
|
optimizeloads = true;
|
||||||
|
haltnop = true;
|
||||||
|
verbose = false;
|
||||||
|
warnings = true;
|
||||||
|
sym_SetExportAll(false);
|
||||||
|
uint32_t maxRecursionDepth = 64;
|
||||||
|
size_t nTargetFileNameLen = 0;
|
||||||
|
|
||||||
newopt = CurrentOptions;
|
while ((ch = musl_getopt_long_only(argc, argv, optstring, longopts, NULL)) != -1) {
|
||||||
|
|
||||||
while ((ch = getopt(argc, argv, "b:D:Eg:hi:LM:o:p:Vvw")) != -1) {
|
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'b':
|
case 'b':
|
||||||
if (strlen(optarg) == 2) {
|
if (strlen(musl_optarg) == 2)
|
||||||
newopt.binary[0] = optarg[1];
|
opt_B(&musl_optarg[1]);
|
||||||
newopt.binary[1] = optarg[2];
|
else
|
||||||
} else {
|
|
||||||
errx(1, "Must specify exactly 2 characters for option 'b'");
|
errx(1, "Must specify exactly 2 characters for option 'b'");
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
char *equals;
|
||||||
case 'D':
|
case 'D':
|
||||||
opt_AddDefine(optarg);
|
equals = strchr(musl_optarg, '=');
|
||||||
break;
|
if (equals) {
|
||||||
case 'E':
|
*equals = '\0';
|
||||||
newopt.exportall = true;
|
sym_AddString(musl_optarg, equals + 1);
|
||||||
break;
|
|
||||||
case 'g':
|
|
||||||
if (strlen(optarg) == 4) {
|
|
||||||
newopt.gbgfx[0] = optarg[1];
|
|
||||||
newopt.gbgfx[1] = optarg[2];
|
|
||||||
newopt.gbgfx[2] = optarg[3];
|
|
||||||
newopt.gbgfx[3] = optarg[4];
|
|
||||||
} else {
|
} else {
|
||||||
errx(1, "Must specify exactly 4 characters for option 'g'");
|
sym_AddString(musl_optarg, "1");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
sym_SetExportAll(true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'g':
|
||||||
|
if (strlen(musl_optarg) == 4)
|
||||||
|
opt_G(&musl_optarg[1]);
|
||||||
|
else
|
||||||
|
errx(1, "Must specify exactly 4 characters for option 'g'");
|
||||||
|
break;
|
||||||
|
|
||||||
case 'h':
|
case 'h':
|
||||||
newopt.haltnop = false;
|
haltnop = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'i':
|
case 'i':
|
||||||
fstk_AddIncludePath(optarg);
|
fstk_AddIncludePath(musl_optarg);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
newopt.optimizeloads = false;
|
optimizeloads = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'M':
|
case 'M':
|
||||||
dependfile = fopen(optarg, "w");
|
if (!strcmp("-", musl_optarg))
|
||||||
|
dependfile = stdout;
|
||||||
|
else
|
||||||
|
dependfile = fopen(musl_optarg, "w");
|
||||||
if (dependfile == NULL)
|
if (dependfile == NULL)
|
||||||
err(1, "Could not open dependfile %s", optarg);
|
err(1, "Could not open dependfile %s", musl_optarg);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
out_SetFileName(optarg);
|
out_SetFileName(musl_optarg);
|
||||||
break;
|
break;
|
||||||
case 'p':
|
|
||||||
newopt.fillchar = strtoul(optarg, &ep, 0);
|
|
||||||
|
|
||||||
if (optarg[0] == '\0' || *ep != '\0')
|
unsigned long fill;
|
||||||
|
case 'p':
|
||||||
|
fill = strtoul(musl_optarg, &ep, 0);
|
||||||
|
|
||||||
|
if (musl_optarg[0] == '\0' || *ep != '\0')
|
||||||
errx(1, "Invalid argument for option 'p'");
|
errx(1, "Invalid argument for option 'p'");
|
||||||
|
|
||||||
if (newopt.fillchar < 0 || newopt.fillchar > 0xFF)
|
if (fill < 0 || fill > 0xFF)
|
||||||
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
|
errx(1, "Argument for option 'p' must be between 0 and 0xFF");
|
||||||
|
|
||||||
|
opt_P(fill);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'r':
|
||||||
|
maxRecursionDepth = strtoul(musl_optarg, &ep, 0);
|
||||||
|
|
||||||
|
if (musl_optarg[0] == '\0' || *ep != '\0')
|
||||||
|
errx(1, "Invalid argument for option 'r'");
|
||||||
|
break;
|
||||||
|
|
||||||
case 'V':
|
case 'V':
|
||||||
printf("rgbasm %s\n", get_package_version_string());
|
printf("rgbasm %s\n", get_package_version_string());
|
||||||
exit(0);
|
exit(0);
|
||||||
case 'v':
|
case 'v':
|
||||||
newopt.verbose = true;
|
verbose = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'W':
|
||||||
|
processWarningFlag(musl_optarg);
|
||||||
|
break;
|
||||||
|
|
||||||
case 'w':
|
case 'w':
|
||||||
newopt.warnings = false;
|
warnings = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
/* Long-only options */
|
||||||
|
case 0:
|
||||||
|
switch (depType) {
|
||||||
|
case 'G':
|
||||||
|
oGeneratedMissingIncludes = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'P':
|
||||||
|
oGeneratePhonyDeps = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'Q':
|
||||||
|
case 'T':
|
||||||
|
if (musl_optind == argc)
|
||||||
|
errx(1, "-M%c takes a target file name argument", depType);
|
||||||
|
ep = musl_optarg;
|
||||||
|
if (depType == 'Q')
|
||||||
|
ep = make_escape(ep);
|
||||||
|
|
||||||
|
nTargetFileNameLen += strlen(ep) + 1;
|
||||||
|
if (!tzTargetFileName) {
|
||||||
|
/* On first alloc, make an empty str */
|
||||||
|
tzTargetFileName = malloc(nTargetFileNameLen + 1);
|
||||||
|
if (tzTargetFileName)
|
||||||
|
*tzTargetFileName = '\0';
|
||||||
|
} else {
|
||||||
|
tzTargetFileName = realloc(tzTargetFileName,
|
||||||
|
nTargetFileNameLen + 1);
|
||||||
|
}
|
||||||
|
if (tzTargetFileName == NULL)
|
||||||
|
err(1, "Cannot append new file to target file list");
|
||||||
|
strcat(tzTargetFileName, ep);
|
||||||
|
if (depType == 'Q')
|
||||||
|
free(ep);
|
||||||
|
char *ptr = tzTargetFileName + strlen(tzTargetFileName);
|
||||||
|
|
||||||
|
*ptr++ = ' ';
|
||||||
|
*ptr = '\0';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Unrecognized options */
|
||||||
default:
|
default:
|
||||||
print_usage();
|
print_usage();
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
argc -= optind;
|
|
||||||
argv += optind;
|
|
||||||
|
|
||||||
opt_SetCurrentOptions(&newopt);
|
if (tzTargetFileName == NULL)
|
||||||
|
tzTargetFileName = tzObjectname;
|
||||||
|
|
||||||
DefaultOptions = CurrentOptions;
|
if (argc == musl_optind) {
|
||||||
|
fputs("FATAL: No input files\n", stderr);
|
||||||
if (argc == 0)
|
|
||||||
print_usage();
|
print_usage();
|
||||||
|
} else if (argc != musl_optind + 1) {
|
||||||
|
fputs("FATAL: More than one input file given\n", stderr);
|
||||||
|
print_usage();
|
||||||
|
}
|
||||||
|
|
||||||
tzMainfile = argv[argc - 1];
|
char const *mainFileName = argv[musl_optind];
|
||||||
|
|
||||||
setup_lexer();
|
if (verbose)
|
||||||
|
printf("Assembling %s\n", mainFileName);
|
||||||
if (CurrentOptions.verbose)
|
|
||||||
printf("Assembling %s\n", tzMainfile);
|
|
||||||
|
|
||||||
if (dependfile) {
|
if (dependfile) {
|
||||||
if (!tzObjectname)
|
if (!tzTargetFileName)
|
||||||
errx(1, "Dependency files can only be created if an output object file is specified.\n");
|
errx(1, "Dependency files can only be created if a target file is specified with either -o, -MQ or -MT\n");
|
||||||
|
|
||||||
fprintf(dependfile, "%s: %s\n", tzObjectname, tzMainfile);
|
fprintf(dependfile, "%s: %s\n", tzTargetFileName, mainFileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
nStartClock = clock();
|
charmap_New("main", NULL);
|
||||||
|
|
||||||
nLineNo = 1;
|
// Init lexer and file stack, prodiving file info
|
||||||
nTotalLines = 0;
|
lexer_Init();
|
||||||
nIFDepth = 0;
|
fstk_Init(mainFileName, maxRecursionDepth);
|
||||||
skipElif = true;
|
|
||||||
nUnionDepth = 0;
|
|
||||||
nPC = 0;
|
|
||||||
nPass = 1;
|
|
||||||
nErrors = 0;
|
|
||||||
sym_PrepPass1();
|
|
||||||
sym_SetExportAll(CurrentOptions.exportall);
|
|
||||||
fstk_Init(tzMainfile);
|
|
||||||
opt_ParseDefines();
|
|
||||||
|
|
||||||
if (CurrentOptions.verbose)
|
// Perform parse (yyparse is auto-generated from `parser.y`)
|
||||||
printf("Pass 1...\n");
|
if (yyparse() != 0 && nbErrors == 0)
|
||||||
|
nbErrors = 1;
|
||||||
|
|
||||||
yy_set_state(LEX_STATE_NORMAL);
|
if (dependfile)
|
||||||
opt_SetCurrentOptions(&DefaultOptions);
|
fclose(dependfile);
|
||||||
|
|
||||||
if (yyparse() != 0 || nErrors != 0)
|
sect_CheckUnionClosed();
|
||||||
errx(1, "Assembly aborted in pass 1 (%ld errors)!", nErrors);
|
|
||||||
|
|
||||||
if (nIFDepth != 0)
|
if (nbErrors != 0)
|
||||||
errx(1, "Unterminated IF construct (%ld levels)!", nIFDepth);
|
errx(1, "Assembly aborted (%u error%s)!", nbErrors,
|
||||||
|
nbErrors == 1 ? "" : "s");
|
||||||
|
|
||||||
if (nUnionDepth != 0) {
|
// If parse aborted due to missing an include, and `-MG` was given, exit normally
|
||||||
errx(1, "Unterminated UNION construct (%ld levels)!",
|
if (oFailedOnMissingInclude)
|
||||||
nUnionDepth);
|
return 0;
|
||||||
}
|
|
||||||
|
|
||||||
nTotalLines = 0;
|
/* If no path specified, don't write file */
|
||||||
nLineNo = 1;
|
if (tzObjectname != NULL)
|
||||||
nIFDepth = 0;
|
out_WriteObject();
|
||||||
skipElif = true;
|
|
||||||
nUnionDepth = 0;
|
|
||||||
nPC = 0;
|
|
||||||
nPass = 2;
|
|
||||||
nErrors = 0;
|
|
||||||
sym_PrepPass2();
|
|
||||||
out_PrepPass2();
|
|
||||||
fstk_Init(tzMainfile);
|
|
||||||
yy_set_state(LEX_STATE_NORMAL);
|
|
||||||
opt_SetCurrentOptions(&DefaultOptions);
|
|
||||||
opt_ParseDefines();
|
|
||||||
|
|
||||||
if (CurrentOptions.verbose)
|
|
||||||
printf("Pass 2...\n");
|
|
||||||
|
|
||||||
if (yyparse() != 0 || nErrors != 0)
|
|
||||||
errx(1, "Assembly aborted in pass 2 (%ld errors)!", nErrors);
|
|
||||||
|
|
||||||
double timespent;
|
|
||||||
|
|
||||||
nEndClock = clock();
|
|
||||||
timespent = ((double)(nEndClock - nStartClock))
|
|
||||||
/ (double)CLOCKS_PER_SEC;
|
|
||||||
if (CurrentOptions.verbose) {
|
|
||||||
printf("Success! %u lines in %d.%02d seconds ", nTotalLines,
|
|
||||||
(int)timespent, ((int)(timespent * 100.0)) % 100);
|
|
||||||
if (timespent < FLT_MIN_EXP)
|
|
||||||
printf("(INFINITY lines/minute)\n");
|
|
||||||
else
|
|
||||||
printf("(%d lines/minute)\n",
|
|
||||||
(int)(60 / timespent * nTotalLines));
|
|
||||||
}
|
|
||||||
out_WriteObject();
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
-142
@@ -1,142 +0,0 @@
|
|||||||
/*
|
|
||||||
* This file is part of RGBDS.
|
|
||||||
*
|
|
||||||
* Copyright (c) 1997-2018, Carsten Sorensen and RGBDS contributors.
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: MIT
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Fixedpoint math routines
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <math.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
#include "asm/mymath.h"
|
|
||||||
#include "asm/symbol.h"
|
|
||||||
|
|
||||||
#define fx2double(i) ((double)((i) / 65536.0))
|
|
||||||
#define double2fx(d) ((int32_t)((d) * 65536.0))
|
|
||||||
|
|
||||||
#ifndef M_PI
|
|
||||||
#define M_PI 3.14159265358979323846
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Define the _PI symbol
|
|
||||||
*/
|
|
||||||
void math_DefinePI(void)
|
|
||||||
{
|
|
||||||
sym_AddEqu("_PI", double2fx(M_PI));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Print a fixed point value
|
|
||||||
*/
|
|
||||||
void math_Print(int32_t i)
|
|
||||||
{
|
|
||||||
if (i >= 0)
|
|
||||||
printf("%d.%05d", i >> 16,
|
|
||||||
((int32_t)(fx2double(i) * 100000 + 0.5)) % 100000);
|
|
||||||
else
|
|
||||||
printf("-%d.%05d", (-i) >> 16,
|
|
||||||
((int32_t)(fx2double(-i) * 100000 + 0.5)) % 100000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate sine
|
|
||||||
*/
|
|
||||||
int32_t math_Sin(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(sin(fx2double(i) * 2 * M_PI / 65536));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate cosine
|
|
||||||
*/
|
|
||||||
int32_t math_Cos(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(cos(fx2double(i) * 2 * M_PI / 65536));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate tangent
|
|
||||||
*/
|
|
||||||
int32_t math_Tan(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(tan(fx2double(i) * 2 * M_PI / 65536));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate arcsine
|
|
||||||
*/
|
|
||||||
int32_t math_ASin(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(asin(fx2double(i)) / 2 / M_PI * 65536);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate arccosine
|
|
||||||
*/
|
|
||||||
int32_t math_ACos(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(acos(fx2double(i)) / 2 / M_PI * 65536);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate arctangent
|
|
||||||
*/
|
|
||||||
int32_t math_ATan(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(atan(fx2double(i)) / 2 / M_PI * 65536);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Calculate atan2
|
|
||||||
*/
|
|
||||||
int32_t math_ATan2(int32_t i, int32_t j)
|
|
||||||
{
|
|
||||||
return double2fx(atan2(fx2double(i), fx2double(j)) / 2 / M_PI * 65536);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Multiplication
|
|
||||||
*/
|
|
||||||
int32_t math_Mul(int32_t i, int32_t j)
|
|
||||||
{
|
|
||||||
return double2fx(fx2double(i) * fx2double(j));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Division
|
|
||||||
*/
|
|
||||||
int32_t math_Div(int32_t i, int32_t j)
|
|
||||||
{
|
|
||||||
return double2fx(fx2double(i) / fx2double(j));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Round
|
|
||||||
*/
|
|
||||||
int32_t math_Round(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(round(fx2double(i)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Ceil
|
|
||||||
*/
|
|
||||||
int32_t math_Ceil(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(ceil(fx2double(i)));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Floor
|
|
||||||
*/
|
|
||||||
int32_t math_Floor(int32_t i)
|
|
||||||
{
|
|
||||||
return double2fx(floor(fx2double(i)));
|
|
||||||
}
|
|
||||||
+111
@@ -0,0 +1,111 @@
|
|||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "asm/lexer.h"
|
||||||
|
#include "asm/section.h"
|
||||||
|
#include "asm/warning.h"
|
||||||
|
|
||||||
|
struct OptStackEntry {
|
||||||
|
char binary[2];
|
||||||
|
char gbgfx[4];
|
||||||
|
int32_t fillByte;
|
||||||
|
struct OptStackEntry *next;
|
||||||
|
};
|
||||||
|
|
||||||
|
static struct OptStackEntry *stack = NULL;
|
||||||
|
|
||||||
|
void opt_B(char chars[2])
|
||||||
|
{
|
||||||
|
lexer_SetBinDigits(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
void opt_G(char chars[4])
|
||||||
|
{
|
||||||
|
lexer_SetGfxDigits(chars);
|
||||||
|
}
|
||||||
|
|
||||||
|
void opt_P(uint8_t fill)
|
||||||
|
{
|
||||||
|
fillByte = fill;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opt_Parse(char *s)
|
||||||
|
{
|
||||||
|
switch (s[0]) {
|
||||||
|
case 'b':
|
||||||
|
if (strlen(&s[1]) == 2)
|
||||||
|
opt_B(&s[1]);
|
||||||
|
else
|
||||||
|
error("Must specify exactly 2 characters for option 'b'\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'g':
|
||||||
|
if (strlen(&s[1]) == 4)
|
||||||
|
opt_G(&s[1]);
|
||||||
|
else
|
||||||
|
error("Must specify exactly 4 characters for option 'g'\n");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'p':
|
||||||
|
if (strlen(&s[1]) <= 2) {
|
||||||
|
int result;
|
||||||
|
unsigned int fillchar;
|
||||||
|
|
||||||
|
result = sscanf(&s[1], "%x", &fillchar);
|
||||||
|
if (result != EOF && result != 1)
|
||||||
|
error("Invalid argument for option 'p'\n");
|
||||||
|
else
|
||||||
|
opt_P(fillchar);
|
||||||
|
} else {
|
||||||
|
error("Invalid argument for option 'p'\n");
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
error("Unknown option '%c'\n", s[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void opt_Push(void)
|
||||||
|
{
|
||||||
|
struct OptStackEntry *entry = malloc(sizeof(*entry));
|
||||||
|
|
||||||
|
if (entry == NULL)
|
||||||
|
fatalerror("Failed to alloc option stack entry: %s\n", strerror(errno));
|
||||||
|
|
||||||
|
// Both of these pulled from lexer.h
|
||||||
|
entry->binary[0] = binDigits[0];
|
||||||
|
entry->binary[1] = binDigits[1];
|
||||||
|
|
||||||
|
entry->gbgfx[0] = gfxDigits[0];
|
||||||
|
entry->gbgfx[1] = gfxDigits[1];
|
||||||
|
entry->gbgfx[2] = gfxDigits[2];
|
||||||
|
entry->gbgfx[3] = gfxDigits[3];
|
||||||
|
|
||||||
|
entry->fillByte = fillByte; // Pulled from section.h
|
||||||
|
|
||||||
|
entry->next = stack;
|
||||||
|
stack = entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
void opt_Pop(void)
|
||||||
|
{
|
||||||
|
if (stack == NULL) {
|
||||||
|
error("No entries in the option stack\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OptStackEntry *entry = stack;
|
||||||
|
|
||||||
|
opt_B(entry->binary);
|
||||||
|
opt_G(entry->gbgfx);
|
||||||
|
opt_P(entry->fillByte);
|
||||||
|
stack = entry->next;
|
||||||
|
free(entry);
|
||||||
|
}
|
||||||
+369
-806
File diff suppressed because it is too large
Load Diff
+2223
File diff suppressed because it is too large
Load Diff
+226
-44
@@ -1,95 +1,278 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" This file is part of RGBDS.
|
.\" This file is part of RGBDS.
|
||||||
.\"
|
.\"
|
||||||
.\" Copyright (c) 2010-2018, Anthony J. Bentley and RGBDS contributors.
|
.\" Copyright (c) 2010-2021, Anthony J. Bentley and RGBDS contributors.
|
||||||
.\"
|
.\"
|
||||||
.\" SPDX-License-Identifier: MIT
|
.\" SPDX-License-Identifier: MIT
|
||||||
.\"
|
.\"
|
||||||
.Dd February 24, 2018
|
.Dd March 28, 2021
|
||||||
.Dt RGBASM 1
|
.Dt RGBASM 1
|
||||||
.Os RGBDS Manual
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
.Nm rgbasm
|
.Nm rgbasm
|
||||||
.Nd Game Boy assembler
|
.Nd Game Boy assembler
|
||||||
.Sh SYNOPSIS
|
.Sh SYNOPSIS
|
||||||
.Nm rgbasm
|
.Nm
|
||||||
.Op Fl EhLVvw
|
.Op Fl EhLVvw
|
||||||
.Op Fl b Ar chars
|
.Op Fl b Ar chars
|
||||||
.Op Fl D Ar name Ns Op = Ns Ar value
|
.Op Fl D Ar name Ns Op = Ns Ar value
|
||||||
.Op Fl g Ar chars
|
.Op Fl g Ar chars
|
||||||
.Op Fl i Ar path
|
.Op Fl i Ar path
|
||||||
.Op Fl M Ar dependfile
|
.Op Fl M Ar depend_file
|
||||||
.Op Fl o Ar outfile
|
.Op Fl MG
|
||||||
|
.Op Fl MP
|
||||||
|
.Op Fl MT Ar target_file
|
||||||
|
.Op Fl MQ Ar target_file
|
||||||
|
.Op Fl o Ar out_file
|
||||||
.Op Fl p Ar pad_value
|
.Op Fl p Ar pad_value
|
||||||
.Ar file
|
.Op Fl r Ar recursion_depth
|
||||||
|
.Op Fl W Ar warning
|
||||||
|
.Ar
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Nm
|
.Nm
|
||||||
program creates an object file from an assembly source file.
|
program creates an RGB object file from an assembly source file.
|
||||||
Its arguments are as follows:
|
The input
|
||||||
|
.Ar file
|
||||||
|
can be a file path, or
|
||||||
|
.Cm \-
|
||||||
|
denoting
|
||||||
|
.Cm stdin .
|
||||||
|
.Pp
|
||||||
|
Note that options can be abbreviated as long as the abbreviation is unambiguous:
|
||||||
|
.Fl Fl verb
|
||||||
|
is
|
||||||
|
.Fl Fl verbose ,
|
||||||
|
but
|
||||||
|
.Fl Fl ver
|
||||||
|
is invalid because it could also be
|
||||||
|
.Fl Fl version .
|
||||||
|
The arguments are as follows:
|
||||||
.Bl -tag -width Ds
|
.Bl -tag -width Ds
|
||||||
.It Fl b Ar chars
|
.It Fl b Ar chars , Fl Fl binary-digits Ar chars
|
||||||
Change the two characters used for binary constants.
|
Change the two characters used for binary constants.
|
||||||
The defaults are 01.
|
The defaults are 01.
|
||||||
.It Fl D Ar name Ns Op = Ns Ar value
|
.It Fl D Ar name Ns Oo = Ns Ar value Oc , Fl Fl define Ar name Ns Oo = Ns Ar value Oc
|
||||||
Add string symbol to the compiled source code. This is equivalent to
|
Add a string symbol to the compiled source code.
|
||||||
.Ar name
|
This is equivalent to
|
||||||
.Cm EQUS
|
.Ql Ar name Ic EQUS \(dq Ns Ar value Ns \(dq
|
||||||
.Qq Ar "value"
|
in code, or
|
||||||
in code. If a value is not specified, a value of 1 is given.
|
.Ql Ar name Ic EQUS \(dq1\(dq
|
||||||
.It Fl E
|
if
|
||||||
|
.Ar value
|
||||||
|
is not specified.
|
||||||
|
.It Fl E , Fl Fl export-all
|
||||||
Export all labels, including unreferenced and local labels.
|
Export all labels, including unreferenced and local labels.
|
||||||
.It Fl g Ar chars
|
.It Fl g Ar chars , Fl Fl gfx-chars Ar chars
|
||||||
Change the four characters used for binary constants.
|
Change the four characters used for gfx constants.
|
||||||
The defaults are 0123.
|
The defaults are 0123.
|
||||||
.It Fl h
|
.It Fl h , Fl Fl halt-without-nop
|
||||||
By default,
|
By default,
|
||||||
.Nm
|
.Nm
|
||||||
inserts a
|
inserts a
|
||||||
.Sq nop
|
.Ic nop
|
||||||
instruction immediately after any
|
instruction immediately after any
|
||||||
.Sq halt
|
.Ic halt
|
||||||
instruction.
|
instruction.
|
||||||
The
|
The
|
||||||
.Fl h
|
.Fl h
|
||||||
option disables this behavior.
|
option disables this behavior.
|
||||||
.It Fl i Ar path
|
.It Fl i Ar path , Fl Fl include Ar path
|
||||||
Add an include path.
|
Add an include path.
|
||||||
.It Fl L
|
.It Fl L , Fl Fl preserve-ld
|
||||||
Disable the optimization that turns loads of the form
|
Disable the optimization that turns loads of the form
|
||||||
.Sy LD [$FF00+n8],A
|
.Ic LD [$FF00+n8],A
|
||||||
into the opcode
|
into the opcode
|
||||||
.Sy LDH [$FF00+n8],A
|
.Ic LD [H $FF00+n8],A
|
||||||
in order to have full control of the result in the final ROM.
|
in order to have full control of the result in the final ROM.
|
||||||
.It Fl M Ar dependfile
|
.It Fl M Ar depend_file , Fl Fl dependfile Ar depend_file
|
||||||
Print
|
Print
|
||||||
.Xr make 1
|
.Xr make 1
|
||||||
dependencies to
|
dependencies to
|
||||||
.Ar dependfile .
|
.Ar depend_file .
|
||||||
.It Fl o Ar outfile
|
.It Fl MG
|
||||||
|
To be used in conjunction with
|
||||||
|
.Fl M .
|
||||||
|
This makes
|
||||||
|
.Nm
|
||||||
|
assume that missing files are auto-generated: when
|
||||||
|
.Ic INCLUDE
|
||||||
|
or
|
||||||
|
.Ic INCBIN
|
||||||
|
is attempted on a non-existent file, it is added as a dependency, then
|
||||||
|
.Nm
|
||||||
|
exits normally instead of erroring out.
|
||||||
|
This feature is used in automatic updating of makefiles.
|
||||||
|
.It Fl MP
|
||||||
|
When enabled, this causes a phony target to be added for each dependency other than the main file.
|
||||||
|
This prevents
|
||||||
|
.Xr make 1
|
||||||
|
from erroring out when dependency files are deleted.
|
||||||
|
.It Fl MT Ar target_file
|
||||||
|
Add a target to the rules emitted by
|
||||||
|
.Fl M .
|
||||||
|
The exact string provided will be written, including spaces and special characters.
|
||||||
|
.Dl Fl MT No fileA Fl MT No fileB
|
||||||
|
is equivalent to
|
||||||
|
.Dl Fl MT No 'fileA fileB' .
|
||||||
|
If neither this nor
|
||||||
|
.Fl MQ
|
||||||
|
is specified, the output file name is used.
|
||||||
|
.It Fl MQ Ar target_file
|
||||||
|
Same as
|
||||||
|
.Fl MT ,
|
||||||
|
but additionally escapes any special
|
||||||
|
.Xr make 1
|
||||||
|
characters, essentially
|
||||||
|
.Sq $ .
|
||||||
|
.It Fl o Ar out_file , Fl Fl output Ar out_file
|
||||||
Write an object file to the given filename.
|
Write an object file to the given filename.
|
||||||
.It Fl p Ar pad_value
|
.It Fl p Ar pad_value , Fl Fl pad-value Ar pad_value
|
||||||
When padding an image, pad with this value.
|
When padding an image, pad with this value.
|
||||||
The default is 0x00.
|
The default is 0x00.
|
||||||
.It Fl V
|
.It Fl r Ar recursion_depth , Fl Fl recursion-depth Ar recursion_depth
|
||||||
|
Specifies the recursion depth at which RGBASM will assume being in an infinite loop.
|
||||||
|
.It Fl V , Fl Fl version
|
||||||
Print the version of the program and exit.
|
Print the version of the program and exit.
|
||||||
.It Fl v
|
.It Fl v , Fl Fl verbose
|
||||||
Be verbose.
|
Be verbose.
|
||||||
|
.It Fl W Ar warning , Fl Fl warning Ar warning
|
||||||
|
Set warning flag
|
||||||
|
.Ar warning .
|
||||||
|
A warning message will be printed if
|
||||||
|
.Ar warning
|
||||||
|
is an unknown warning flag.
|
||||||
|
See the
|
||||||
|
.Sx DIAGNOSTICS
|
||||||
|
section for a list of warnings.
|
||||||
.It Fl w
|
.It Fl w
|
||||||
Disable warning output.
|
Disable all warning output, even when turned into errors.
|
||||||
|
.El
|
||||||
|
.Sh DIAGNOSTICS
|
||||||
|
Warnings are diagnostic messages that indicate possibly erroneous behavior that does not necessarily compromise the assembling process.
|
||||||
|
The following options alter the way warnings are processed.
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl Werror
|
||||||
|
Make all warnings into errors.
|
||||||
|
.It Fl Werror=
|
||||||
|
Make the specified warning into an error.
|
||||||
|
A warning's name is appended
|
||||||
|
.Pq example: Fl Werror=obsolete ,
|
||||||
|
and this warning is implicitly enabled and turned into an error.
|
||||||
|
This is an error if used with a meta warning, such as
|
||||||
|
.Fl Werror=all .
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The following warnings are
|
||||||
|
.Dq meta
|
||||||
|
warnings, that enable a collection of other warnings.
|
||||||
|
If a specific warning is toggled via a meta flag and a specific one, the more specific one takes priority.
|
||||||
|
The position on the command-line acts as a tie breaker, the last one taking effect.
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl Wall
|
||||||
|
This enables warnings that are likely to indicate an error or undesired behavior, and that can easily be fixed.
|
||||||
|
.It Fl Wextra
|
||||||
|
This enables extra warnings that are less likely to pose a problem, but that may still be wanted.
|
||||||
|
.It Fl Weverything
|
||||||
|
Enables literally every warning.
|
||||||
|
.El
|
||||||
|
.Pp
|
||||||
|
The following warnings are actual warning flags; with each description, the corresponding warning flag is included.
|
||||||
|
Note that each of these flag also has a negation (for example,
|
||||||
|
.Fl Wcharmap-redef
|
||||||
|
enables the warning that
|
||||||
|
.Fl Wno-charmap-redef
|
||||||
|
disables).
|
||||||
|
Only the non-default flag is listed here.
|
||||||
|
Ignoring the
|
||||||
|
.Dq no-
|
||||||
|
prefix, entries are listed alphabetically.
|
||||||
|
.Bl -tag -width Ds
|
||||||
|
.It Fl Wno-assert
|
||||||
|
Warns when
|
||||||
|
.Ic WARN Ns No -type
|
||||||
|
assertions fail. (See
|
||||||
|
.Dq Aborting the assembly process
|
||||||
|
in
|
||||||
|
.Xr rgbasm 5
|
||||||
|
for
|
||||||
|
.Ic ASSERT ) .
|
||||||
|
.It Fl Wbuiltin-args
|
||||||
|
Warn about incorrect arguments to built-in functions, such as
|
||||||
|
.Fn STRSUB
|
||||||
|
with indexes outside of the string's bounds.
|
||||||
|
This warning is enabled by
|
||||||
|
.Fl Wall .
|
||||||
|
.It Fl Wcharmap-redef
|
||||||
|
Warn when re-defining a charmap mapping.
|
||||||
|
This warning is enabled by
|
||||||
|
.Fl Wall .
|
||||||
|
.It Fl Wdiv
|
||||||
|
Warn when dividing the smallest negative integer by -1, which yields itself due to integer overflow.
|
||||||
|
.It Fl Wempty-macro-arg
|
||||||
|
Warn when a macro argument is empty.
|
||||||
|
This warning is enabled by
|
||||||
|
.Fl Wextra .
|
||||||
|
.It Fl Wempty-strrpl
|
||||||
|
Warn when
|
||||||
|
.Fn STRRPL
|
||||||
|
is called with an empty string as its second argument (the substring to replace).
|
||||||
|
This warning is enabled by
|
||||||
|
.Fl Wall .
|
||||||
|
.It Fl Wlarge-constant
|
||||||
|
Warn when a constant too large to fit in a signed 32-bit integer is encountered.
|
||||||
|
This warning is enabled by
|
||||||
|
.Fl Wall .
|
||||||
|
.It Fl Wlong-string
|
||||||
|
Warn when a string too long to fit in internal buffers is encountered.
|
||||||
|
This warning is enabled by
|
||||||
|
.Fl Wall .
|
||||||
|
.It Fl Wmacro-shift
|
||||||
|
Warn when shifting macro arguments past their limits.
|
||||||
|
This warning is enabled by
|
||||||
|
.Fl Wextra .
|
||||||
|
.It Fl Wno-obsolete
|
||||||
|
Warn when obsolete constructs such as the
|
||||||
|
.Ic _PI
|
||||||
|
constant or
|
||||||
|
.Ic PRINTT
|
||||||
|
directive are encountered.
|
||||||
|
.It Fl Wshift
|
||||||
|
Warn when shifting right a negative value.
|
||||||
|
Use a division by 2^N instead.
|
||||||
|
.It Fl Wshift-amount
|
||||||
|
Warn when a shift's operand is negative or greater than 32.
|
||||||
|
.It Fl Wno-truncation
|
||||||
|
Warn when an implicit truncation (for example,
|
||||||
|
.Ic LD [B @] )
|
||||||
|
loses some bits.
|
||||||
|
.It Fl Wno-user
|
||||||
|
Warn when the
|
||||||
|
.Ic WARN
|
||||||
|
built-in is executed. (See
|
||||||
|
.Dq Aborting the assembly process
|
||||||
|
in
|
||||||
|
.Xr rgbasm 5
|
||||||
|
for
|
||||||
|
.Ic WARN ) .
|
||||||
.El
|
.El
|
||||||
.Sh EXAMPLES
|
.Sh EXAMPLES
|
||||||
Assembling a basic source file is simple:
|
You can assemble a source file in two ways.
|
||||||
.Pp
|
.Pp
|
||||||
.Bd -literal -offset indent
|
Straightforward way:
|
||||||
$ rgbasm -o bar.o foo.asm
|
.Dl $ rgbasm -o bar.o foo.asm
|
||||||
.Ed
|
|
||||||
.Pp
|
.Pp
|
||||||
The resulting object file is not yet a usable ROM image \(em it must first be
|
Pipes way:
|
||||||
run through
|
.Dl $ cat foo.asm | rgbasm -o bar.o -
|
||||||
|
.Dl $ rgbasm -o bar.o - < foo.asm
|
||||||
|
.Pp
|
||||||
|
The resulting object file is not yet a usable ROM image\(emit must first be run through
|
||||||
.Xr rgblink 1
|
.Xr rgblink 1
|
||||||
and
|
and then
|
||||||
.Xr rgbfix 1 .
|
.Xr rgbfix 1 .
|
||||||
|
.Sh BUGS
|
||||||
|
Please report bugs on
|
||||||
|
.Lk https://github.com/gbdev/rgbds/issues GitHub .
|
||||||
.Sh SEE ALSO
|
.Sh SEE ALSO
|
||||||
.Xr rgbasm 5 ,
|
.Xr rgbasm 5 ,
|
||||||
.Xr rgbfix 1 ,
|
.Xr rgbfix 1 ,
|
||||||
@@ -99,7 +282,6 @@ and
|
|||||||
.Xr gbz80 7
|
.Xr gbz80 7
|
||||||
.Sh HISTORY
|
.Sh HISTORY
|
||||||
.Nm
|
.Nm
|
||||||
was originally written by Carsten S\(/orensen as part of the ASMotor package,
|
was originally written by Carsten S\(/orensen as part of the ASMotor package, and was later packaged in RGBDS by Justin Lloyd.
|
||||||
and was later packaged in RGBDS by Justin Lloyd. It is now maintained by a
|
It is now maintained by a number of contributors at
|
||||||
number of contributors at
|
.Lk https://github.com/gbdev/rgbds .
|
||||||
.Lk https://github.com/rednex/rgbds .
|
|
||||||
|
|||||||
+1675
-948
File diff suppressed because it is too large
Load Diff
+411
-285
@@ -10,74 +10,92 @@
|
|||||||
* Controls RPN expressions for objectfiles
|
* Controls RPN expressions for objectfiles
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <inttypes.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "asm/asm.h"
|
|
||||||
#include "asm/main.h"
|
#include "asm/main.h"
|
||||||
|
#include "asm/output.h"
|
||||||
#include "asm/rpn.h"
|
#include "asm/rpn.h"
|
||||||
|
#include "asm/section.h"
|
||||||
#include "asm/symbol.h"
|
#include "asm/symbol.h"
|
||||||
|
#include "asm/warning.h"
|
||||||
|
|
||||||
#include "linkdefs.h"
|
#include "opmath.h"
|
||||||
|
|
||||||
void mergetwoexpressions(struct Expression *expr, const struct Expression *src1,
|
/* Makes an expression "not known", also setting its error message */
|
||||||
const struct Expression *src2)
|
#define makeUnknown(expr_, ...) do { \
|
||||||
|
struct Expression *_expr = expr_; \
|
||||||
|
_expr->isKnown = false; \
|
||||||
|
/* If we had `asprintf` this would be great, but alas. */ \
|
||||||
|
_expr->reason = malloc(128); /* Use an initial reasonable size */ \
|
||||||
|
if (!_expr->reason) \
|
||||||
|
fatalerror("Can't allocate err string: %s\n", strerror(errno)); \
|
||||||
|
int size = snprintf(_expr->reason, 128, __VA_ARGS__); \
|
||||||
|
if (size >= 128) { /* If this wasn't enough, try again */ \
|
||||||
|
_expr->reason = realloc(_expr->reason, size + 1); \
|
||||||
|
sprintf(_expr->reason, __VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
static uint8_t *reserveSpace(struct Expression *expr, uint32_t size)
|
||||||
{
|
{
|
||||||
*expr = *src1;
|
/* This assumes the RPN length is always less than the capacity */
|
||||||
memcpy(&(expr->tRPN[expr->nRPNLength]), src2->tRPN, src2->nRPNLength);
|
if (expr->nRPNCapacity - expr->nRPNLength < size) {
|
||||||
|
/* If there isn't enough room to reserve the space, realloc */
|
||||||
|
if (!expr->tRPN)
|
||||||
|
expr->nRPNCapacity = 256; /* Initial size */
|
||||||
|
while (expr->nRPNCapacity - expr->nRPNLength < size) {
|
||||||
|
if (expr->nRPNCapacity >= MAXRPNLEN)
|
||||||
|
/*
|
||||||
|
* To avoid generating humongous object files, cap the
|
||||||
|
* size of RPN expressions
|
||||||
|
*/
|
||||||
|
fatalerror("RPN expression cannot grow larger than "
|
||||||
|
EXPAND_AND_STR(MAXRPNLEN) " bytes\n");
|
||||||
|
else if (expr->nRPNCapacity > MAXRPNLEN / 2)
|
||||||
|
expr->nRPNCapacity = MAXRPNLEN;
|
||||||
|
else
|
||||||
|
expr->nRPNCapacity *= 2;
|
||||||
|
}
|
||||||
|
expr->tRPN = realloc(expr->tRPN, expr->nRPNCapacity);
|
||||||
|
|
||||||
expr->nRPNLength += src2->nRPNLength;
|
if (!expr->tRPN)
|
||||||
expr->isReloc |= src2->isReloc;
|
fatalerror("Failed to grow RPN expression: %s\n", strerror(errno));
|
||||||
expr->isPCRel |= src2->isPCRel;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#define joinexpr() mergetwoexpressions(expr, src1, src2)
|
uint8_t *ptr = expr->tRPN + expr->nRPNLength;
|
||||||
|
|
||||||
/*
|
expr->nRPNLength += size;
|
||||||
* Add a byte to the RPN expression
|
return ptr;
|
||||||
*/
|
|
||||||
void pushbyte(struct Expression *expr, int b)
|
|
||||||
{
|
|
||||||
expr->tRPN[expr->nRPNLength++] = b & 0xFF;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Reset the RPN module
|
* Init the RPN expression
|
||||||
*/
|
*/
|
||||||
void rpn_Reset(struct Expression *expr)
|
static void rpn_Init(struct Expression *expr)
|
||||||
{
|
{
|
||||||
|
expr->reason = NULL;
|
||||||
|
expr->isKnown = true;
|
||||||
|
expr->isSymbol = false;
|
||||||
|
expr->tRPN = NULL;
|
||||||
|
expr->nRPNCapacity = 0;
|
||||||
expr->nRPNLength = 0;
|
expr->nRPNLength = 0;
|
||||||
expr->nRPNOut = 0;
|
expr->nRPNPatchSize = 0;
|
||||||
expr->isReloc = 0;
|
|
||||||
expr->isPCRel = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Returns the next rpn byte in expression
|
* Free the RPN expression
|
||||||
*/
|
*/
|
||||||
uint16_t rpn_PopByte(struct Expression *expr)
|
void rpn_Free(struct Expression *expr)
|
||||||
{
|
{
|
||||||
if (expr->nRPNOut == expr->nRPNLength)
|
free(expr->tRPN);
|
||||||
return 0xDEAD;
|
free(expr->reason);
|
||||||
|
rpn_Init(expr);
|
||||||
return expr->tRPN[expr->nRPNOut++];
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine if the current expression is relocatable
|
|
||||||
*/
|
|
||||||
uint32_t rpn_isReloc(const struct Expression *expr)
|
|
||||||
{
|
|
||||||
return expr->isReloc;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine if the current expression can be pc-relative
|
|
||||||
*/
|
|
||||||
uint32_t rpn_isPCRelative(const struct Expression *expr)
|
|
||||||
{
|
|
||||||
return expr->isPCRel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -85,32 +103,30 @@ uint32_t rpn_isPCRelative(const struct Expression *expr)
|
|||||||
*/
|
*/
|
||||||
void rpn_Number(struct Expression *expr, uint32_t i)
|
void rpn_Number(struct Expression *expr, uint32_t i)
|
||||||
{
|
{
|
||||||
rpn_Reset(expr);
|
rpn_Init(expr);
|
||||||
pushbyte(expr, RPN_CONST);
|
|
||||||
pushbyte(expr, i);
|
|
||||||
pushbyte(expr, i >> 8);
|
|
||||||
pushbyte(expr, i >> 16);
|
|
||||||
pushbyte(expr, i >> 24);
|
|
||||||
expr->nVal = i;
|
expr->nVal = i;
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_Symbol(struct Expression *expr, char *tzSym)
|
void rpn_Symbol(struct Expression *expr, char const *tzSym)
|
||||||
{
|
{
|
||||||
if (!sym_isConstant(tzSym)) {
|
struct Symbol *sym = sym_FindScopedSymbol(tzSym);
|
||||||
const struct sSymbol *psym;
|
|
||||||
|
|
||||||
rpn_Reset(expr);
|
if (sym_IsPC(sym) && !sect_GetSymbolSection()) {
|
||||||
|
error("PC has no value outside a section\n");
|
||||||
|
rpn_Number(expr, 0);
|
||||||
|
} else if (!sym || !sym_IsConstant(sym)) {
|
||||||
|
rpn_Init(expr);
|
||||||
|
expr->isSymbol = true;
|
||||||
|
|
||||||
psym = sym_FindSymbol(tzSym);
|
makeUnknown(expr, sym_IsPC(sym) ? "PC is not constant at assembly time"
|
||||||
|
: "'%s' is not constant at assembly time", tzSym);
|
||||||
|
sym = sym_Ref(tzSym);
|
||||||
|
expr->nRPNPatchSize += 5; /* 1-byte opcode + 4-byte symbol ID */
|
||||||
|
|
||||||
if (psym == NULL || psym->pSection == pCurrentSection
|
size_t nameLen = strlen(sym->name) + 1; /* Don't forget NUL! */
|
||||||
|| psym->pSection == NULL)
|
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||||
expr->isPCRel = 1;
|
*ptr++ = RPN_SYM;
|
||||||
expr->isReloc = 1;
|
memcpy(ptr, sym->name, nameLen);
|
||||||
pushbyte(expr, RPN_SYM);
|
|
||||||
while (*tzSym)
|
|
||||||
pushbyte(expr, *tzSym++);
|
|
||||||
pushbyte(expr, 0);
|
|
||||||
} else {
|
} else {
|
||||||
rpn_Number(expr, sym_GetConstantValue(tzSym));
|
rpn_Number(expr, sym_GetConstantValue(tzSym));
|
||||||
}
|
}
|
||||||
@@ -118,284 +134,394 @@ void rpn_Symbol(struct Expression *expr, char *tzSym)
|
|||||||
|
|
||||||
void rpn_BankSelf(struct Expression *expr)
|
void rpn_BankSelf(struct Expression *expr)
|
||||||
{
|
{
|
||||||
rpn_Reset(expr);
|
rpn_Init(expr);
|
||||||
|
|
||||||
/*
|
if (!pCurrentSection) {
|
||||||
* This symbol is not really relocatable, but this makes the assembler
|
error("PC has no bank outside a section\n");
|
||||||
* write this expression as a RPN patch to the object file.
|
expr->nVal = 1;
|
||||||
*/
|
} else if (pCurrentSection->bank == (uint32_t)-1) {
|
||||||
expr->isReloc = 1;
|
makeUnknown(expr, "Current section's bank is not known");
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
pushbyte(expr, RPN_BANK_SELF);
|
*reserveSpace(expr, 1) = RPN_BANK_SELF;
|
||||||
|
} else {
|
||||||
|
expr->nVal = pCurrentSection->bank;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_BankSymbol(struct Expression *expr, char *tzSym)
|
void rpn_BankSymbol(struct Expression *expr, char const *tzSym)
|
||||||
{
|
{
|
||||||
|
struct Symbol const *sym = sym_FindScopedSymbol(tzSym);
|
||||||
|
|
||||||
/* The @ symbol is treated differently. */
|
/* The @ symbol is treated differently. */
|
||||||
if (sym_FindSymbol(tzSym) == pPCSymbol) {
|
if (sym_IsPC(sym)) {
|
||||||
rpn_BankSelf(expr);
|
rpn_BankSelf(expr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!sym_isConstant(tzSym)) {
|
rpn_Init(expr);
|
||||||
rpn_Reset(expr);
|
if (sym && !sym_IsLabel(sym)) {
|
||||||
|
error("BANK argument must be a label\n");
|
||||||
/*
|
|
||||||
* Check that the symbol exists by evaluating and discarding the
|
|
||||||
* value.
|
|
||||||
*/
|
|
||||||
sym_GetValue(tzSym);
|
|
||||||
|
|
||||||
expr->isReloc = 1;
|
|
||||||
pushbyte(expr, RPN_BANK_SYM);
|
|
||||||
while (*tzSym)
|
|
||||||
pushbyte(expr, *tzSym++);
|
|
||||||
pushbyte(expr, 0);
|
|
||||||
} else {
|
} else {
|
||||||
yyerror("BANK argument must be a relocatable identifier");
|
sym = sym_Ref(tzSym);
|
||||||
|
assert(sym); // If the symbol didn't exist, it should have been created
|
||||||
|
|
||||||
|
if (sym_GetSection(sym) && sym_GetSection(sym)->bank != (uint32_t)-1) {
|
||||||
|
/* Symbol's section is known and bank is fixed */
|
||||||
|
expr->nVal = sym_GetSection(sym)->bank;
|
||||||
|
} else {
|
||||||
|
makeUnknown(expr, "\"%s\"'s bank is not known", tzSym);
|
||||||
|
expr->nRPNPatchSize += 5; /* opcode + 4-byte sect ID */
|
||||||
|
|
||||||
|
size_t nameLen = strlen(sym->name) + 1; /* Room for NUL! */
|
||||||
|
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||||
|
*ptr++ = RPN_BANK_SYM;
|
||||||
|
memcpy(ptr, sym->name, nameLen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_BankSection(struct Expression *expr, char *tzSectionName)
|
void rpn_BankSection(struct Expression *expr, char const *tzSectionName)
|
||||||
{
|
{
|
||||||
rpn_Reset(expr);
|
rpn_Init(expr);
|
||||||
|
|
||||||
/*
|
struct Section *pSection = out_FindSectionByName(tzSectionName);
|
||||||
* This symbol is not really relocatable, but this makes the assembler
|
|
||||||
* write this expression as a RPN patch to the object file.
|
|
||||||
*/
|
|
||||||
expr->isReloc = 1;
|
|
||||||
|
|
||||||
pushbyte(expr, RPN_BANK_SECT);
|
if (pSection && pSection->bank != (uint32_t)-1) {
|
||||||
while (*tzSectionName)
|
expr->nVal = pSection->bank;
|
||||||
pushbyte(expr, *tzSectionName++);
|
} else {
|
||||||
pushbyte(expr, 0);
|
makeUnknown(expr, "Section \"%s\"'s bank is not known",
|
||||||
|
tzSectionName);
|
||||||
|
|
||||||
|
size_t nameLen = strlen(tzSectionName) + 1; /* Room for NUL! */
|
||||||
|
uint8_t *ptr = reserveSpace(expr, nameLen + 1);
|
||||||
|
|
||||||
|
expr->nRPNPatchSize += nameLen + 1;
|
||||||
|
*ptr++ = RPN_BANK_SECT;
|
||||||
|
memcpy(ptr, tzSectionName, nameLen);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
void rpn_CheckHRAM(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
pushbyte(expr, RPN_HRAM);
|
expr->isSymbol = false;
|
||||||
|
|
||||||
|
if (!rpn_isKnown(expr)) {
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
*reserveSpace(expr, 1) = RPN_HRAM;
|
||||||
|
} else if (expr->nVal >= 0xFF00 && expr->nVal <= 0xFFFF) {
|
||||||
|
/* That range is valid, but only keep the lower byte */
|
||||||
|
expr->nVal &= 0xFF;
|
||||||
|
} else if (expr->nVal < 0 || expr->nVal > 0xFF) {
|
||||||
|
error("Source address $%" PRIx32 " not between $FF00 to $FFFF\n", expr->nVal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_CheckRST(struct Expression *expr, const struct Expression *src)
|
||||||
|
{
|
||||||
|
*expr = *src;
|
||||||
|
|
||||||
|
if (rpn_isKnown(expr)) {
|
||||||
|
/* A valid RST address must be masked with 0x38 */
|
||||||
|
if (expr->nVal & ~0x38)
|
||||||
|
error("Invalid address $%" PRIx32 " for RST\n", expr->nVal);
|
||||||
|
/* The target is in the "0x38" bits, all other bits are set */
|
||||||
|
expr->nVal |= 0xC7;
|
||||||
|
} else {
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
*reserveSpace(expr, 1) = RPN_RST;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
|
void rpn_LOGNOT(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
pushbyte(expr, RPN_LOGUNNOT);
|
expr->isSymbol = false;
|
||||||
|
|
||||||
|
if (rpn_isKnown(expr)) {
|
||||||
|
expr->nVal = !expr->nVal;
|
||||||
|
} else {
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
*reserveSpace(expr, 1) = RPN_LOGUNNOT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGOR(struct Expression *expr, const struct Expression *src1,
|
struct Symbol const *rpn_SymbolOf(struct Expression const *expr)
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
{
|
||||||
joinexpr();
|
if (!rpn_isSymbol(expr))
|
||||||
expr->nVal = (expr->nVal || src2->nVal);
|
return NULL;
|
||||||
pushbyte(expr, RPN_LOGOR);
|
return sym_FindScopedSymbol((char *)expr->tRPN + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGAND(struct Expression *expr, const struct Expression *src1,
|
bool rpn_IsDiffConstant(struct Expression const *src, struct Symbol const *sym)
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
{
|
||||||
joinexpr();
|
/* Check if both expressions only refer to a single symbol */
|
||||||
expr->nVal = (expr->nVal && src2->nVal);
|
struct Symbol const *sym1 = rpn_SymbolOf(src);
|
||||||
pushbyte(expr, RPN_LOGAND);
|
|
||||||
|
if (!sym1 || !sym || sym1->type != SYM_LABEL || sym->type != SYM_LABEL)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
struct Section const *section1 = sym_GetSection(sym1);
|
||||||
|
struct Section const *section2 = sym_GetSection(sym);
|
||||||
|
return section1 && (section1 == section2);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool isDiffConstant(struct Expression const *src1,
|
||||||
|
struct Expression const *src2)
|
||||||
|
{
|
||||||
|
return rpn_IsDiffConstant(src1, rpn_SymbolOf(src2));
|
||||||
|
}
|
||||||
|
|
||||||
|
void rpn_BinaryOp(enum RPNCommand op, struct Expression *expr,
|
||||||
|
const struct Expression *src1, const struct Expression *src2)
|
||||||
|
{
|
||||||
|
expr->isSymbol = false;
|
||||||
|
|
||||||
|
/* First, check if the expression is known */
|
||||||
|
expr->isKnown = src1->isKnown && src2->isKnown;
|
||||||
|
if (expr->isKnown) {
|
||||||
|
rpn_Init(expr); /* Init the expression to something sane */
|
||||||
|
|
||||||
|
/* If both expressions are known, just compute the value */
|
||||||
|
uint32_t uleft = src1->nVal, uright = src2->nVal;
|
||||||
|
|
||||||
|
switch (op) {
|
||||||
|
case RPN_LOGOR:
|
||||||
|
expr->nVal = src1->nVal || src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_LOGAND:
|
||||||
|
expr->nVal = src1->nVal && src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_LOGEQ:
|
||||||
|
expr->nVal = src1->nVal == src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_LOGGT:
|
||||||
|
expr->nVal = src1->nVal > src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_LOGLT:
|
||||||
|
expr->nVal = src1->nVal < src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_LOGGE:
|
||||||
|
expr->nVal = src1->nVal >= src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_LOGLE:
|
||||||
|
expr->nVal = src1->nVal <= src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_LOGNE:
|
||||||
|
expr->nVal = src1->nVal != src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_ADD:
|
||||||
|
expr->nVal = uleft + uright;
|
||||||
|
break;
|
||||||
|
case RPN_SUB:
|
||||||
|
expr->nVal = uleft - uright;
|
||||||
|
break;
|
||||||
|
case RPN_XOR:
|
||||||
|
expr->nVal = src1->nVal ^ src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_OR:
|
||||||
|
expr->nVal = src1->nVal | src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_AND:
|
||||||
|
expr->nVal = src1->nVal & src2->nVal;
|
||||||
|
break;
|
||||||
|
case RPN_SHL:
|
||||||
|
if (src2->nVal < 0)
|
||||||
|
warning(WARNING_SHIFT_AMOUNT,
|
||||||
|
"Shifting left by negative amount %" PRId32 "\n",
|
||||||
|
src2->nVal);
|
||||||
|
|
||||||
|
if (src2->nVal >= 32)
|
||||||
|
warning(WARNING_SHIFT_AMOUNT,
|
||||||
|
"Shifting left by large amount %" PRId32 "\n",
|
||||||
|
src2->nVal);
|
||||||
|
|
||||||
|
expr->nVal = op_shift_left(src1->nVal, src2->nVal);
|
||||||
|
break;
|
||||||
|
case RPN_SHR:
|
||||||
|
if (src1->nVal < 0)
|
||||||
|
warning(WARNING_SHIFT, "Shifting right negative value %"
|
||||||
|
PRId32 "\n",
|
||||||
|
src1->nVal);
|
||||||
|
|
||||||
|
if (src2->nVal < 0)
|
||||||
|
warning(WARNING_SHIFT_AMOUNT,
|
||||||
|
"Shifting right by negative amount %" PRId32 "\n",
|
||||||
|
src2->nVal);
|
||||||
|
|
||||||
|
if (src2->nVal >= 32)
|
||||||
|
warning(WARNING_SHIFT_AMOUNT,
|
||||||
|
"Shifting right by large amount %" PRId32 "\n",
|
||||||
|
src2->nVal);
|
||||||
|
|
||||||
|
expr->nVal = op_shift_right(src1->nVal, src2->nVal);
|
||||||
|
break;
|
||||||
|
case RPN_MUL:
|
||||||
|
expr->nVal = uleft * uright;
|
||||||
|
break;
|
||||||
|
case RPN_DIV:
|
||||||
|
if (src2->nVal == 0)
|
||||||
|
fatalerror("Division by zero\n");
|
||||||
|
|
||||||
|
if (src1->nVal == INT32_MIN && src2->nVal == -1) {
|
||||||
|
warning(WARNING_DIV, "Division of %" PRId32 " by -1 yields %"
|
||||||
|
PRId32 "\n", INT32_MIN, INT32_MIN);
|
||||||
|
expr->nVal = INT32_MIN;
|
||||||
|
} else {
|
||||||
|
expr->nVal = op_divide(src1->nVal, src2->nVal);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RPN_MOD:
|
||||||
|
if (src2->nVal == 0)
|
||||||
|
fatalerror("Modulo by zero\n");
|
||||||
|
|
||||||
|
if (src1->nVal == INT32_MIN && src2->nVal == -1)
|
||||||
|
expr->nVal = 0;
|
||||||
|
else
|
||||||
|
expr->nVal = op_modulo(src1->nVal, src2->nVal);
|
||||||
|
break;
|
||||||
|
case RPN_EXP:
|
||||||
|
if (src2->nVal < 0)
|
||||||
|
fatalerror("Exponentiation by negative power\n");
|
||||||
|
|
||||||
|
if (src1->nVal == INT32_MIN && src2->nVal == -1)
|
||||||
|
expr->nVal = 0;
|
||||||
|
else
|
||||||
|
expr->nVal = op_exponent(src1->nVal, src2->nVal);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case RPN_UNSUB:
|
||||||
|
case RPN_UNNOT:
|
||||||
|
case RPN_LOGUNNOT:
|
||||||
|
case RPN_BANK_SYM:
|
||||||
|
case RPN_BANK_SECT:
|
||||||
|
case RPN_BANK_SELF:
|
||||||
|
case RPN_HRAM:
|
||||||
|
case RPN_RST:
|
||||||
|
case RPN_CONST:
|
||||||
|
case RPN_SYM:
|
||||||
|
fatalerror("%d is not a binary operator\n", op);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (op == RPN_SUB && isDiffConstant(src1, src2)) {
|
||||||
|
struct Symbol const *symbol1 = rpn_SymbolOf(src1);
|
||||||
|
struct Symbol const *symbol2 = rpn_SymbolOf(src2);
|
||||||
|
|
||||||
|
expr->nVal = sym_GetValue(symbol1) - sym_GetValue(symbol2);
|
||||||
|
expr->isKnown = true;
|
||||||
|
} else {
|
||||||
|
/* If it's not known, start computing the RPN expression */
|
||||||
|
|
||||||
|
/* Convert the left-hand expression if it's constant */
|
||||||
|
if (src1->isKnown) {
|
||||||
|
uint32_t lval = src1->nVal;
|
||||||
|
uint8_t bytes[] = {RPN_CONST, lval, lval >> 8,
|
||||||
|
lval >> 16, lval >> 24};
|
||||||
|
expr->nRPNPatchSize = sizeof(bytes);
|
||||||
|
expr->tRPN = NULL;
|
||||||
|
expr->nRPNCapacity = 0;
|
||||||
|
expr->nRPNLength = 0;
|
||||||
|
memcpy(reserveSpace(expr, sizeof(bytes)), bytes,
|
||||||
|
sizeof(bytes));
|
||||||
|
|
||||||
|
/* Use the other expression's un-const reason */
|
||||||
|
expr->reason = src2->reason;
|
||||||
|
free(src1->reason);
|
||||||
|
} else {
|
||||||
|
/* Otherwise just reuse its RPN buffer */
|
||||||
|
expr->nRPNPatchSize = src1->nRPNPatchSize;
|
||||||
|
expr->tRPN = src1->tRPN;
|
||||||
|
expr->nRPNCapacity = src1->nRPNCapacity;
|
||||||
|
expr->nRPNLength = src1->nRPNLength;
|
||||||
|
expr->reason = src1->reason;
|
||||||
|
free(src2->reason);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now, merge the right expression into the left one */
|
||||||
|
uint8_t *ptr = src2->tRPN; /* Pointer to the right RPN */
|
||||||
|
uint32_t len = src2->nRPNLength; /* Size of the right RPN */
|
||||||
|
uint32_t patchSize = src2->nRPNPatchSize;
|
||||||
|
|
||||||
|
/* If the right expression is constant, merge a shim instead */
|
||||||
|
uint32_t rval = src2->nVal;
|
||||||
|
uint8_t bytes[] = {RPN_CONST, rval, rval >> 8, rval >> 16,
|
||||||
|
rval >> 24};
|
||||||
|
if (src2->isKnown) {
|
||||||
|
ptr = bytes;
|
||||||
|
len = sizeof(bytes);
|
||||||
|
patchSize = sizeof(bytes);
|
||||||
|
}
|
||||||
|
/* Copy the right RPN and append the operator */
|
||||||
|
uint8_t *buf = reserveSpace(expr, len + 1);
|
||||||
|
|
||||||
|
memcpy(buf, ptr, len);
|
||||||
|
buf[len] = op;
|
||||||
|
|
||||||
|
free(src2->tRPN); /* If there was none, this is `free(NULL)` */
|
||||||
|
expr->nRPNPatchSize += patchSize + 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
void rpn_HIGH(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
|
expr->isSymbol = false;
|
||||||
|
|
||||||
expr->nVal = (expr->nVal >> 8) & 0xFF;
|
if (rpn_isKnown(expr)) {
|
||||||
|
expr->nVal = (uint32_t)expr->nVal >> 8 & 0xFF;
|
||||||
pushbyte(expr, RPN_CONST);
|
} else {
|
||||||
pushbyte(expr, 8);
|
uint8_t bytes[] = {RPN_CONST, 8, 0, 0, 0, RPN_SHR,
|
||||||
pushbyte(expr, 0);
|
RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
||||||
pushbyte(expr, 0);
|
expr->nRPNPatchSize += sizeof(bytes);
|
||||||
pushbyte(expr, 0);
|
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
|
||||||
|
}
|
||||||
pushbyte(expr, RPN_SHR);
|
|
||||||
|
|
||||||
pushbyte(expr, RPN_CONST);
|
|
||||||
pushbyte(expr, 0xFF);
|
|
||||||
pushbyte(expr, 0);
|
|
||||||
pushbyte(expr, 0);
|
|
||||||
pushbyte(expr, 0);
|
|
||||||
|
|
||||||
pushbyte(expr, RPN_AND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
void rpn_LOW(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
|
expr->isSymbol = false;
|
||||||
|
|
||||||
expr->nVal = expr->nVal & 0xFF;
|
if (rpn_isKnown(expr)) {
|
||||||
|
expr->nVal = expr->nVal & 0xFF;
|
||||||
|
} else {
|
||||||
|
uint8_t bytes[] = {RPN_CONST, 0xFF, 0, 0, 0, RPN_AND};
|
||||||
|
|
||||||
pushbyte(expr, RPN_CONST);
|
expr->nRPNPatchSize += sizeof(bytes);
|
||||||
pushbyte(expr, 0xFF);
|
memcpy(reserveSpace(expr, sizeof(bytes)), bytes, sizeof(bytes));
|
||||||
pushbyte(expr, 0);
|
}
|
||||||
pushbyte(expr, 0);
|
|
||||||
pushbyte(expr, 0);
|
|
||||||
|
|
||||||
pushbyte(expr, RPN_AND);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_LOGEQU(struct Expression *expr, const struct Expression *src1,
|
void rpn_ISCONST(struct Expression *expr, const struct Expression *src)
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
{
|
||||||
joinexpr();
|
rpn_Init(expr);
|
||||||
expr->nVal = (expr->nVal == src2->nVal);
|
expr->nVal = rpn_isKnown(src);
|
||||||
pushbyte(expr, RPN_LOGEQ);
|
expr->isKnown = true;
|
||||||
}
|
expr->isSymbol = false;
|
||||||
|
|
||||||
void rpn_LOGGT(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal > src2->nVal);
|
|
||||||
pushbyte(expr, RPN_LOGGT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_LOGLT(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal < src2->nVal);
|
|
||||||
pushbyte(expr, RPN_LOGLT);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_LOGGE(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal >= src2->nVal);
|
|
||||||
pushbyte(expr, RPN_LOGGE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_LOGLE(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal <= src2->nVal);
|
|
||||||
pushbyte(expr, RPN_LOGLE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_LOGNE(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal != src2->nVal);
|
|
||||||
pushbyte(expr, RPN_LOGNE);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_ADD(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal + src2->nVal);
|
|
||||||
pushbyte(expr, RPN_ADD);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_SUB(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal - src2->nVal);
|
|
||||||
pushbyte(expr, RPN_SUB);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_XOR(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal ^ src2->nVal);
|
|
||||||
pushbyte(expr, RPN_XOR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_OR(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal | src2->nVal);
|
|
||||||
pushbyte(expr, RPN_OR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_AND(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal & src2->nVal);
|
|
||||||
pushbyte(expr, RPN_AND);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_SHL(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
|
|
||||||
if (src1->nVal < 0)
|
|
||||||
warning("Left shift of negative value: %d", src1->nVal);
|
|
||||||
|
|
||||||
if (src2->nVal < 0)
|
|
||||||
fatalerror("Shift by negative value: %d", src2->nVal);
|
|
||||||
else if (src2->nVal >= 32)
|
|
||||||
fatalerror("Shift by too big value: %d", src2->nVal);
|
|
||||||
|
|
||||||
expr->nVal = (expr->nVal << src2->nVal);
|
|
||||||
pushbyte(expr, RPN_SHL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_SHR(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
if (src2->nVal < 0)
|
|
||||||
fatalerror("Shift by negative value: %d", src2->nVal);
|
|
||||||
else if (src2->nVal >= 32)
|
|
||||||
fatalerror("Shift by too big value: %d", src2->nVal);
|
|
||||||
|
|
||||||
expr->nVal = (expr->nVal >> src2->nVal);
|
|
||||||
pushbyte(expr, RPN_SHR);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_MUL(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
expr->nVal = (expr->nVal * src2->nVal);
|
|
||||||
pushbyte(expr, RPN_MUL);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_DIV(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
if (src2->nVal == 0)
|
|
||||||
fatalerror("Division by zero");
|
|
||||||
|
|
||||||
expr->nVal = (expr->nVal / src2->nVal);
|
|
||||||
pushbyte(expr, RPN_DIV);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpn_MOD(struct Expression *expr, const struct Expression *src1,
|
|
||||||
const struct Expression *src2)
|
|
||||||
{
|
|
||||||
joinexpr();
|
|
||||||
if (src2->nVal == 0)
|
|
||||||
fatalerror("Division by zero");
|
|
||||||
|
|
||||||
expr->nVal = (expr->nVal % src2->nVal);
|
|
||||||
pushbyte(expr, RPN_MOD);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
|
void rpn_UNNEG(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->nVal = -expr->nVal;
|
expr->isSymbol = false;
|
||||||
pushbyte(expr, RPN_UNSUB);
|
|
||||||
|
if (rpn_isKnown(expr)) {
|
||||||
|
expr->nVal = -(uint32_t)expr->nVal;
|
||||||
|
} else {
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
*reserveSpace(expr, 1) = RPN_UNSUB;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
|
void rpn_UNNOT(struct Expression *expr, const struct Expression *src)
|
||||||
{
|
{
|
||||||
*expr = *src;
|
*expr = *src;
|
||||||
expr->nVal = ~expr->nVal;
|
expr->isSymbol = false;
|
||||||
pushbyte(expr, RPN_UNNOT);
|
|
||||||
|
if (rpn_isKnown(expr)) {
|
||||||
|
expr->nVal = ~expr->nVal;
|
||||||
|
} else {
|
||||||
|
expr->nRPNPatchSize++;
|
||||||
|
*reserveSpace(expr, 1) = RPN_UNNOT;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user