aboutsummaryrefslogtreecommitdiffstats
path: root/src/uxn/uxn.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/uxn/uxn.c')
-rw-r--r--src/uxn/uxn.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/uxn/uxn.c b/src/uxn/uxn.c
new file mode 100644
index 0000000..796a980
--- /dev/null
+++ b/src/uxn/uxn.c
@@ -0,0 +1,196 @@
1#include <stdio.h>
2#include "uxn.h"
3
4/*
5Copyright (u) 2021 Devine Lu Linvega
6
7Permission to use, copy, modify, and distribute this software for any
8purpose with or without fee is hereby granted, provided that the above
9copyright notice and this permission notice appear in all copies.
10
11THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12WITH REGARD TO THIS SOFTWARE.
13*/
14
15#pragma mark - Operations
16
17/* clang-format off */
18void push8(Stack *s, Uint8 a) { if (s->ptr == 0xff) { s->error = 2; return; } s->dat[s->ptr++] = a; }
19Uint8 pop8_keep(Stack *s) { if (s->kptr == 0) { s->error = 1; return 0; } return s->dat[--s->kptr]; }
20Uint8 pop8_nokeep(Stack *s) { if (s->ptr == 0) { s->error = 1; return 0; } return s->dat[--s->ptr]; }
21static Uint8 (*pop8)(Stack *s);
22void mempoke8(Uint8 *m, Uint16 a, Uint8 b) { m[a] = b; }
23Uint8 mempeek8(Uint8 *m, Uint16 a) { return m[a]; }
24void devpoke8(Device *d, Uint8 a, Uint8 b) { d->dat[a & 0xf] = b; d->talk(d, a & 0x0f, 1); }
25Uint8 devpeek8(Device *d, Uint8 a) { d->talk(d, a & 0x0f, 0); return d->dat[a & 0xf]; }
26void push16(Stack *s, Uint16 a) { push8(s, a >> 8); push8(s, a); }
27Uint16 pop16(Stack *s) { return pop8(s) + (pop8(s) << 8); }
28void mempoke16(Uint8 *m, Uint16 a, Uint16 b) { mempoke8(m, a, b >> 8); mempoke8(m, a + 1, b); }
29Uint16 mempeek16(Uint8 *m, Uint16 a) { return (mempeek8(m, a) << 8) + mempeek8(m, a + 1); }
30void devpoke16(Device *d, Uint8 a, Uint16 b) { devpoke8(d, a, b >> 8); devpoke8(d, a + 1, b); }
31Uint16 devpeek16(Device *d, Uint16 a) { return (devpeek8(d, a) << 8) + devpeek8(d, a + 1); }
32/* Stack */
33void op_brk(Uxn *u) { u->ram.ptr = 0; }
34void op_nop(Uxn *u) { (void)u; }
35void op_lit(Uxn *u) { push8(u->src, mempeek8(u->ram.dat, u->ram.ptr++)); }
36void op_pop(Uxn *u) { pop8(u->src); }
37void op_dup(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, a); push8(u->src, a); }
38void op_swp(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, a); push8(u->src, b); }
39void op_ovr(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b); push8(u->src, a); push8(u->src, b); }
40void op_rot(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src), c = pop8(u->src); push8(u->src, b); push8(u->src, a); push8(u->src, c); }
41/* Logic */
42void op_equ(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b == a); }
43void op_neq(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b != a); }
44void op_gth(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b > a); }
45void op_lth(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b < a); }
46void op_jmp(Uxn *u) { Uint8 a = pop8(u->src); u->ram.ptr += (Sint8)a; }
47void op_jnz(Uxn *u) { Uint8 a = pop8(u->src); if (pop8(u->src)) u->ram.ptr += (Sint8)a; }
48void op_jsr(Uxn *u) { Uint8 a = pop8(u->src); push16(u->dst, u->ram.ptr); u->ram.ptr += (Sint8)a; }
49void op_sth(Uxn *u) { Uint8 a = pop8(u->src); push8(u->dst, a); }
50/* Memory */
51void op_pek(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, mempeek8(u->ram.dat, a)); }
52void op_pok(Uxn *u) { Uint8 a = pop8(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, a, b); }
53void op_ldr(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, mempeek8(u->ram.dat, u->ram.ptr + (Sint8)a)); }
54void op_str(Uxn *u) { Uint8 a = pop8(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, u->ram.ptr + (Sint8)a, b); }
55void op_lda(Uxn *u) { Uint16 a = pop16(u->src); push8(u->src, mempeek8(u->ram.dat, a)); }
56void op_sta(Uxn *u) { Uint16 a = pop16(u->src); Uint8 b = pop8(u->src); mempoke8(u->ram.dat, a, b); }
57void op_dei(Uxn *u) { Uint8 a = pop8(u->src); push8(u->src, devpeek8(&u->dev[a >> 4], a)); }
58void op_deo(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); devpoke8(&u->dev[a >> 4], a, b); }
59/* Arithmetic */
60void op_add(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b + a); }
61void op_sub(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b - a); }
62void op_mul(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b * a); }
63void op_div(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b / a); }
64void op_and(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b & a); }
65void op_ora(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b | a); }
66void op_eor(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b ^ a); }
67void op_sft(Uxn *u) { Uint8 a = pop8(u->src), b = pop8(u->src); push8(u->src, b >> (a & 0x07) << ((a & 0x70) >> 4)); }
68/* Stack */
69void op_lit16(Uxn *u) { push16(u->src, mempeek16(u->ram.dat, u->ram.ptr++)); u->ram.ptr++; }
70void op_pop16(Uxn *u) { pop16(u->src); }
71void op_dup16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->src, a); push16(u->src, a); }
72void op_swp16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, a); push16(u->src, b); }
73void op_ovr16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b); push16(u->src, a); push16(u->src, b); }
74void op_rot16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src), c = pop16(u->src); push16(u->src, b); push16(u->src, a); push16(u->src, c); }
75/* Logic(16-bits) */
76void op_equ16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b == a); }
77void op_neq16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b != a); }
78void op_gth16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b > a); }
79void op_lth16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push8(u->src, b < a); }
80void op_jmp16(Uxn *u) { u->ram.ptr = pop16(u->src); }
81void op_jnz16(Uxn *u) { Uint16 a = pop16(u->src); if (pop8(u->src)) u->ram.ptr = a; }
82void op_jsr16(Uxn *u) { push16(u->dst, u->ram.ptr); u->ram.ptr = pop16(u->src); }
83void op_sth16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->dst, a); }
84/* Memory(16-bits) */
85void op_pek16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, mempeek16(u->ram.dat, a)); }
86void op_pok16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, a, b); }
87void op_ldr16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, mempeek16(u->ram.dat, u->ram.ptr + (Sint8)a)); }
88void op_str16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, u->ram.ptr + (Sint8)a, b); }
89void op_lda16(Uxn *u) { Uint16 a = pop16(u->src); push16(u->src, mempeek16(u->ram.dat, a)); }
90void op_sta16(Uxn *u) { Uint16 a = pop16(u->src); Uint16 b = pop16(u->src); mempoke16(u->ram.dat, a, b); }
91void op_dei16(Uxn *u) { Uint8 a = pop8(u->src); push16(u->src, devpeek16(&u->dev[a >> 4], a)); }
92void op_deo16(Uxn *u) { Uint8 a = pop8(u->src); Uint16 b = pop16(u->src); devpoke16(&u->dev[a >> 4], a, b); }
93/* Arithmetic(16-bits) */
94void op_add16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b + a); }
95void op_sub16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b - a); }
96void op_mul16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b * a); }
97void op_div16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b / a); }
98void op_and16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b & a); }
99void op_ora16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b | a); }
100void op_eor16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b ^ a); }
101void op_sft16(Uxn *u) { Uint16 a = pop16(u->src), b = pop16(u->src); push16(u->src, b >> (a & 0x000f) << ((a & 0x00f0) >> 4)); }
102
103void (*ops[])(Uxn *u) = {
104 op_brk, op_lit, op_nop, op_pop, op_dup, op_swp, op_ovr, op_rot,
105 op_equ, op_neq, op_gth, op_lth, op_jmp, op_jnz, op_jsr, op_sth,
106 op_pek, op_pok, op_ldr, op_str, op_lda, op_sta, op_dei, op_deo,
107 op_add, op_sub, op_mul, op_div, op_and, op_ora, op_eor, op_sft,
108 /* 16-bit */
109 op_brk, op_lit16, op_nop, op_pop16, op_dup16, op_swp16, op_ovr16, op_rot16,
110 op_equ16, op_neq16, op_gth16, op_lth16, op_jmp16, op_jnz16, op_jsr16, op_sth16,
111 op_pek16, op_pok16, op_ldr16, op_str16, op_lda16, op_sta16, op_dei16, op_deo16,
112 op_add16, op_sub16, op_mul16, op_div16, op_and16, op_ora16, op_eor16, op_sft16
113};
114
115/* clang-format on */
116
117#pragma mark - Core
118
119int
120haltuxn(Uxn *u, char *name, int id)
121{
122 txt_printf("Halted: %s#%04x, at 0x%04x\n", name, id, u->ram.ptr);
123 u->ram.ptr = 0;
124 return 0;
125}
126
127void
128opcuxn(Uxn *u, Uint8 instr)
129{
130 Uint8 op = instr & 0x3f, freturn = instr & 0x40, fkeep = instr & 0x80;
131 u->src = freturn ? &u->rst : &u->wst;
132 u->dst = freturn ? &u->wst : &u->rst;
133 if(fkeep) {
134 pop8 = pop8_keep;
135 u->src->kptr = u->src->ptr;
136 } else {
137 pop8 = pop8_nokeep;
138 }
139 (*ops[op])(u);
140}
141
142int
143stepuxn(Uxn *u, Uint8 instr)
144{
145 opcuxn(u, instr);
146 if(u->wst.error)
147 return haltuxn(u, u->wst.error == 1 ? "Working-stack underflow" : "Working-stack overflow", instr);
148 if(u->rst.error)
149 return haltuxn(u, u->rst.error == 1 ? "Return-stack underflow" : "Return-stack overflow", instr);
150 return 1;
151}
152
153int
154evaluxn(Uxn *u, Uint16 vec)
155{
156 u->ram.ptr = vec;
157 u->wst.error = 0;
158 u->rst.error = 0;
159 while(u->ram.ptr)
160 if(!stepuxn(u, u->ram.dat[u->ram.ptr++]))
161 return 0;
162 return 1;
163}
164
165int
166bootuxn(Uxn *u)
167{
168 size_t i;
169 char *cptr = (char *)u;
170 for(i = 0; i < sizeof(*u); i++)
171 cptr[i] = 0;
172 return 1;
173}
174
175int
176loaduxn(Uxn *u, char *filepath)
177{
178 FILE *f;
179 if(!(f = fopen(filepath, "rb")))
180 return haltuxn(u, "Missing input rom.", 0);
181 fread(u->ram.dat + PAGE_PROGRAM, sizeof(u->ram.dat) - PAGE_PROGRAM, 1, f);
182 txt_printf("Uxn loaded[%s].\n", filepath);
183 return 1;
184}
185
186Device *
187portuxn(Uxn *u, Uint8 id, char *name, void (*talkfn)(Device *d, Uint8 b0, Uint8 w))
188{
189 Device *d = &u->dev[id];
190 d->addr = id * 0x10;
191 d->u = u;
192 d->mem = u->ram.dat;
193 d->talk = talkfn;
194 txt_printf("Device added #%02x: %s, at 0x%04x \n", id, name, d->addr);
195 return d;
196}