build/sim: use json_object_get_int64 instead of json_object_get_uint64.
[litex.git] / litex / build / sim / core / modules / clocker / clocker.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <json-c/json.h>
5 #include "error.h"
6 #include "modules.h"
7
8 struct session_s {
9 char *clk;
10 char *name;
11 uint32_t freq_hz;
12 uint16_t phase_deg;
13 };
14
15 static int litex_sim_module_pads_get( struct pad_s *pads, char *name, void **signal)
16 {
17 int ret = RC_OK;
18 void *sig=NULL;
19 int i;
20
21 if(!pads || !name || !signal) {
22 ret=RC_INVARG;
23 goto out;
24 }
25
26 i = 0;
27 while(pads[i].name) {
28 if(!strcmp(pads[i].name, name))
29 {
30 sig=(void*)pads[i].signal;
31 break;
32 }
33 i++;
34 }
35
36 out:
37 *signal=sig;
38 return ret;
39 }
40
41 static int clocker_parse_args(struct session_s *s, const char *args)
42 {
43 int ret = RC_OK;
44 json_object *args_json = NULL;
45 json_object *freq_json = NULL;
46 json_object *phase_json = NULL;
47
48 args_json = json_tokener_parse(args);
49 if (!args_json) {
50 ret = RC_JSERROR;
51 fprintf(stderr, "[clocker] Could not parse args: %s\n", args);
52 goto out;
53 }
54
55 if(!json_object_object_get_ex(args_json, "freq_hz", &freq_json))
56 {
57 ret = RC_JSERROR;
58 fprintf(stderr, "[clocker] \"freq_hz\" not found in args: %s\n", json_object_to_json_string(args_json));
59 goto out;
60 }
61
62 if(!json_object_object_get_ex(args_json, "phase_deg", &phase_json))
63 {
64 ret = RC_JSERROR;
65 fprintf(stderr, "[clocker] \"phase_deg\" not found in args: %s\n", json_object_to_json_string(args_json));
66 goto out;
67 }
68
69 s->freq_hz = json_object_get_int64(freq_json);
70 s->phase_deg = json_object_get_int64(phase_json);
71
72 if (s->freq_hz == 0) {
73 ret = RC_JSERROR;
74 fprintf(stderr, "[clocker] \"freq_hz\" must be different than 0\n");
75 goto out;
76 }
77
78 if (s->phase_deg >= 360) {
79 ret = RC_JSERROR;
80 fprintf(stderr, "[clocker] \"phase_deg\" must be in range [0, 360)\n");
81 goto out;
82 }
83 out:
84 if(args_json) json_object_put(args_json);
85 return ret;
86 }
87
88 static int clocker_start()
89 {
90 printf("[clocker] loaded\n");
91 return RC_OK;
92 }
93
94 static int clocker_new(void **sess, char *args)
95 {
96 int ret = RC_OK;
97
98 struct session_s *s=NULL;
99
100 if(!sess) {
101 ret = RC_INVARG;
102 goto out;
103 }
104
105 s=(struct session_s*)malloc(sizeof(struct session_s));
106 if(!s) {
107 ret=RC_NOENMEM;
108 goto out;
109 }
110 memset(s, 0, sizeof(struct session_s));
111
112 clocker_parse_args(s, args);
113 out:
114 *sess=(void*)s;
115 return ret;
116 }
117
118 static int clocker_add_pads(void *sess, struct pad_list_s *plist)
119 {
120 int ret = RC_OK;
121 struct session_s *s = (struct session_s*)sess;
122 struct pad_s *pads;
123
124 if(!sess || !plist) {
125 ret = RC_INVARG;
126 goto out;
127 }
128 pads = plist->pads;
129
130 ret = litex_sim_module_pads_get(pads, plist->name, (void**)&s->clk);
131 if (ret != RC_OK) {
132 goto out;
133 }
134
135 s->name = plist->name;
136 *s->clk=0;
137 printf("[clocker] %s: freq_hz=%u, phase_deg=%u\n", s->name, s->freq_hz, s->phase_deg);
138 out:
139 return ret;
140 }
141
142 static int clocker_tick(void *sess, uint64_t time_ps)
143 {
144 static const uint64_t ps_in_sec = 1000000000000ull;
145 struct session_s *s = (struct session_s*) sess;
146
147 uint64_t period_ps = ps_in_sec / s->freq_hz;
148 uint64_t phase_shift_ps = period_ps * s->phase_deg / 360;
149
150 // phase-shifted time relative to start of current period
151 uint64_t rel_time_ps = (time_ps - phase_shift_ps) % period_ps;
152 if (rel_time_ps < (period_ps/2)) {
153 *s->clk = 1;
154 } else {
155 *s->clk = 0;
156 }
157
158 return 0;
159 }
160
161 static struct ext_module_s ext_mod = {
162 "clocker",
163 clocker_start,
164 clocker_new,
165 clocker_add_pads,
166 NULL,
167 clocker_tick
168 };
169
170 int litex_sim_ext_module_init(int (*register_module)(struct ext_module_s *))
171 {
172 int ret = RC_OK;
173 ret = register_module(&ext_mod);
174 return ret;
175 }