aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Voss <mail@thomasvoss.com> 2024-02-16 21:28:01 +0100
committerThomas Voss <mail@thomasvoss.com> 2024-02-16 21:28:01 +0100
commita874670ee6d7b96d74e71467cee8be02db8a63e1 (patch)
tree45a0cf6977537e69ca5386b91f1e2c26ae7682ed /src
parent5e8ac2432d5d1b327be9b8d406b78f008c77bcd5 (diff)
Support custom clock speeds
Diffstat (limited to 'src')
-rw-r--r--src/ahoy/config.h1
-rw-r--r--src/ahoy/main.c98
2 files changed, 62 insertions, 37 deletions
diff --git a/src/ahoy/config.h b/src/ahoy/config.h
index 9a78f59..106382f 100644
--- a/src/ahoy/config.h
+++ b/src/ahoy/config.h
@@ -6,6 +6,7 @@
struct config {
/* Valid ranges are 0–UINT16_MAX. >UINT16_MAX is for random seed. */
uint32_t seed;
+ unsigned cpu_hz;
};
extern struct config cfg;
diff --git a/src/ahoy/main.c b/src/ahoy/main.c
index 581078b..fc737e6 100644
--- a/src/ahoy/main.c
+++ b/src/ahoy/main.c
@@ -1,8 +1,10 @@
#include <sys/stat.h>
+#include <err.h>
#include <fcntl.h>
#include <getopt.h>
#include <inttypes.h>
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
@@ -27,12 +29,28 @@
# error "Platform not supported at the moment"
#endif
-#define FPS 60
-#define INSTS_PER_SEC 700
+#define FPS 60
+
+#define STRTOX(T, SUF) \
+ static T strto##SUF(const char8_t *s, rune *ch) \
+ { \
+ T n = 0; \
+ size_t len = strlen(s); \
+ while (u8next(ch, &s, &len)) { \
+ if (!(*ch >= '0' && *ch <= '9')) \
+ return -1; \
+ if (ckd_mul(&n, n, 10) || ckd_add(&n, n, *ch - '0')) \
+ return -1; \
+ } \
+ *ch = '\0'; \
+ return n; \
+ }
+
+STRTOX(unsigned, u)
+STRTOX(uint16_t, u16)
[[noreturn]] static void usage(void);
static void run(int, const char *);
-static uint16_t strtou16(const char8_t *, rune *);
struct config cfg = {
.seed = UINT16_MAX + 1,
@@ -42,46 +60,69 @@ static const char *argv0;
void
usage(void)
{
- fprintf(stderr, "Usage: %s [file]\n", argv0);
+ fprintf(stderr,
+ "Usage: %s [-c clock speed] [-s seed] [file]\n"
+ " %s -h\n",
+ argv0, argv0);
exit(EXIT_FAILURE);
}
+#define NUMERIC_ARG(T, M, FMT, F, DST, N) \
+ do { \
+ rune ch; \
+ T n = F(optarg, &ch); \
+ if (ch >= '0' && ch <= '9') { \
+ warnx(N " too high; may not exceed %" FMT, M); \
+ usage(); \
+ } else if (ch) { \
+ char8_t buf[U8_LEN_MAX]; \
+ int w = rtou8(buf, ch, sizeof(buf)); \
+ warnx("invalid character ‘%.*s’; " N " must be numeric", w, buf); \
+ usage(); \
+ } \
+ cfg.DST = n; \
+ } while (false)
+
int
main(int argc, char **argv)
{
int opt;
const struct option longopts[] = {
- {"help", no_argument, nullptr, 'h'},
- {"seed", required_argument, nullptr, 's'},
- {nullptr, no_argument, nullptr, 0 },
+ {"clock-speed", required_argument, nullptr, 'c'},
+ {"help", no_argument, nullptr, 'h'},
+ {"seed", required_argument, nullptr, 's'},
+ {nullptr, no_argument, nullptr, 0 },
};
argv0 = argv[0];
cerrinit(*argv);
- while ((opt = getopt_long(argc, argv, "hs:", longopts, nullptr)) != -1) {
+ while ((opt = getopt_long(argc, argv, "c:hs:", longopts, nullptr)) != -1) {
switch (opt) {
case 'h':
execlp("man", "man", "1", argv[0], nullptr);
die("execlp: man 1 %s", argv[0]);
- case 's': {
- rune ch;
- uint16_t n = strtou16(optarg, &ch);
- if (ch >= '0' && ch <= '9')
- diex("seed too large; may not exceed %" PRIu16, UINT16_MAX);
- else if (ch) {
- char8_t buf[U8_LEN_MAX];
- int w = rtou8(buf, ch, sizeof(buf));
- diex("invalid character ‘%.*s’; seed must be numeric", w, buf);
+ case 'c':
+ NUMERIC_ARG(unsigned, UINT_MAX, "u", strtou, cpu_hz,
+ "cpu clock speed");
+ if (cfg.cpu_hz < FPS) {
+ warnx("cpu clock speed may not be lower than the framerate (%d "
+ "FPS)",
+ FPS);
+ usage();
}
- cfg.seed = n;
break;
- }
+ case 's':
+ NUMERIC_ARG(uint16_t, UINT16_MAX, PRIu16, strtou16, seed, "seed");
+ break;
default:
usage();
}
}
+ if (!cfg.cpu_hz)
+ cfg.cpu_hz = 700;
+
argc -= optind;
argv += optind;
@@ -147,7 +188,7 @@ run(int fd, const char *fn)
continue;
st = SDL_GetPerformanceCounter();
- for (int i = 0; i < INSTS_PER_SEC / FPS; i++)
+ for (unsigned i = 0; i < cfg.cpu_hz / FPS; i++)
emutick();
et = SDL_GetPerformanceCounter();
dt = (double)((et - st) * 1000) / SDL_GetPerformanceFrequency();
@@ -169,20 +210,3 @@ run(int fd, const char *fn)
u8strfree(sb);
winfree();
}
-
-uint16_t
-strtou16(const char8_t *s, rune *ch)
-{
- uint16_t n = 0;
- size_t len = strlen(s);
-
- while (u8next(ch, &s, &len)) {
- if (!(*ch >= '0' && *ch <= '9'))
- return -1;
- if (ckd_mul(&n, n, 10) || ckd_add(&n, n, *ch - '0'))
- return -1;
- }
-
- *ch = '\0';
- return n;
-}