summaryrefslogtreecommitdiff
path: root/src/cs.vala
blob: ff8a16878c44a09986f1a6083aeaa0fda24d1ba8 (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
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
/*
 * Copyright 2010 Joakim Sindholt <opensource@zhasha.com>
 *
 * 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
 * on the rights to use, copy, modify, merge, publish, distribute, sub
 * license, 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 (including the next
 * paragraph) 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 NON-INFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHOR(S) AND/OR THEIR SUPPLIERS 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. */

namespace Emulation
{
    /* Packet is very tolerant and will allow you to specify null for it's
     * DWORDs. This feature is very useful when checking a CS, as you can
     * simply pawn off the work on the Packetn classes. */
    public abstract class Packet : Object
    {
        public class Iterator
        {
            private weak Packet packet;
            private uint pos;

            public Iterator(Packet p)
            {
                packet = p;
                pos = 0;
            }

            public bool next() { return pos++ < packet.length; }
            public new uint32 get() { return packet[pos-1]; }
        }

        protected uint32[] dwords;
        public uint32 header { get; internal set; }
        public uint type_id { get { return (header >> 30) & 3; } }

        //public Type element_type { get { return typeof(uint32); } }
        public Iterator iterator() { return new Iterator(this); }

        public abstract uint32 target_addr(uint index);
        public abstract uint length { get; }
        public new uint32 get(uint index) { return dwords[index]; }

        protected inline uint32 extract_bits(uint high, uint low)
        {
            return (header >> low) & ((1 << (high-low+1))-1);
        }

        public static Packet make(uint32 header, uint32 *dwords = null)
        {
            switch ((header >> 30) & 3) {
                case 0: return new Packet0(header, dwords);
                case 1: return new Packet1(header, dwords);
                case 2: return new Packet2(header);
                case 3: return new Packet3(header, dwords);
            }
            /* we can't ever get here, but appease the compiler. */
            assert(false);
            return new Packet2(header);
        }
    }

    public class Packet0 : Packet
    {
        public uint32 addr { get { return _ADDR << 2; } }
        public bool one_reg_wr { get { return (bool)_ONE_REG_WR; } }
        public override uint length { get { return (uint)_COUNT+1; } }

        public uint32 _ADDR { get { return extract_bits(12, 0); } }
        public uint32 _ONE_REG_WR { get { return extract_bits(15, 15); } }
        public uint32 _COUNT { get { return extract_bits(29, 16); } }

        public override uint32 target_addr(uint index) { return (one_reg_wr) ? addr : (addr + index*4); }

        public Packet0(uint32 header, uint32 *dwords)
        {
            this.header = header;
            if (dwords != null) {
                this.dwords = new uint32[length];
                for (uint i = 0; i < length; i++) {
                    this.dwords[i] = dwords[i];
                }
            }
        }
    }

    public class Packet1 : Packet
    {
        public uint32 addr1 { get { return _ADDR1 << 2; } }
        public uint32 addr2 { get { return _ADDR2 << 2; } }
        public override uint length { get { return 2; } }

        public uint32 _ADDR1 { get { return extract_bits(10, 0); } }
        public uint32 _ADDR2 { get { return extract_bits(21, 11); } }

        public override uint32 target_addr(uint index) { return (index == 0) ? addr1 : addr2; }

        public Packet1(uint32 header, uint32 *dwords)
        {
            this.header = header;
            if (dwords != null) {
                this.dwords = new uint32[2];
                this.dwords[0] = dwords[0];
                this.dwords[1] = dwords[1];
            }
        }
    }

    public class Packet2 : Packet
    {
        public override uint length { get { return 0; } }
        public override uint32 target_addr(uint index) { return 0; }

        public Packet2(uint32 header)
        {
            this.header = header;
            this.dwords = null;
        }
    }

    public class Packet3 : Packet
    {
        public uint32 opcode { get { return _IT_OPCODE; } }
        public override uint length { get { return (uint)_COUNT+1; } }

        public uint32 _IT_OPCODE { get { return extract_bits(15, 8); } }
        public uint32 _COUNT { get { return extract_bits(29, 16); } }

        public override uint32 target_addr(uint index) { return 0; /* XXX todo */ }
        public string opcode_name { get { return "TODO"; } }

        public Packet3(uint32 header, uint32 *dwords)
        {
            this.header = header;
            if (dwords != null) {
                this.dwords = new uint32[length];
                for (uint i = 0; i < length; i++) {
                    this.dwords[i] = dwords[i];
                }
            }
        }
    }

    public class CS : Object
    {
        public class Iterator
        {
            private weak CS cs;
            private uint pos;

            public Iterator(CS cs)
            {
                this.cs = cs;
                this.pos = 0;
            }

            public bool next() { return pos++ < cs.length; }
            public new Packet get() { return cs[pos-1]; }
        }

        private static uint check(uint32 *dwords, uint len)
        {
            int pkt_count = 0;
            for (uint i = 0; i < len; i++, pkt_count++) {
                i += Packet.make(dwords[i]).length;
                if (i+1 > len) { return 0; }
            }
            return pkt_count;
        }

        private Packet[] packets;

        public Type element_type { get { return typeof(Packet); } }
        public Iterator iterator() { return new Iterator(this); }

        public uint length { get { return (packets != null) ? packets.length : 0; } }
        public new Packet get(uint index) { return packets[index]; }

        public CS(uint32 *dwords, uint len)
        {
            if (len > 0) { assert(dwords != null); }

            var pkt_count = check(dwords, len);
            packets = (pkt_count > 0) ? new Packet[pkt_count] : null;
            if (pkt_count > 0) {
                for (uint i = 0, pkt = 0; i < len; i++) {
                    packets[pkt] = Packet.make(dwords[i], dwords+i+1);
                    i += packets[pkt++].length;
                }
            }
        }
    }
}