corundum_bm.c 6.91 KB
Newer Older
Jialin Li's avatar
Jialin Li committed
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
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <signal.h>

#include <corundum_bm.h>
#include <nicsim.h>

static volatile int exiting = 0;
static struct CorundumRegs regs;

static void sigint_handler(int dummy)
{
    exiting = 1;
}

static volatile union cosim_pcie_proto_d2h *d2h_alloc(void)
{
    volatile union cosim_pcie_proto_d2h *msg = nicsim_d2h_alloc();
    if (msg == NULL) {
        fprintf(stderr, "d2h_alloc: no entry available\n");
        abort();
    }
    return msg;
}

static uint64_t csr_read(uint64_t off)
{
    switch (off) {
        case   0x00: return 32; /* firmware id */
        case   0x04: return 1; /* firmware version */
        case   0x08: return 0x43215678; /* board id */
        case   0x0c: return 0x1; /* board version */
        case   0x10: return 1; /* phc count */
        case   0x14: return 0x200; /* phc offset */
        case   0x18: return 0x80; /* phc stride */
        case   0x20: return 1; /* if_count */
        case   0x24: return 0x80000; /* if stride */
        case   0x2c: return 0x80000; /* if csr offset */
        case  0x200: return 0x1; /* phc features */
        default:
            fprintf(stderr, "csr_read(%lu) unimplemented\n", off);
            return 0;
    }
}

static void csr_write(uint64_t off, uint64_t val)
{
}

static void read_complete(uint64_t req_id, void *val, uint16_t len)
{
    volatile union cosim_pcie_proto_d2h *msg;
    volatile struct cosim_pcie_proto_d2h_readcomp *rc;

    msg = d2h_alloc();
    rc = &msg->readcomp;

    memcpy((void *)rc->data, val, len);
    rc->req_id = req_id;

    //WMB();
    rc->own_type = COSIM_PCIE_PROTO_D2H_MSG_READCOMP |
        COSIM_PCIE_PROTO_D2H_OWN_HOST;
}

static void h2d_read(volatile struct cosim_pcie_proto_h2d_read *read)
{
    printf("read(bar=0x%x, off=0x%lx, len=%u)\n", read->bar, read->offset, read->len);
    if (read->offset < 0x80000) {
        uint64_t val = csr_read(read->offset);
        read_complete(read->req_id, &val, read->len);
    } else {
        switch (read->offset - 0x80000) {
        case REG_A:
            read_complete(read->req_id, &regs.reg_a, read->len);
            break;
        case REG_B:
            read_complete(read->req_id, &regs.reg_b, read->len);
            break;
        case REG_C:
            read_complete(read->req_id, &regs.reg_c, read->len);
            break;
        case REG_D:
            read_complete(read->req_id, &regs.reg_d, read->len);
            break;
        case REG_E:
            read_complete(read->req_id, &regs.reg_e, read->len);
            break;
        case REG_F:
            read_complete(read->req_id, &regs.reg_f, read->len);
            break;
        case REG_G:
            read_complete(read->req_id, &regs.reg_g, read->len);
            break;
        case REG_H:
            read_complete(read->req_id, &regs.reg_h, read->len);
            break;
        case REG_I:
            read_complete(read->req_id, &regs.reg_i, read->len);
            break;
        case REG_J:
            read_complete(read->req_id, &regs.reg_j, read->len);
            break;
        case REG_K:
            read_complete(read->req_id, &regs.reg_k, read->len);
            break;
        case REG_L:
            read_complete(read->req_id, &regs.reg_l, read->len);
            break;
        case REG_M:
            read_complete(read->req_id, &regs.reg_m, read->len);
            break;
        case REG_N:
            read_complete(read->req_id, &regs.reg_n, read->len);
            break;
        case REG_O:
            read_complete(read->req_id, &regs.reg_o, read->len);
            break;
        default:
            fprintf(stderr, "unimplemented read at off=0x%lx len=%u\n", read->offset, read->len);
            uint64_t val = 0;
            read_complete(read->req_id, &val, read->len);
            break;
        }
    }
}

static void h2d_write(volatile struct cosim_pcie_proto_h2d_write *write)
{
    uint64_t val = 0;
    memcpy(&val, (void *)write->data, write->len);

    if (write->offset < 0x80000) {
        volatile union cosim_pcie_proto_d2h *msg;
        volatile struct cosim_pcie_proto_d2h_writecomp *wc;

        msg = d2h_alloc();
        wc = &msg->writecomp;

        printf("write(bar=0x%x, off=0x%lx, len=%u)\n", write->bar, write->offset, write->len);

        csr_write(write->offset, val);
        wc->req_id = write->req_id;

        //WMB();
        wc->own_type = COSIM_PCIE_PROTO_D2H_MSG_WRITECOMP |
            COSIM_PCIE_PROTO_D2H_OWN_HOST;
    } else {
        fprintf(stderr, "unimplemented write at off=0x%lx\n", write->offset);
    }
}

static void h2d_readcomp(volatile struct cosim_pcie_proto_h2d_readcomp *rc)
{
    printf("read complete(req_id=%lu)\n", rc->req_id);
}

static void h2d_writecomp(volatile struct cosim_pcie_proto_h2d_writecomp *wc)
{
    printf("write complete(req_id=%lu\n", wc->req_id);
}

static void n2d_recv(volatile struct cosim_eth_proto_n2d_recv *recv)
{
    printf("RX recv(port=%u, len=%u)\n", recv->port, recv->len);
}

static void poll_h2d(void)
{
    volatile union cosim_pcie_proto_h2d *msg = nicif_h2d_poll();
    uint8_t type;

    if (msg == NULL)
        return;

    type = msg->dummy.own_type & COSIM_PCIE_PROTO_H2D_MSG_MASK;
    switch (type) {
        case COSIM_PCIE_PROTO_H2D_MSG_READ:
            h2d_read(&msg->read);
            break;

        case COSIM_PCIE_PROTO_H2D_MSG_WRITE:
            h2d_write(&msg->write);
            break;

        case COSIM_PCIE_PROTO_H2D_MSG_READCOMP:
            h2d_readcomp(&msg->readcomp);
            break;

        case COSIM_PCIE_PROTO_H2D_MSG_WRITECOMP:
            h2d_writecomp(&msg->writecomp);
            break;

        default:
            fprintf(stderr, "poll_h2d: unsupported type=%u\n", type);
    }

    nicif_h2d_done(msg);
    nicif_h2d_next();
}

static void poll_n2d(void)
{
    volatile union cosim_eth_proto_n2d *msg = nicif_n2d_poll();
    uint8_t t;

    if (msg == NULL)
        return;

    t = msg->dummy.own_type & COSIM_ETH_PROTO_N2D_MSG_MASK;
    switch (t) {
        case COSIM_ETH_PROTO_N2D_MSG_RECV:
            n2d_recv(&msg->recv);
            break;

        default:
            fprintf(stderr, "poll_n2d: unsupported type=%u", t);
    }

    nicif_n2d_done(msg);
    nicif_n2d_next();
}

int main(int argc, char *argv[])
{
    struct cosim_pcie_proto_dev_intro di;
    memset(&di, 0, sizeof(di));

    di.bars[0].len = 1 << 24;
    di.bars[0].flags = COSIM_PCIE_PROTO_BAR_64;

    di.pci_vendor_id = 0x5543;
    di.pci_device_id = 0x1001;
    di.pci_class = 0x02;
    di.pci_subclass = 0x00;
    di.pci_revision = 0x00;
    di.pci_msi_nvecs = 32;

    int sync_pci_en = 0, sync_eth_en = 0;
    if (nicsim_init(&di, "/tmp/cosim-pci", &sync_pci_en,
                NULL, &sync_eth_en,
                "/dev/shm/dummy_nic_shm")) {
        return EXIT_FAILURE;
    }

    signal(SIGINT, sigint_handler);

    memset(&regs, 0, sizeof(regs));

    while (!exiting) {
        poll_h2d();
        poll_n2d();
    }

    nicsim_cleanup();
    return 0;
}