12 static int debug_level
= -1;
16 debug_level
= atoi(getenv("DEBUG") ?: "0");
19 static void __attribute__((format(printf
, 2, 3)))
20 debug_raw(int level
, const char *fmt
, ...) {
22 if (debug_level
>= level
) {
24 vfprintf(stderr
, fmt
, ap
);
28 #define debug(...) debug_raw(1, __VA_ARGS__)
30 static int __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2)))
31 die(const char *fmt
, ...)
47 static int64_t orig
[LIMIT
];
64 static struct state s
[50];
67 dump(struct state
*s
) {
70 debug(" state of id=%d: pc=%d base=%d in=%s%" PRId64
" out=%s%" PRId64
71 " steps=%d\n", s
->id
, s
->pc
, s
->base
,
72 s
->has_in
? "" : "!", s
->in
, s
->has_out
? "" : "!", s
->out
, s
->steps
);
73 for (int i
= 0; i
< len
; i
++)
74 debug_raw(3, "%" PRId64
",", s
->a
[i
]);
78 static void __attribute__((noreturn
))
79 crash(struct state
*s
, const char *msg
) {
80 printf("invalid program id=%d, pc=%d: %s\n", s
->id
, s
->pc
, msg
);
85 get(struct state
*s
, int param
) {
86 int64_t op
= s
->a
[s
->pc
];
91 if (op
> 99999 || op
< 0)
92 crash(s
, "unexpected opcode");
93 if (s
->pc
+ param
> LIMIT
)
94 crash(s
, "memory too short for opcode");
95 value
= s
->a
[s
->pc
+ param
];
98 mode
= (op
/ scale
) % 10;
99 debug_raw(3, "get op=%" PRId64
" mode=%d value=%" PRId64
"\n",
103 if (value
> LIMIT
|| value
< 0)
104 crash(s
, "in position mode, param beyond memory");
110 if (value
> LIMIT
|| value
< 0)
111 crash(s
, "in relative mode, param beyond memory");
114 crash(s
, "unexpected mode");
119 put(struct state
*s
, int param
, int64_t value
) {
120 int64_t op
= s
->a
[s
->pc
];
125 if (op
> 99999 || op
< 0)
126 crash(s
, "unexpected opcode");
127 if (s
->pc
+ param
> LIMIT
)
128 crash(s
, "memory too short for opcode");
129 offset
= s
->a
[s
->pc
+ param
];
132 mode
= (op
/ scale
) % 10;
133 debug_raw(3, "put op=%" PRId64
" mode=%d value=%" PRId64
" offset=%" PRId64
134 "\n", op
, mode
, value
, offset
);
137 if (offset
> LIMIT
|| offset
< 0)
138 crash(s
, "in position mode, param beyond memory");
139 s
->a
[offset
] = value
;
143 if (offset
> LIMIT
|| offset
< 0)
144 crash(s
, "in relative mode, param beyond memory");
145 s
->a
[offset
] = value
;
148 crash(s
, "unexpected mode");
153 init(struct state
*s
, int64_t in
) {
154 memset(s
, 0, sizeof *s
);
155 memcpy(s
->a
, orig
, len
* sizeof orig
[0]);
162 /* Returns -1 for stalled on input, 0 for done, 1 for stalled after output */
164 run(struct state
*s
) {
168 debug_raw(2, "executing id=%d step=%d pc=%d base=%d %" PRId64
169 ",%" PRId64
",%" PRId64
",%" PRId64
"\n", s
->id
,
170 s
->steps
++, s
->pc
, s
->base
, s
->a
[s
->pc
], s
->a
[s
->pc
+1],
171 s
->a
[s
->pc
+2], s
->a
[s
->pc
+3]);
172 if (!(s
->steps
% 10000))
173 debug(" steps=%d\n", s
->steps
);
174 if (s
->pc
> LIMIT
|| s
->pc
< 0)
175 crash(s
, "program ran out of bounds");
176 switch (s
->a
[s
->pc
] % 100) {
178 put(s
, 3, get(s
, 1) + get(s
, 2));
182 put(s
, 3, get(s
, 1) * get(s
, 2));
187 debug_raw(2, "id=%d stalling for input\n", s
->id
);
197 debug_raw(2, "id=%d stalling for output\n", s
->id
);
220 put(s
, 3, get(s
, 1) < get(s
, 2));
224 put(s
, 3, get(s
, 1) == get(s
, 2));
228 s
->base
+= get(s
, 1);
229 if (s
->base
< 0 || s
->base
> LIMIT
)
230 crash(s
, "relative base out of bounds");
234 debug_raw(2, "id=%d halting\n", s
->id
);
237 crash(s
, "unexpected opcode");
245 main(int argc
, char **argv
) {
247 bool done
= false, idle
;
254 if (argc
> 1 && strcmp("-", argv
[1]))
255 if (!(stdin
= freopen(argv
[1], "r", stdin
))) {
260 while (scanf("%" SCNd64
"%*[,\n]", &orig
[len
]) == 1)
261 if (len
++ > LIMIT
- 3)
262 die("recompile with larger LIMIT");
263 printf("Read %u slots\n", len
);
265 for (i
= 0; i
< 50; i
++) {
267 if (run(&s
[i
]) != -1)
268 crash(&s
[i
], "unexpected program behavior");
272 for (i
= 0; i
< 50 && !done
; i
++) {
274 if (s
[i
].head
< s
[i
].tail
) {
275 s
[i
].in
= s
[i
].q
[s
[i
].head
].x
;
281 switch (run(&s
[i
])) {
284 debug("program %d consuming %" PRId64
",%" PRId64
"\n",
285 i
, s
[i
].q
[s
[i
].head
].x
, s
[i
].q
[s
[i
].head
].y
);
286 s
[i
].in
= s
[i
].q
[s
[i
].head
].y
;
290 crash(&s
[i
], "unexpected completion");
293 case 0: crash(&s
[i
], "unexpected completion");
299 } else if (addr
< 50ULL) {
300 q
= &s
[addr
].q
[s
[addr
].tail
];
301 if (++s
[addr
].tail
== QLEN
)
302 crash(&s
[addr
], "recompile with larger QLEN");
304 crash(&s
[i
], "addr out of bounds");
305 s
[i
].has_out
= false;
307 crash(&s
[i
], "expecting output sequence");
309 s
[i
].has_out
= false;
310 if (!run(&s
[i
]) || !s
[i
].has_out
)
311 crash(&s
[i
], "expecting output sequence");
313 s
[i
].has_out
= false;
314 debug("program %d sending %" PRId64
",%" PRId64
" to %" PRId64
"\n",
315 i
, q
->x
, q
->y
, addr
);
316 if (!part1
&& addr
== 255) {
318 printf("first value to 255: %" PRId64
", %" PRId64
"\n",
325 debug("detected idle, NAT contains %" PRId64
", %" PRId64
"\n",
327 for (i
= 0; i
< 50; i
++)
328 s
[i
].head
= s
[i
].tail
= 0;
330 if (q255
.y
== s
[0].q
[0].y
)
335 printf("NAT repeated %" PRId64
", %" PRId64
" after %d idle detections\n",
336 q255
.x
, q255
.y
, count
);