summaryrefslogtreecommitdiff
path: root/tools/libdol2asm/data/reference_array.py
blob: d5d5fdf918d59d8c8481240999e366d73ca5f111 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
import struct

from dataclasses import dataclass, field
from typing import List, Tuple

from ..builder import AsyncBuilder
from ..globals import *
from .. import util
from .base import *
from .identifier import *
from .literal import *

@dataclass(eq=False)
class ReferenceArray(ArbitraryData):
    @property
    def element_size(self):
        return 4

    def array_type(self):
        size = self.size // self.element_size
        padding = self.padding // self.element_size
        
        if size == 1 and padding == 0:
            return self.element_type()
        else:
            return PaddingArrayType.create(
                self.element_type(),
                self.size // self.element_size,
                self.padding // self.element_size)

    def valid_reference(self, addr):
        return addr % 4 == 0

    def values(self):
        return Integer.u32_from(self.data)
        
    def gather_references(self, context, valid_range):
        self.references = [ addr for addr in self.values() if addr in valid_range ]

    def export_reference_value(self, symbol_table, index, addr) -> str:
        symbol = symbol_table[-1, addr]
        if symbol:
            return symbol.cpp_reference(self, addr)
        elif addr == 0:
            return "NULL"
        else:
            return f"0x{addr:08X}"

    async def export_declaration_body(self, exporter, builder: AsyncBuilder):
        values = self.values()

        if self.total_element_count == 1:
            await builder.write(f" = (void*){self.export_reference_value(exporter.gst, 0, values[0])};")
        else:
            await builder.write(f" = {{")
            for index, addr in enumerate(values):
                value = self.export_reference_value(exporter.gst, index, addr)
                await builder.write(f"\t(void*){value},")

            if self.padding > 0:
                await builder.write("\t/* padding */")
                for i in range(self.padding // self.element_size):
                    await builder.write("\tNULL,")
            await builder.write("};")


    @staticmethod
    def create(identifier: Identifier, addr: int, data: bytearray, padding_data: bytearray, always_extern: bool = False) -> "ReferenceArray":
        if sum(padding_data) != 0:
            print(identifier)

        assert sum(padding_data) == 0
        assert len(data) % 4 == 0
        assert len(padding_data) % 4 == 0
        return ReferenceArray(
            identifier=identifier,
            data_type=PointerType(VOID),
            addr=addr,
            data = data,
            size=len(data),
            padding_data = padding_data,
            padding = len(padding_data),
            always_extern=always_extern,
        )