1 /****************************************************************************
2 Copyright (C) 1987-2015 by Jeffery P. Hansen
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, write to the Free Software Foundation, Inc.,
16 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 ****************************************************************************/
18
19 #include <stdlib.h>
20
21 #include "tkgate.h"
22
23
24 /*****************************************************************************
25 *
26 * Helping function to clear all breakpoints and reclaim allocated memory.
27 * Used in conjunction with Hash_flush().
28 *
29 *****************************************************************************/
breakpoint_flush(HashElem * e,Hash * h)30 static void breakpoint_flush(HashElem *e,Hash *h)
31 {
32 SBreakPoint *b = (SBreakPoint*) HashElem_obj(e);
33 delete_SBreakPoint(b);
34 }
35
36 /*****************************************************************************
37 *
38 * Helping function used with qsort() to sort breakpoints by their ID value.
39 *
40 *****************************************************************************/
breakpoint_compare(const void * vA,const void * vB)41 static int breakpoint_compare(const void *vA,const void *vB)
42 {
43 const SBreakPoint *A = *(SBreakPoint**) vA;
44 const SBreakPoint *B = *(SBreakPoint**) vB;
45
46 return A->bp_id - B->bp_id;
47 }
48
49 /*****************************************************************************
50 *
51 * Generates a breakpoint file and loads it into the simulator.
52 *
53 * Parameters:
54 * bp Breakpoint to be set.
55 *
56 *
57 * Creates a script file to implement the specified breakpoint and loads the
58 * breakpoint as if it were a script file. A breakpoint can be any expression
59 * in terms of nets in the user circuit and can optionally be prepended by
60 * the 'negedge' or 'posedge' keyword. It can also optionally have a '#' followed
61 * by a number at the end. The [*] in the net declaration/assignment means that
62 * the bit width of the declared net will match the bitwidth of the right-hand
63 * side expression. The is a tkgate extension to verilog intended only for use
64 * with tkgate breakpoints.
65 *
66 * Some examples of the scripts generated from various breakpoint commands.
67 *
68 * Command: $break 1 (W + E)
69 *
70 * wire [*] BP$1 = (W + E);
71 * always @(BP$1) $tkg$break(1,BP$1);
72 *
73 * Command: $break 2 posedge (W > E)
74 *
75 * wire [*] BP$2 = W > E;
76 * always @(posedge BP$2) #10 $tkg$break(2,BP$2);
77 *
78 * Command: $break 3 (W > E) #10
79 *
80 * wire [*] BP$3 = W > E;
81 * always @(BP$3) #10 $tkg$break(3,BP$3);
82 *
83 * Command: $break 4 #10
84 *
85 * always #10 $tkg$break(4,1'b1);
86 *
87 *****************************************************************************/
SBreakPoint_enable(SBreakPoint * bp)88 void SBreakPoint_enable(SBreakPoint *bp)
89 {
90 char fileName[STRMAX];
91 char expression[STRMAX];
92 const char *p;
93 const char *edge;
94 char *q;
95 int delay = -1;
96 int isDelayOnly;
97 FILE *f;
98 char x;
99
100
101 p = bp->bp_condition;
102
103 while (*p && isspace(*p)) p++;
104
105 if (strncmp(p,"posedge",7) == 0 && !isalnum(p[7])) {
106 edge = "posedge";
107 p += 7;
108 } else if (strncmp(p,"negedge",7) == 0 && !isalnum(p[7])) {
109 edge = "negedge";
110 p += 7;
111 } else
112 edge = "";
113
114 strcpy(expression,p);
115 q = strchr(expression,'#');
116 if (q) {
117 /* Make sure there is no tailing junk by trying to scan an additional character */
118 if (sscanf(q,"#%d %c",&delay,&x) == 1) {
119 *q = 0;
120 } else if (sscanf(q,"#(%d) %c",&delay,&x) == 1) {
121 *q = 0;
122 } else
123 delay = -1;
124 }
125
126 isDelayOnly = (sscanf(expression,"%c",&x) == 0);
127
128 /*
129 * Empty breakpoint
130 */
131 if (isDelayOnly && delay < 0.0) {
132 BrkPtTable_error(TkGate.circuit->c_breakpoints,bp->bp_id);
133 return;
134 }
135
136
137 getSimTempFile(fileName);
138 f = fopen(fileName,"w");
139 if (!f) {
140 message(MC_MSGLOG|MC_URGENT,"Failed to create temorary file '%s' for breakpoint.",fileName);
141 BrkPtTable_error(TkGate.circuit->c_breakpoints,bp->bp_id);
142 return;
143 }
144
145 if (isDelayOnly) {
146 fprintf(f,"always #%d $tkg$reportbreak(%d, 1'b1);\n",delay,bp->bp_id);
147 } else {
148 fprintf(f,"wire [*] \\BP$%d = %s;\n", bp->bp_id, expression);
149 if (delay > 0)
150 fprintf(f,"always #0 @(%s \\BP$%d ) #%d $tkg$reportbreak(%d, \\BP$%d );\n",
151 edge, bp->bp_id, delay, bp->bp_id, bp->bp_id);
152 else
153 fprintf(f,"always #0 @(%s \\BP$%d ) $tkg$reportbreak(%d, \\BP$%d );\n",
154 edge, bp->bp_id, bp->bp_id, bp->bp_id);
155 }
156
157 fclose(f);
158
159 sendSimCmd("$script break:%d %s -delete -silent -breakpt", bp->bp_id, fileName);
160 }
161
162 /*****************************************************************************
163 *
164 * Create a new breapoint object
165 *
166 *****************************************************************************/
new_SBreakPoint(int idx,int state,const char * condition)167 SBreakPoint *new_SBreakPoint(int idx,int state, const char *condition)
168 {
169 SBreakPoint *bp = OM_MALLOC(SBreakPoint);
170
171 bp->bp_id = idx;
172 bp->bp_state = state;
173 bp->bp_condition = ob_strdup(condition);
174
175 return bp;
176 }
177
178 /*****************************************************************************
179 *
180 * Delete a breapoint object and reclaim its memory.
181 *
182 *****************************************************************************/
delete_SBreakPoint(SBreakPoint * bp)183 void delete_SBreakPoint(SBreakPoint *bp)
184 {
185 ob_free(bp->bp_condition);
186 ob_free(bp);
187 }
188
189
190 /*****************************************************************************
191 *
192 * Insert breakpoint with the specified id
193 *
194 *****************************************************************************/
BrkPtTable_insert(NHash * bpm,int id,const char * condition)195 int BrkPtTable_insert(NHash *bpm,int id,const char *condition)
196 {
197 SBreakPoint *bp;
198
199 while (NHash_find(bpm,id))
200 id++;
201
202 bp = new_SBreakPoint(id,BPS_GO,condition);
203 NHash_insert(bpm,id,bp);
204
205 if (TkGate.circuit->simulator.active)
206 SBreakPoint_enable(bp);
207
208 return id;
209 }
210
211 /*****************************************************************************
212 *
213 * Delete breakpoint at an index (not id number)
214 *
215 *****************************************************************************/
BrkPtTable_delete(NHash * bpm,int id)216 void BrkPtTable_delete(NHash *bpm,int id)
217 {
218 SBreakPoint *bp = NHash_find(bpm,id);
219 if (!bp) return;
220
221 NHash_remove(bpm,id);
222
223 if (TkGate.circuit->simulator.active)
224 sendSimCmd("$delscript break:%d",id);
225 }
226
BrkPtTable_enable(NHash * bpm,int id)227 void BrkPtTable_enable(NHash *bpm,int id)
228 {
229 SBreakPoint *bp = NHash_find(bpm,id);
230 if (!bp) return;
231
232 if (TkGate.circuit->simulator.active) {
233 if (bp->bp_state == BPS_INVALID || bp->bp_state == BPS_IGNORE) {
234 ob_touch(bp);
235 bp->bp_state = BPS_GO;
236 SBreakPoint_enable(bp);
237 }
238 DoTcl("Breakpoint::setState %d %d",bp->bp_id,bp->bp_state);
239 } else {
240 ob_touch(bp);
241 bp->bp_state = BPS_STANDBY;
242 DoTcl("Breakpoint::setState %d %d",bp->bp_id,bp->bp_state);
243 }
244 }
245
BrkPtTable_disable(NHash * bpm,int id)246 void BrkPtTable_disable(NHash *bpm,int id)
247 {
248 SBreakPoint *bp = NHash_find(bpm,id);
249 if (!bp) return;
250
251 if (TkGate.circuit->simulator.active) {
252 sendSimCmd("$delscript break:%d",bp->bp_id);
253 }
254
255 ob_touch(bp);
256 bp->bp_state = BPS_IGNORE;
257 DoTcl("Breakpoint::setState %d %d",bp->bp_id,bp->bp_state);
258 }
259
260
261 /*****************************************************************************
262 *
263 * Send all registered breakpoints to simulator.
264 *
265 *****************************************************************************/
BrkPtTable_sendAll(NHash * bpm)266 void BrkPtTable_sendAll(NHash *bpm)
267 {
268 if (TkGate.circuit->simulator.active) {
269 HashElem *he;
270
271 for (he = Hash_first(bpm);he;he = Hash_next(bpm,he)) {
272 SBreakPoint *bp = (SBreakPoint*)HashElem_obj(he);
273
274 if (bp->bp_state != BPS_IGNORE) {
275 SBreakPoint_enable(bp);
276 bp->bp_state = BPS_GO;
277 DoTcl("Breakpoint::setState %d %d",bp->bp_id,bp->bp_state);
278 }
279 }
280 }
281 }
282
283 /*****************************************************************************
284 *
285 * Show a breakpoint as having been activated.
286 *
287 *****************************************************************************/
BrkPtTable_activate(NHash * bpm,int id,const char * value)288 void BrkPtTable_activate(NHash *bpm,int id,const char *value)
289 {
290 char s_id[STRMAX];
291 SBreakPoint *bp = NHash_find(bpm,id);
292 if (!bp) return;
293
294 ob_touch(bp);
295 bp->bp_state = BPS_STOP;
296 sprintf(s_id,"%d",id);
297 DoTclL("Breakpoint::seeBreak",s_id,value,NULL);
298 }
299
300 /*****************************************************************************
301 *
302 * Mark a breakpoint as having an error.
303 *
304 *****************************************************************************/
BrkPtTable_error(NHash * bpm,int id)305 void BrkPtTable_error(NHash *bpm,int id)
306 {
307 SBreakPoint *bp = NHash_find(bpm,id);
308 if (!bp) return;
309
310 ob_touch(bp);
311 bp->bp_state = BPS_INVALID;
312 DoTcl("Breakpoint::seeError %d",id);
313 }
314
315 /*****************************************************************************
316 *
317 * Clear the 'active' mark on all breakpoints.
318 *
319 *****************************************************************************/
BrkPtTable_clearStop(NHash * bpm)320 void BrkPtTable_clearStop(NHash *bpm)
321 {
322 HashElem *he;
323
324 for (he = Hash_first(bpm);he;he = Hash_next(bpm,he)) {
325 SBreakPoint *bp = (SBreakPoint*)HashElem_obj(he);
326
327 if (TkGate.circuit->simulator.active) {
328 if (bp->bp_state == BPS_STOP) {
329 ob_touch(bp);
330 bp->bp_state = BPS_GO;
331 DoTcl("Breakpoint::seeGo %d",bp->bp_id);
332 }
333 } else {
334 if (bp->bp_state == BPS_STOP || bp->bp_state == BPS_GO) {
335 ob_touch(bp);
336 bp->bp_state = BPS_STANDBY;
337 DoTcl("Breakpoint::seeStandby %d",bp->bp_id);
338 }
339 }
340 }
341 }
342
343 /*****************************************************************************
344 *
345 * Flush all breakpoints from C registry and from tcl spreadsheet
346 *
347 *****************************************************************************/
BrkPtTable_flush(NHash * bpm)348 void BrkPtTable_flush(NHash *bpm)
349 {
350 Hash_flush(bpm, breakpoint_flush);
351 DoTcl("Breakpoint::flush");
352 }
353
354 /*****************************************************************************
355 *
356 * Load all registered breakpoints into the tcl spreadsheet.
357 *
358 *****************************************************************************/
BrkPtTable_loadInterface(NHash * bpm)359 void BrkPtTable_loadInterface(NHash *bpm)
360 {
361 HashElem *he;
362 SBreakPoint **bplist;
363 int n = Hash_numElems(bpm);
364 int i;
365
366 if (n == 0) return;
367 bplist = (SBreakPoint**) malloc(sizeof(SBreakPoint*)*n);
368
369 i = 0;
370 for (he = Hash_first(bpm);he;he = Hash_next(bpm,he), i++) {
371 SBreakPoint *bp = (SBreakPoint*)HashElem_obj(he);
372 bplist[i] = bp;
373 }
374
375 qsort(bplist,n,sizeof(SBreakPoint*),breakpoint_compare);
376
377 for (i = 0;i < n;i++) {
378 char id_str[STRMAX], state_str[STRMAX];
379 int state;
380
381 sprintf(id_str,"%d",bplist[i]->bp_id);
382
383 state = bplist[i]->bp_state;
384
385 if (!TkGate.circuit->simulator.active) {
386 if (state == BPS_GO || state == BPS_STOP)
387 state = BPS_STANDBY;
388 }
389
390 sprintf(state_str,"%d",state);
391 DoTclL("Breakpoint::addEntry",id_str,state_str,bplist[i]->bp_condition,NULL);
392 }
393
394
395 free(bplist);
396 }
397