Update copyright notices
[litex.git] / vpi / main.c
1 /*
2 * Copyright (C) 2012 Vermeer Manufacturing Co.
3 * License: GPLv3 with additional permissions (see README).
4 */
5
6 #include <assert.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <vpi_user.h>
10
11 #include "ipc.h"
12
13 struct migensim_softc {
14 struct ipc_softc *ipc;
15 int has_go;
16 };
17
18 static int h_go(void *user)
19 {
20 struct migensim_softc *sc = (struct migensim_softc *)user;
21 sc->has_go = 1;
22 return 1;
23 }
24
25 static s_vpi_time zero_delay = {
26 .type = vpiSimTime,
27 .high = 0,
28 .low = 0
29 };
30
31 static int h_write(char *name, int index, int nchunks, const unsigned char *chunks, void *user)
32 {
33 vpiHandle item;
34 s_vpi_vecval vector[64];
35 int i;
36 s_vpi_value value;
37
38 item = vpi_handle_by_name(name, NULL);
39 if(item == NULL) {
40 fprintf(stderr, "Attempted to write non-existing signal %s\n", name);
41 return 0;
42 }
43 if(vpi_get(vpiType, item) == vpiMemory)
44 item = vpi_handle_by_index(item, index);
45 else
46 assert(index == 0);
47
48 assert(nchunks <= 255);
49 for(i=0;i<64;i++) {
50 vector[i].aval = 0;
51 vector[i].bval = 0;
52 }
53 for(i=0;i<nchunks;i++)
54 vector[i/4].aval |= chunks[i] << 8*(i % 4);
55
56 value.format = vpiVectorVal;
57 value.value.vector = vector;
58 vpi_put_value(item, &value, &zero_delay, vpiInertialDelay);
59
60 return 1;
61 }
62
63 static int h_read(char *name, int index, void *user)
64 {
65 struct migensim_softc *sc = (struct migensim_softc *)user;
66 vpiHandle item;
67 s_vpi_value value;
68 int size;
69 int i;
70 int nvals;
71 unsigned int vals[64];
72 int nchunks;
73 unsigned char chunks[255];
74
75 item = vpi_handle_by_name(name, NULL);
76 if(item == NULL) {
77 fprintf(stderr, "Attempted to read non-existing signal %s\n", name);
78 return 0;
79 }
80 if(vpi_get(vpiType, item) == vpiMemory)
81 item = vpi_handle_by_index(item, index);
82 else
83 assert(index == 0);
84
85 value.format = vpiVectorVal;
86 vpi_get_value(item, &value);
87 size = vpi_get(vpiSize, item);
88 nvals = (size + 31)/32;
89 assert(nvals <= 64);
90 for(i=0;i<nvals;i++)
91 vals[i] = value.value.vector[i].aval & ~value.value.vector[i].bval;
92 nchunks = (size + 7)/8;
93 assert(nchunks <= 255);
94 for(i=0;i<nchunks;i++) {
95 switch(i % 4) {
96 case 0:
97 chunks[i] = vals[i/4] & 0xff;
98 break;
99 case 1:
100 chunks[i] = (vals[i/4] & 0xff00) >> 8;
101 break;
102 case 2:
103 chunks[i] = (vals[i/4] & 0xff0000) >> 16;
104 break;
105 case 3:
106 chunks[i] = (vals[i/4] & 0xff000000) >> 24;
107 break;
108 }
109 }
110
111 if(!ipc_read_reply(sc->ipc, nchunks, chunks)) {
112 perror("ipc_read_reply");
113 return 0;
114 }
115
116 return 1;
117 }
118
119 static int process_until_go(struct migensim_softc *sc)
120 {
121 int r;
122
123 sc->has_go = 0;
124 while(!sc->has_go) {
125 r = ipc_receive(sc->ipc);
126 if(r != 1)
127 return r;
128 }
129 return 1;
130 }
131
132 static PLI_INT32 connect_calltf(PLI_BYTE8 *user)
133 {
134 struct migensim_softc *sc = (struct migensim_softc *)user;
135 vpiHandle sys;
136 vpiHandle argv;
137 vpiHandle item;
138 s_vpi_value value;
139
140 sys = vpi_handle(vpiSysTfCall, 0);
141 argv = vpi_iterate(vpiArgument, sys);
142 item = vpi_scan(argv);
143 value.format = vpiStringVal;
144 vpi_get_value(item, &value);
145
146 sc->ipc = ipc_connect(value.value.str, h_go, h_write, h_read, sc);
147 if(sc->ipc == NULL) {
148 perror("ipc_connect");
149 vpi_control(vpiFinish, 1);
150 return 0;
151 }
152
153 return 0;
154 }
155
156 static PLI_INT32 tick_calltf(PLI_BYTE8 *user)
157 {
158 struct migensim_softc *sc = (struct migensim_softc *)user;
159 int r;
160
161 if(!ipc_tick(sc->ipc)) {
162 perror("ipc_tick");
163 vpi_control(vpiFinish, 1);
164 ipc_destroy(sc->ipc);
165 sc->ipc = NULL;
166 return 0;
167 }
168 r = process_until_go(sc);
169 if(r != 1) {
170 vpi_control(vpiFinish, r == 2 ? 0 : 1);
171 ipc_destroy(sc->ipc);
172 sc->ipc = NULL;
173 return 0;
174 }
175
176 return 0;
177 }
178
179 static struct migensim_softc sc;
180
181 static void simple_register(const char *tfname, PLI_INT32 (*calltf)(PLI_BYTE8 *))
182 {
183 s_vpi_systf_data tf_data;
184
185 tf_data.type = vpiSysTask;
186 tf_data.tfname = tfname;
187 tf_data.calltf = calltf;
188 tf_data.compiletf = NULL;
189 tf_data.sizetf = 0;
190 tf_data.user_data = (void *)&sc;
191 vpi_register_systf(&tf_data);
192 }
193
194 static void migensim_register()
195 {
196 simple_register("$migensim_connect", connect_calltf);
197 simple_register("$migensim_tick", tick_calltf);
198 }
199
200 void (*vlog_startup_routines[])() = {
201 migensim_register,
202 0
203 };