mirror of https://git.sr.ht/~rabbits/uxn
13 changed files with 0 additions and 1109 deletions
@ -1,119 +0,0 @@
|
||||
#!/bin/sh |
||||
set -e |
||||
cd "$(dirname "${0}")/.." |
||||
rm -rf asma-test |
||||
mkdir asma-test |
||||
|
||||
expect_failure() { |
||||
cat > asma-test/in.tal |
||||
bin/uxncli asma-test/asma.rom asma-test/in.tal asma-test/out.rom 2> asma-test/asma.log |
||||
if ! grep -qF "${1}" asma-test/asma.log; then |
||||
echo "error: asma didn't report error ${1} in faulty code" |
||||
cat asma-test/asma.log |
||||
exit 1 |
||||
fi |
||||
} |
||||
|
||||
echo 'Assembling asma with uxnasm' |
||||
if ! bin/uxnasm projects/software/asma.tal asma-test/asma.rom > asma-test/uxnasm.log; then |
||||
echo 'Failed to assemble asma!' |
||||
cat asma-test/uxnasm.log |
||||
exit 1 |
||||
fi |
||||
for F in $(find projects -path projects/library -prune -false -or -path projects/assets -prune -false -or -type f -name '*.tal' | sort); do |
||||
echo "Comparing assembly of ${F}" |
||||
|
||||
UASM_BASE="asma-test/uxnasm-$(basename "${F%.tal}")" |
||||
if ! bin/uxnasm "${F}" "${UASM_BASE}.rom" 2> "${UASM_BASE}.log"; then |
||||
echo "error: uxnasm failed to assemble ${F}" |
||||
cat "${UASM_BASE}.log" |
||||
exit 1 |
||||
fi |
||||
xxd "${UASM_BASE}.rom" > "${UASM_BASE}.hex" |
||||
|
||||
ASMA_BASE="asma-test/asma-$(basename "${F%.tal}")" |
||||
bin/uxncli asma-test/asma.rom "${F}" "${ASMA_BASE}.rom" 2> "${ASMA_BASE}.log" |
||||
if ! grep -qF 'bytes of heap used' "${ASMA_BASE}.log"; then |
||||
echo "error: asma failed to assemble ${F}, while uxnasm succeeded" |
||||
cat "${ASMA_BASE}.log" |
||||
exit 1 |
||||
fi |
||||
xxd "${ASMA_BASE}.rom" > "${ASMA_BASE}.hex" |
||||
|
||||
diff -u "${UASM_BASE}.hex" "${ASMA_BASE}.hex" |
||||
done |
||||
expect_failure 'Invalid hexadecimal: $defg' <<'EOD' |
||||
|1000 $defg |
||||
EOD |
||||
expect_failure 'Invalid hexadecimal: #defg' <<'EOD' |
||||
|1000 #defg |
||||
EOD |
||||
expect_failure 'Invalid hexadecimal: #' <<'EOD' |
||||
|1000 # |
||||
EOD |
||||
expect_failure 'Invalid hexadecimal: #0' <<'EOD' |
||||
|1000 #0 |
||||
EOD |
||||
expect_failure 'Invalid hexadecimal: #000' <<'EOD' |
||||
|1000 #000 |
||||
EOD |
||||
expect_failure 'Label not found: 0' <<'EOD' |
||||
|1000 0 |
||||
EOD |
||||
expect_failure 'Label not found: 000' <<'EOD' |
||||
|1000 000 |
||||
EOD |
||||
expect_failure 'Address not in zero page: .hello' <<'EOD' |
||||
|1000 @hello |
||||
.hello |
||||
EOD |
||||
expect_failure 'Address not in zero page: -hello' <<'EOD' |
||||
|1000 @hello |
||||
-hello |
||||
EOD |
||||
expect_failure 'Address outside range: ,hello' <<'EOD' |
||||
|1000 @hello |
||||
|2000 ,hello |
||||
EOD |
||||
expect_failure 'Label not found: hello' <<'EOD' |
||||
hello |
||||
EOD |
||||
expect_failure 'Macro already exists: %me' <<'EOD' |
||||
%me { #00 } |
||||
%me { #01 } |
||||
EOD |
||||
expect_failure 'Memory overwrite: SUB' <<'EOD' |
||||
|2000 ADD |
||||
|1000 SUB |
||||
EOD |
||||
# expect_failure 'Recursion level too deep:' <<'EOD' |
||||
# %me { you } |
||||
# %you { me } |
||||
# |1000 me |
||||
# EOD |
||||
# expect_failure 'Recursion level too deep: ~asma-test/in.tal' <<'EOD' |
||||
# ~asma-test/in.tal |
||||
# EOD |
||||
expect_failure 'Label not found: ;blah' <<'EOD' |
||||
|1000 ;blah |
||||
EOD |
||||
expect_failure 'Label not found: :blah' <<'EOD' |
||||
|1000 :blah |
||||
EOD |
||||
expect_failure 'Label not found: =blah' <<'EOD' |
||||
|1000 =blah |
||||
EOD |
||||
expect_failure 'Label not found: -blah' <<'EOD' |
||||
|1000 -blah |
||||
EOD |
||||
expect_failure 'Label not found: ,blah' <<'EOD' |
||||
|1000 ,blah |
||||
EOD |
||||
expect_failure 'Label not found: .blah' <<'EOD' |
||||
|1000 .blah |
||||
EOD |
||||
expect_failure "Label not found: 'a" <<'EOD' |
||||
|1000 'a |
||||
EOD |
||||
echo 'All OK' |
||||
|
||||
@ -1,103 +0,0 @@
|
||||
local output = assert(io.open('.asma.tal', 'w')) |
||||
local process_subtree |
||||
process_subtree = function(items) |
||||
local middle = math.floor(#items / 2 + 1.25) |
||||
local node = items[middle] |
||||
if not node then |
||||
return |
||||
end |
||||
node.left = process_subtree((function() |
||||
local _accum_0 = { } |
||||
local _len_0 = 1 |
||||
for i, item in ipairs(items) do |
||||
if i < middle then |
||||
_accum_0[_len_0] = item |
||||
_len_0 = _len_0 + 1 |
||||
end |
||||
end |
||||
return _accum_0 |
||||
end)()) |
||||
node.right = process_subtree((function() |
||||
local _accum_0 = { } |
||||
local _len_0 = 1 |
||||
for i, item in ipairs(items) do |
||||
if i > middle then |
||||
_accum_0[_len_0] = item |
||||
_len_0 = _len_0 + 1 |
||||
end |
||||
end |
||||
return _accum_0 |
||||
end)()) |
||||
return node |
||||
end |
||||
local process_tree |
||||
process_tree = function(items) |
||||
local sorted_items |
||||
do |
||||
local _accum_0 = { } |
||||
local _len_0 = 1 |
||||
for _index_0 = 1, #items do |
||||
local item = items[_index_0] |
||||
_accum_0[_len_0] = item |
||||
_len_0 = _len_0 + 1 |
||||
end |
||||
sorted_items = _accum_0 |
||||
end |
||||
table.sort(sorted_items, function(a, b) |
||||
return a.order < b.order |
||||
end); |
||||
(process_subtree(sorted_items)).label = '&_entry' |
||||
for _index_0 = 1, #items do |
||||
local item = items[_index_0] |
||||
output:write(('\t%-11s %-10s %-12s %s%s\n'):format(item.label, item.left and item.left.ref or ' $2', (item.right and item.right.ref or ' $2') .. item.extra, item.key, item.rest)) |
||||
end |
||||
end |
||||
local parse_tree |
||||
parse_tree = function(it) |
||||
local items = { } |
||||
for l in it do |
||||
if l == '' then |
||||
process_tree(items) |
||||
output:write('\n') |
||||
return |
||||
end |
||||
local item = { |
||||
extra = '' |
||||
} |
||||
item.key, item.rest = l:match('^%s*%S+%s+%S+%s+%S+%s+(%S+)(.*)') |
||||
if item.key:match('^%&') then |
||||
item.extra = (' %s'):format(item.key) |
||||
item.key, item.rest = item.rest:match('^%s+(%S+)(.*)') |
||||
end |
||||
if item.key:match('^%"') then |
||||
item.order = item.key:sub(2) |
||||
elseif item.key:match('^%x%x') then |
||||
item.order = string.char(tonumber(item.key, 16)) |
||||
else |
||||
error(('unknown key: %q'):format(item.key)) |
||||
end |
||||
if item.order:match('^%a') then |
||||
item.label = ('&%s'):format(item.order) |
||||
elseif item.order:match('^.$') then |
||||
item.label = ('&%x'):format(item.order:byte()) |
||||
else |
||||
error(('unknown label: %q'):format(item.order)) |
||||
end |
||||
item.ref = (':%s'):format(item.label) |
||||
table.insert(items, item) |
||||
end |
||||
end |
||||
local it = assert(io.lines('projects/library/asma.tal')) |
||||
local waiting_for_cut = true |
||||
for l in it do |
||||
output:write(l) |
||||
output:write('\n') |
||||
if l:find('--- cut here ---', 1, true) then |
||||
waiting_for_cut = false |
||||
end |
||||
if not waiting_for_cut and '@' == l:sub(1, 1) then |
||||
parse_tree(it) |
||||
end |
||||
end |
||||
output:close() |
||||
return os.execute('mv .asma.tal projects/library/asma.tal') |
||||
@ -1,74 +0,0 @@
|
||||
-- |
||||
-- Asma tree helper script |
||||
-- |
||||
-- This script balances the trees at the end of projects/library/asma.tal. |
||||
-- |
||||
-- To run, you need Lua or LuaJIT, and just run etc/asma.lua from the top |
||||
-- directory of Uxn's git repository: |
||||
-- |
||||
-- lua etc/asma.lua |
||||
-- |
||||
-- This file is written in MoonScript, which is a language that compiles to |
||||
-- Lua, the same way as e.g. CoffeeScript compiles to JavaScript. Since |
||||
-- installing MoonScript has more dependencies than Lua, the compiled |
||||
-- etc/asma.lua is kept in Uxn's repository and will be kept updated as this |
||||
-- file changes. |
||||
-- |
||||
|
||||
output = assert io.open '.asma.tal', 'w' |
||||
|
||||
process_subtree = (items) -> |
||||
middle = math.floor #items / 2 + 1.25 |
||||
node = items[middle] |
||||
if not node |
||||
return |
||||
node.left = process_subtree [ item for i, item in ipairs items when i < middle ] |
||||
node.right = process_subtree [ item for i, item in ipairs items when i > middle ] |
||||
node |
||||
|
||||
process_tree = (items) -> |
||||
sorted_items = [ item for item in *items ] |
||||
table.sort sorted_items, (a, b) -> a.order < b.order |
||||
(process_subtree sorted_items).label = '&_entry' |
||||
for item in *items |
||||
output\write '\t%-11s %-10s %-12s %s%s\n'\format item.label, item.left and item.left.ref or ' $2', (item.right and item.right.ref or ' $2') .. item.extra, item.key, item.rest |
||||
|
||||
parse_tree = (it) -> |
||||
items = {} |
||||
for l in it |
||||
if l == '' |
||||
process_tree items |
||||
output\write '\n' |
||||
return |
||||
item = { extra: '' } |
||||
item.key, item.rest = l\match '^%s*%S+%s+%S+%s+%S+%s+(%S+)(.*)' |
||||
if item.key\match '^%&' |
||||
item.extra = ' %s'\format item.key |
||||
item.key, item.rest = item.rest\match '^%s+(%S+)(.*)' |
||||
if item.key\match '^%"' |
||||
item.order = item.key\sub 2 |
||||
elseif item.key\match '^%x%x' |
||||
item.order = string.char tonumber item.key, 16 |
||||
else |
||||
error 'unknown key: %q'\format item.key |
||||
if item.order\match '^%a' |
||||
item.label = '&%s'\format item.order |
||||
elseif item.order\match '^.$' |
||||
item.label = '&%x'\format item.order\byte! |
||||
else |
||||
error 'unknown label: %q'\format item.order |
||||
item.ref = ':%s'\format item.label |
||||
table.insert items, item |
||||
|
||||
it = assert io.lines 'projects/library/asma.tal' |
||||
waiting_for_cut = true |
||||
for l in it |
||||
output\write l |
||||
output\write '\n' |
||||
if l\find '--- cut here ---', 1, true |
||||
waiting_for_cut = false |
||||
if not waiting_for_cut and '@' == l\sub 1, 1 |
||||
parse_tree it |
||||
output\close! |
||||
os.execute 'mv .asma.tal projects/library/asma.tal' |
||||
|
||||
@ -1,11 +0,0 @@
|
||||
pcm.!default { |
||||
type file |
||||
slave.pcm null |
||||
file /proc/self/fd/3 |
||||
format "raw" |
||||
} |
||||
|
||||
pcm.null { |
||||
type null |
||||
} |
||||
|
||||
@ -1,332 +0,0 @@
|
||||
#define _GNU_SOURCE |
||||
|
||||
#include <errno.h> |
||||
#include <fcntl.h> |
||||
#include <math.h> |
||||
#include <signal.h> |
||||
#include <stdarg.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <sys/select.h> |
||||
#include <sys/stat.h> |
||||
#include <sys/time.h> |
||||
#include <sys/types.h> |
||||
#include <sys/wait.h> |
||||
#include <unistd.h> |
||||
|
||||
#define WIDTH 512 |
||||
#define HEIGHT 320 |
||||
|
||||
#define str(x) stra(x) |
||||
#define stra(x) #x |
||||
|
||||
#define die(fnname) \ |
||||
do { \
|
||||
perror(fnname); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} while(0) |
||||
|
||||
#define x(fn, ...) \ |
||||
do { \
|
||||
if(fn(__VA_ARGS__) < 0) { \
|
||||
perror(#fn); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
} while(0) |
||||
|
||||
int fix_fft(short *fr, short *fi, short m, short inverse); |
||||
|
||||
static pid_t |
||||
launch_xvfb(void) |
||||
{ |
||||
char displayfd[16]; |
||||
int r; |
||||
pid_t pid; |
||||
int fds[2]; |
||||
x(pipe2, &fds[0], 0); |
||||
pid = fork(); |
||||
if(pid < 0) { |
||||
die("fork"); |
||||
} else if(!pid) { |
||||
x(snprintf, displayfd, sizeof(displayfd), "%d", fds[1]); |
||||
x(close, fds[0]); |
||||
execlp("Xvfb", "Xvfb", "-screen", "0", str(WIDTH) "x" str(HEIGHT) "x24", "-fbdir", ".", "-displayfd", displayfd, "-nolisten", "tcp", NULL); |
||||
die("execl"); |
||||
exit(EXIT_FAILURE); |
||||
} |
||||
x(close, fds[1]); |
||||
r = read(fds[0], &displayfd[1], sizeof(displayfd) - 1); |
||||
if(r < 0) die("read"); |
||||
x(close, fds[0]); |
||||
displayfd[r] = '\0'; |
||||
displayfd[0] = ':'; |
||||
x(setenv, "DISPLAY", displayfd, 1); |
||||
x(setenv, "ALSA_CONFIG_PATH", "asoundrc", 1); |
||||
return pid; |
||||
} |
||||
|
||||
static pid_t |
||||
launch_uxnemu(int *write_fd, int *read_fd, int *sound_fd) |
||||
{ |
||||
pid_t pid; |
||||
int fds[6]; |
||||
x(pipe2, &fds[0], O_CLOEXEC); |
||||
x(pipe2, &fds[2], O_CLOEXEC); |
||||
x(pipe2, &fds[4], O_CLOEXEC); |
||||
pid = fork(); |
||||
if(pid < 0) { |
||||
die("fork"); |
||||
} else if(!pid) { |
||||
x(dup2, fds[0], 0); |
||||
x(dup2, fds[3], 1); |
||||
x(dup2, fds[5], 3); |
||||
execl("../../bin/uxnemu", "uxnemu", "autotest.rom", NULL); |
||||
die("execl"); |
||||
} |
||||
x(close, fds[0]); |
||||
x(close, fds[3]); |
||||
x(close, fds[5]); |
||||
*write_fd = fds[1]; |
||||
*read_fd = fds[2]; |
||||
*sound_fd = fds[4]; |
||||
return pid; |
||||
} |
||||
|
||||
static void |
||||
terminate(pid_t pid) |
||||
{ |
||||
int signals[] = {SIGINT, SIGTERM, SIGKILL}; |
||||
int status; |
||||
size_t i; |
||||
for(i = 0; i < sizeof(signals) / sizeof(int) * 10; ++i) { |
||||
if(kill(pid, signals[i / 10])) { |
||||
break; |
||||
} |
||||
usleep(100000); |
||||
if(pid == waitpid(pid, &status, WNOHANG)) { |
||||
return; |
||||
} |
||||
} |
||||
waitpid(pid, &status, 0); |
||||
} |
||||
|
||||
static int |
||||
open_framebuffer(void) |
||||
{ |
||||
for(;;) { |
||||
int fd = open("Xvfb_screen0", O_RDONLY | O_CLOEXEC); |
||||
if(fd >= 0) { |
||||
return fd; |
||||
} |
||||
if(errno != ENOENT) { |
||||
perror("open"); |
||||
return fd; |
||||
} |
||||
usleep(100000); |
||||
} |
||||
} |
||||
|
||||
#define PPM_HEADER "P6\n" str(WIDTH) " " str(HEIGHT) "\n255\n" |
||||
|
||||
static void |
||||
save_screenshot(int fb_fd, const char *filename) |
||||
{ |
||||
unsigned char screen[WIDTH * HEIGHT * 4 + 4]; |
||||
int fd = open(filename, O_WRONLY | O_CREAT, 0666); |
||||
int i; |
||||
if(fd < 0) { |
||||
die("screenshot open"); |
||||
} |
||||
x(write, fd, PPM_HEADER, strlen(PPM_HEADER)); |
||||
x(lseek, fb_fd, 0xca0, SEEK_SET); |
||||
x(read, fb_fd, &screen[4], WIDTH * HEIGHT * 4); |
||||
for(i = 0; i < WIDTH * HEIGHT; ++i) { |
||||
screen[i * 3 + 2] = screen[i * 4 + 4]; |
||||
screen[i * 3 + 1] = screen[i * 4 + 5]; |
||||
screen[i * 3 + 0] = screen[i * 4 + 6]; |
||||
} |
||||
x(write, fd, screen, WIDTH * HEIGHT * 3); |
||||
x(close, fd); |
||||
} |
||||
|
||||
static void |
||||
systemf(char *format, ...) |
||||
{ |
||||
char *command; |
||||
va_list ap; |
||||
va_start(ap, format); |
||||
x(vasprintf, &command, format, ap); |
||||
system(command); |
||||
free(command); |
||||
} |
||||
|
||||
int uxn_read_fd, sound_fd; |
||||
|
||||
static int |
||||
byte(void) |
||||
{ |
||||
char c; |
||||
if(read(uxn_read_fd, &c, 1) != 1) { |
||||
return 0; |
||||
} |
||||
return (unsigned char)c; |
||||
} |
||||
|
||||
#define NEW_FFT_SIZE_POW2 10 |
||||
#define NEW_FFT_SIZE (1 << NEW_FFT_SIZE_POW2) |
||||
#define NEW_FFT_USEC (5000 * NEW_FFT_SIZE / 441) |
||||
|
||||
unsigned char left_peak, right_peak; |
||||
|
||||
static int |
||||
detect_peak(short *real, short *imag) |
||||
{ |
||||
int i, peak = 0, peak_i; |
||||
for(i = 0; i < NEW_FFT_SIZE; ++i) { |
||||
int v = real[i] * real[i] + imag[i] * imag[i]; |
||||
if(peak < v) { |
||||
peak = v; |
||||
peak_i = i; |
||||
} else if(peak > v * 10) { |
||||
return peak_i; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static int |
||||
analyse_sound(short *samples) |
||||
{ |
||||
short real[NEW_FFT_SIZE], imag[NEW_FFT_SIZE]; |
||||
int i; |
||||
for(i = 0; i < NEW_FFT_SIZE * 2; ++i) { |
||||
if(samples[i * 2]) break; |
||||
} |
||||
if(i == NEW_FFT_SIZE * 2) return 0; |
||||
for(i = 0; i < NEW_FFT_SIZE; ++i) { |
||||
real[i] = samples[i * 4]; |
||||
imag[i] = samples[i * 4 + 2]; |
||||
} |
||||
fix_fft(real, imag, NEW_FFT_SIZE_POW2, 0); |
||||
return detect_peak(real, imag); |
||||
} |
||||
|
||||
static int |
||||
read_sound(void) |
||||
{ |
||||
static short samples[NEW_FFT_SIZE * 4]; |
||||
static size_t len = 0; |
||||
int r = read(sound_fd, ((char *)samples) + len, sizeof(samples) - len); |
||||
if(r > 0) { |
||||
len += r; |
||||
if(len == sizeof(samples)) { |
||||
left_peak = analyse_sound(&samples[0]); |
||||
right_peak = analyse_sound(&samples[1]); |
||||
len = 0; |
||||
return 1; |
||||
} |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
static void |
||||
main_loop(int uxn_write_fd, int fb_fd) |
||||
{ |
||||
struct timeval next_sound = {0, 0}; |
||||
for(;;) { |
||||
struct timeval now; |
||||
struct timeval *timeout; |
||||
fd_set fds; |
||||
FD_ZERO(&fds); |
||||
FD_SET(uxn_read_fd, &fds); |
||||
x(gettimeofday, &now, NULL); |
||||
if(now.tv_sec > next_sound.tv_sec || (now.tv_sec == next_sound.tv_sec && now.tv_usec > next_sound.tv_usec)) { |
||||
FD_SET(sound_fd, &fds); |
||||
timeout = NULL; |
||||
} else { |
||||
now.tv_sec = 0; |
||||
now.tv_usec = NEW_FFT_USEC; |
||||
timeout = &now; |
||||
} |
||||
x(select, uxn_read_fd > sound_fd ? uxn_read_fd + 1 : sound_fd + 1, &fds, NULL, NULL, timeout); |
||||
if(FD_ISSET(uxn_read_fd, &fds)) { |
||||
int c, x, y; |
||||
unsigned char blue; |
||||
switch(c = byte()) { |
||||
case 0x00: /* also used for EOF */ |
||||
printf("exiting\n"); |
||||
return; |
||||
/* 01-06 mouse */ |
||||
case 0x01 ... 0x05: |
||||
systemf("xdotool click %d", c); |
||||
break; |
||||
case 0x06: |
||||
x = (byte() << 8) | byte(); |
||||
y = (byte() << 8) | byte(); |
||||
systemf("xdotool mousemove %d %d", x, y); |
||||
break; |
||||
/* 07-08 Screen */ |
||||
case 0x07: |
||||
x = (byte() << 8) | byte(); |
||||
y = (byte() << 8) | byte(); |
||||
lseek(fb_fd, 0xca0 + (x + y * WIDTH) * 4, SEEK_SET); |
||||
read(fb_fd, &blue, 1); |
||||
blue = blue / 0x11; |
||||
write(uxn_write_fd, &blue, 1); |
||||
break; |
||||
case 0x08: |
||||
save_screenshot(fb_fd, "test.ppm"); |
||||
break; |
||||
/* 09-0a Audio */ |
||||
case 0x09: |
||||
write(uxn_write_fd, &left_peak, 1); |
||||
break; |
||||
case 0x0a: |
||||
write(uxn_write_fd, &right_peak, 1); |
||||
break; |
||||
/* 11-7e Controller/key */ |
||||
case 0x11 ... 0x1c: |
||||
systemf("xdotool key F%d", c - 0x10); |
||||
break; |
||||
case '0' ... '9': |
||||
case 'A' ... 'Z': |
||||
case 'a' ... 'z': |
||||
systemf("xdotool key %c", c); |
||||
break; |
||||
default: |
||||
printf("unhandled command 0x%02x\n", c); |
||||
break; |
||||
} |
||||
} |
||||
if(FD_ISSET(sound_fd, &fds)) { |
||||
if(!next_sound.tv_sec) { |
||||
x(gettimeofday, &next_sound, NULL); |
||||
} |
||||
next_sound.tv_usec += NEW_FFT_USEC * read_sound(); |
||||
if(next_sound.tv_usec > 1000000) { |
||||
next_sound.tv_usec -= 1000000; |
||||
++next_sound.tv_sec; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
int |
||||
main(void) |
||||
{ |
||||
pid_t xvfb_pid = launch_xvfb(); |
||||
int fb_fd = open_framebuffer(); |
||||
if(fb_fd >= 0) { |
||||
int uxn_write_fd; |
||||
pid_t uxnemu_pid = launch_uxnemu(&uxn_write_fd, &uxn_read_fd, &sound_fd); |
||||
main_loop(uxn_write_fd, fb_fd); |
||||
terminate(uxnemu_pid); |
||||
x(close, uxn_write_fd); |
||||
x(close, uxn_read_fd); |
||||
x(close, sound_fd); |
||||
x(close, fb_fd); |
||||
} |
||||
terminate(xvfb_pid); |
||||
return 0; |
||||
} |
||||
@ -1,20 +0,0 @@
|
||||
#!/bin/sh -e |
||||
cd "$(dirname "${0}")" |
||||
if ! which Xvfb 2>/dev/null; then |
||||
echo "error: ${0} depends on Xvfb" |
||||
exit 1 |
||||
fi |
||||
if ! which xdotool 2>/dev/null; then |
||||
echo "error: ${0} depends on xdotool" |
||||
exit 1 |
||||
fi |
||||
if [ ! -e fix_fft.c ]; then |
||||
wget https://gist.githubusercontent.com/Tomwi/3842231/raw/67149b6ec81cfb6ac1056fd23a3bb6ce1f0a5188/fix_fft.c |
||||
fi |
||||
if which clang-format 2>/dev/null; then |
||||
( cd ../.. && clang-format -i etc/autotest/main.c ) |
||||
fi |
||||
../../bin/uxnasm autotest.tal autotest.rom |
||||
gcc -std=gnu89 -Wall -Wextra -o autotest main.c fix_fft.c -lm |
||||
./autotest |
||||
|
||||
@ -1,85 +0,0 @@
|
||||
#include "uxn.h" |
||||
|
||||
/*
|
||||
Copyright (u) 2022-2023 Devine Lu Linvega, Andrew Alderwick, Andrew Richards |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE. |
||||
*/ |
||||
|
||||
#define FLIP { s = ins & 0x40 ? &u->wst : &u->rst; } |
||||
#define JUMP(x) { if(m2) pc = (x); else pc += (Sint8)(x); } |
||||
#define POP1(o) { o = s->dat[--*sp]; } |
||||
#define POP2(o) { o = s->dat[--*sp] | (s->dat[--*sp] << 0x8); } |
||||
#define POPx(o) { if(m2) { POP2(o) } else POP1(o) } |
||||
#define PUSH1(y) { s->dat[s->ptr++] = (y); } |
||||
#define PUSH2(y) { tt = (y); s->dat[s->ptr++] = tt >> 0x8; s->dat[s->ptr++] = tt; } |
||||
#define PUSHx(y) { if(m2) { PUSH2(y) } else PUSH1(y) } |
||||
#define PEEK(o, x, r) { if(m2) { r = (x); o = ram[r++] << 8 | ram[r]; } else o = ram[(x)]; } |
||||
#define POKE(x, y, r) { if(m2) { r = (x); ram[r++] = y >> 8; ram[r] = y; } else ram[(x)] = (y); } |
||||
#define DEVR(o, p) { if(m2) { o = (emu_dei(u, p) << 8) | emu_dei(u, p + 1); } else o = emu_dei(u, p); } |
||||
#define DEVW(p, y) { if(m2) { emu_deo(u, p, y >> 8); emu_deo(u, p + 1, y); } else emu_deo(u, p, y); } |
||||
#define next { ins = ram[pc++]; \ |
||||
m2 = ins & 0x20; \
|
||||
s = ins & 0x40 ? &u->rst : &u->wst; \
|
||||
if(ins & 0x80) kp = s->ptr, sp = &kp; else sp = &s->ptr; \
|
||||
goto *lut[ins & 0x1f]; } |
||||
|
||||
int |
||||
uxn_eval(Uxn *u, Uint16 pc) |
||||
{ |
||||
Uint8 t, kp, *sp, ins, m2, *ram = u->ram; |
||||
Uint16 tt, a, b, c; |
||||
Stack *s; |
||||
static void* lut[] = { |
||||
&&_imm, &&_inc, &&_pop, &&_nip, &&_swp, &&_rot, &&_dup, &&_ovr, |
||||
&&_equ, &&_neq, &&_gth, &&_lth, &&_jmp, &&_jcn, &&_jsr, &&_sth, |
||||
&&_ldz, &&_stz, &&_ldr, &&_str, &&_lda, &&_sta, &&_dei, &&_deo, |
||||
&&_add, &&_sub, &&_mul, &&_div, &&_and, &&_ora, &&_eor, &&_sft }; |
||||
if(!pc || u->dev[0x0f]) return 0; |
||||
next |
||||
_imm:
|
||||
switch(ins) { |
||||
case 0x00: /* BRK */ return 1; |
||||
case 0x20: /* JCI */ POP1(b) if(!b) { pc += 2; break; } |
||||
case 0x40: /* JMI */ a = ram[pc++] << 8 | ram[pc++]; pc += a; break; |
||||
case 0x60: /* JSI */ PUSH2(pc + 2) a = ram[pc++] << 8 | ram[pc++]; pc += a; break; |
||||
case 0x80: case 0xc0: /* LIT */ PUSH1(ram[pc++]) break; |
||||
case 0xa0: case 0xe0: /* LIT2 */ PUSH1(ram[pc++]) PUSH1(ram[pc++]) break; |
||||
} next |
||||
_inc: POPx(a) PUSHx(a + 1) next |
||||
_pop: POPx(a) next |
||||
_nip: POPx(a) POPx(b) PUSHx(a) next |
||||
_swp: POPx(a) POPx(b) PUSHx(a) PUSHx(b) next |
||||
_rot: POPx(a) POPx(b) POPx(c) PUSHx(b) PUSHx(a) PUSHx(c) next |
||||
_dup: POPx(a) PUSHx(a) PUSHx(a) next |
||||
_ovr: POPx(a) POPx(b) PUSHx(b) PUSHx(a) PUSHx(b) next |
||||
_equ: POPx(a) POPx(b) PUSH1(b == a) next |
||||
_neq: POPx(a) POPx(b) PUSH1(b != a) next |
||||
_gth: POPx(a) POPx(b) PUSH1(b > a) next |
||||
_lth: POPx(a) POPx(b) PUSH1(b < a) next |
||||
_jmp: POPx(a) JUMP(a) next |
||||
_jcn: POPx(a) POP1(b) if(b) JUMP(a) next |
||||
_jsr: POPx(a) FLIP PUSH2(pc) JUMP(a) next |
||||
_sth: POPx(a) FLIP PUSHx(a) next |
||||
_ldz: POP1(a) PEEK(b, a, t) PUSHx(b) next |
||||
_stz: POP1(a) POPx(b) POKE(a, b, t) next |
||||
_ldr: POP1(a) PEEK(b, pc + (Sint8)a, tt) PUSHx(b) next |
||||
_str: POP1(a) POPx(b) POKE(pc + (Sint8)a, b, tt) next |
||||
_lda: POP2(a) PEEK(b, a, tt) PUSHx(b) next |
||||
_sta: POP2(a) POPx(b) POKE(a, b, tt) next |
||||
_dei: POP1(a) DEVR(b, a) PUSHx(b) next |
||||
_deo: POP1(a) POPx(b) DEVW(a, b) next |
||||
_add: POPx(a) POPx(b) PUSHx(b + a) next |
||||
_sub: POPx(a) POPx(b) PUSHx(b - a) next |
||||
_mul: POPx(a) POPx(b) PUSHx(b * a) next |
||||
_div: POPx(a) POPx(b) PUSHx(a ? b / a : 0) next |
||||
_and: POPx(a) POPx(b) PUSHx(b & a) next |
||||
_ora: POPx(a) POPx(b) PUSHx(b | a) next |
||||
_eor: POPx(a) POPx(b) PUSHx(b ^ a) next |
||||
_sft: POP1(a) POPx(b) PUSHx(b >> (a & 0xf) << (a >> 4)) next |
||||
} |
||||
@ -1,81 +0,0 @@
|
||||
#include "uxn.h" |
||||
|
||||
/*
|
||||
Copyright (u) 2022-2023 Devine Lu Linvega, Andrew Alderwick, Andrew Richards |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE. |
||||
*/ |
||||
|
||||
#define FLIP { s = ins & 0x40 ? &u->wst : &u->rst; } |
||||
#define JUMP(x) { if(m2) pc = (x); else pc += (Sint8)(x); } |
||||
#define POP1(o) { o = s->dat[--*sp]; } |
||||
#define POP2(o) { o = s->dat[--*sp] | (s->dat[--*sp] << 0x8); } |
||||
#define POPx(o) { if(m2) { POP2(o) } else POP1(o) } |
||||
#define PUSH1(y) { s->dat[s->ptr++] = (y); } |
||||
#define PUSH2(y) { tt = (y); s->dat[s->ptr++] = tt >> 0x8; s->dat[s->ptr++] = tt; } |
||||
#define PUSHx(y) { if(m2) { PUSH2(y) } else PUSH1(y) } |
||||
#define PEEK(o, x, r) { if(m2) { r = (x); o = ram[r++] << 8 | ram[r]; } else o = ram[(x)]; } |
||||
#define POKE(x, y, r) { if(m2) { r = (x); ram[r++] = y >> 8; ram[r] = y; } else ram[(x)] = (y); } |
||||
#define DEVR(o, p) { if(m2) { o = (emu_dei(u, p) << 8) | emu_dei(u, p + 1); } else o = emu_dei(u, p); } |
||||
#define DEVW(p, y) { if(m2) { emu_deo(u, p, y >> 8); emu_deo(u, p + 1, y); } else emu_deo(u, p, y); } |
||||
|
||||
int |
||||
uxn_eval(Uxn *u, Uint16 pc) |
||||
{ |
||||
Uint8 t, kp, *sp, *ram = u->ram; |
||||
Uint16 tt, a, b, c; |
||||
if(!pc || u->dev[0x0f]) return 0; |
||||
for(;;) { |
||||
Uint8 ins = ram[pc++]; |
||||
/* 2 */ Uint8 m2 = ins & 0x20; |
||||
/* r */ Stack *s = ins & 0x40 ? &u->rst : &u->wst; |
||||
/* k */ if(ins & 0x80) kp = s->ptr, sp = &kp; else sp = &s->ptr; |
||||
switch(ins & 0x1f) { |
||||
case 0x00: |
||||
switch(ins) { |
||||
case 0x00: /* BRK */ return 1; |
||||
case 0x20: /* JCI */ POP1(b) if(!b) { pc += 2; break; } |
||||
case 0x40: /* JMI */ a = ram[pc++] << 8 | ram[pc++]; pc += a; break; |
||||
case 0x60: /* JSI */ PUSH2(pc + 2) a = ram[pc++] << 8 | ram[pc++]; pc += a; break; |
||||
case 0x80: case 0xc0: /* LIT */ PUSH1(ram[pc++]) break; |
||||
case 0xa0: case 0xe0: /* LIT2 */ PUSH1(ram[pc++]) PUSH1(ram[pc++]) break; |
||||
} break; |
||||
case 0x01: /* INC */ POPx(a) PUSHx(a + 1) break; |
||||
case 0x02: /* POP */ POPx(a) break; |
||||
case 0x03: /* NIP */ POPx(a) POPx(b) PUSHx(a) break; |
||||
case 0x04: /* SWP */ POPx(a) POPx(b) PUSHx(a) PUSHx(b) break; |
||||
case 0x05: /* ROT */ POPx(a) POPx(b) POPx(c) PUSHx(b) PUSHx(a) PUSHx(c) break; |
||||
case 0x06: /* DUP */ POPx(a) PUSHx(a) PUSHx(a) break; |
||||
case 0x07: /* OVR */ POPx(a) POPx(b) PUSHx(b) PUSHx(a) PUSHx(b) break; |
||||
case 0x08: /* EQU */ POPx(a) POPx(b) PUSH1(b == a) break; |
||||
case 0x09: /* NEQ */ POPx(a) POPx(b) PUSH1(b != a) break; |
||||
case 0x0a: /* GTH */ POPx(a) POPx(b) PUSH1(b > a) break; |
||||
case 0x0b: /* LTH */ POPx(a) POPx(b) PUSH1(b < a) break; |
||||
case 0x0c: /* JMP */ POPx(a) JUMP(a) break; |
||||
case 0x0d: /* JCN */ POPx(a) POP1(b) if(b) JUMP(a) break; |
||||
case 0x0e: /* JSR */ POPx(a) FLIP PUSH2(pc) JUMP(a) break; |
||||
case 0x0f: /* STH */ POPx(a) FLIP PUSHx(a) break; |
||||
case 0x10: /* LDZ */ POP1(a) PEEK(b, a, t) PUSHx(b) break; |
||||
case 0x11: /* STZ */ POP1(a) POPx(b) POKE(a, b, t) break; |
||||
case 0x12: /* LDR */ POP1(a) PEEK(b, pc + (Sint8)a, tt) PUSHx(b) break; |
||||
case 0x13: /* STR */ POP1(a) POPx(b) POKE(pc + (Sint8)a, b, tt) break; |
||||
case 0x14: /* LDA */ POP2(a) PEEK(b, a, tt) PUSHx(b) break; |
||||
case 0x15: /* STA */ POP2(a) POPx(b) POKE(a, b, tt) break; |
||||
case 0x16: /* DEI */ POP1(a) DEVR(b, a) PUSHx(b) break; |
||||
case 0x17: /* DEO */ POP1(a) POPx(b) DEVW(a, b) break; |
||||
case 0x18: /* ADD */ POPx(a) POPx(b) PUSHx(b + a) break; |
||||
case 0x19: /* SUB */ POPx(a) POPx(b) PUSHx(b - a) break; |
||||
case 0x1a: /* MUL */ POPx(a) POPx(b) PUSHx(b * a) break; |
||||
case 0x1b: /* DIV */ POPx(a) POPx(b) PUSHx(a ? b / a : 0) break; |
||||
case 0x1c: /* AND */ POPx(a) POPx(b) PUSHx(b & a) break; |
||||
case 0x1d: /* ORA */ POPx(a) POPx(b) PUSHx(b | a) break; |
||||
case 0x1e: /* EOR */ POPx(a) POPx(b) PUSHx(b ^ a) break; |
||||
case 0x1f: /* SFT */ POP1(a) POPx(b) PUSHx(b >> (a & 0xf) << (a >> 4)) break; |
||||
} |
||||
} |
||||
} |
||||
@ -1,123 +0,0 @@
|
||||
#include "uxn.h" |
||||
|
||||
/*
|
||||
Copyright (u) 2022-2023 Devine Lu Linvega, Andrew Alderwick, Andrew Richards |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE. |
||||
*/ |
||||
|
||||
/* Registers
|
||||
[ Z ][ Y ][ X ][ L ][ N ][ T ] < |
||||
[ . ][ . ][ . ][ H2 ][ . ] < |
||||
[ L2 ][ N2 ][ T2 ] < |
||||
*/ |
||||
|
||||
#define T *(s->dat + s->ptr) |
||||
#define N *(s->dat + (Uint8)(s->ptr - 1)) |
||||
#define L *(s->dat + (Uint8)(s->ptr - 2)) |
||||
#define X *(s->dat + (Uint8)(s->ptr - 3)) |
||||
#define Y *(s->dat + (Uint8)(s->ptr - 4)) |
||||
#define Z *(s->dat + (Uint8)(s->ptr - 5)) |
||||
#define T2 (N << 8 | T) |
||||
#define H2 (L << 8 | N) |
||||
#define N2 (X << 8 | L) |
||||
#define L2 (Z << 8 | Y) |
||||
#define T2_(v) { r = (v); T = r; N = r >> 8; } |
||||
#define N2_(v) { r = (v); L = r; X = r >> 8; } |
||||
#define L2_(v) { r = (v); Y = r; Z = r >> 8; } |
||||
#define FLIP { s = ins & 0x40 ? &u->wst : &u->rst; } |
||||
#define SHIFT(y) { s->ptr += (y); } |
||||
#define SET(x, y) { SHIFT((ins & 0x80) ? x + y : y) } |
||||
|
||||
int |
||||
uxn_eval(Uxn *u, Uint16 pc) |
||||
{ |
||||
Uint16 t, n, l, r; |
||||
Uint8 *ram = u->ram, *rr; |
||||
if(!pc || u->dev[0x0f]) return 0; |
||||
for(;;) { |
||||
Uint8 ins = ram[pc++]; |
||||
Stack *s = ins & 0x40 ? &u->rst : &u->wst; |
||||
switch(ins & 0x3f) { |
||||
/* IMM */ |
||||
case 0x00: case 0x20: |
||||
switch(ins) { |
||||
case 0x00: /* BRK */ return 1; |
||||
case 0x20: /* JCI */ t=T; SHIFT(-1) if(!t) { pc += 2; break; } /* fall-through */ |
||||
case 0x40: /* JMI */ rr = ram + pc; pc += 2 + PEEK2(rr); break; |
||||
case 0x60: /* JSI */ SHIFT( 2) rr = ram + pc; pc += 2; T2_(pc); pc += PEEK2(rr); break; |
||||
case 0x80: /* LIT */ case 0xc0: SHIFT( 1) T = ram[pc++]; break; |
||||
case 0xa0: /* LIT2 */ case 0xe0: SHIFT( 2) N = ram[pc++]; T = ram[pc++]; break; |
||||
} break; |
||||
/* ALU */ |
||||
case 0x01: /* INC */ t=T; SET(1, 0) T = t + 1; break; |
||||
case 0x21: /* INC2 */ t=T2; SET(2, 0) T2_(t + 1) break; |
||||
case 0x02: /* POP */ SET(1,-1) break; |
||||
case 0x22: /* POP2 */ SET(2,-2) break; |
||||
case 0x03: /* NIP */ t=T; SET(2,-1) T = t; break; |
||||
case 0x23: /* NIP2 */ t=T2; SET(4,-2) T2_(t) break; |
||||
case 0x04: /* SWP */ t=T;n=N; SET(2, 0) T = n; N = t; break; |
||||
case 0x24: /* SWP2 */ t=T2;n=N2; SET(4, 0) T2_(n) N2_(t) break; |
||||
case 0x05: /* ROT */ t=T;n=N;l=L; SET(3, 0) T = l; N = t; L = n; break; |
||||
case 0x25: /* ROT2 */ t=T2;n=N2;l=L2; SET(6, 0) T2_(l) N2_(t) L2_(n) break; |
||||
case 0x06: /* DUP */ t=T; SET(1, 1) T = t; N = t; break; |
||||
case 0x26: /* DUP2 */ t=T2; SET(2, 2) T2_(t) N2_(t) break; |
||||
case 0x07: /* OVR */ t=T;n=N; SET(2, 1) T = n; N = t; L = n; break; |
||||
case 0x27: /* OVR2 */ t=T2;n=N2; SET(4, 2) T2_(n) N2_(t) L2_(n) break; |
||||
case 0x08: /* EQU */ t=T;n=N; SET(2,-1) T = n == t; break; |
||||
case 0x28: /* EQU2 */ t=T2;n=N2; SET(4,-3) T = n == t; break; |
||||
case 0x09: /* NEQ */ t=T;n=N; SET(2,-1) T = n != t; break; |
||||
case 0x29: /* NEQ2 */ t=T2;n=N2; SET(4,-3) T = n != t; break; |
||||
case 0x0a: /* GTH */ t=T;n=N; SET(2,-1) T = n > t; break; |
||||
case 0x2a: /* GTH2 */ t=T2;n=N2; SET(4,-3) T = n > t; break; |
||||
case 0x0b: /* LTH */ t=T;n=N; SET(2,-1) T = n < t; break; |
||||
case 0x2b: /* LTH2 */ t=T2;n=N2; SET(4,-3) T = n < t; break; |
||||
case 0x0c: /* JMP */ t=T; SET(1,-1) pc += (Sint8)t; break; |
||||
case 0x2c: /* JMP2 */ t=T2; SET(2,-2) pc = t; break; |
||||
case 0x0d: /* JCN */ t=T;n=N; SET(2,-2) if(n) pc += (Sint8)t; break; |
||||
case 0x2d: /* JCN2 */ t=T2;n=L; SET(3,-3) if(n) pc = t; break; |
||||
case 0x0e: /* JSR */ t=T; SET(1,-1) FLIP SHIFT(2) T2_(pc) pc += (Sint8)t; break; |
||||
case 0x2e: /* JSR2 */ t=T2; SET(2,-2) FLIP SHIFT(2) T2_(pc) pc = t; break; |
||||
case 0x0f: /* STH */ t=T; SET(1,-1) FLIP SHIFT(1) T = t; break; |
||||
case 0x2f: /* STH2 */ t=T2; SET(2,-2) FLIP SHIFT(2) T2_(t) break; |
||||
case 0x10: /* LDZ */ t=T; SET(1, 0) T = ram[t]; break; |
||||
case 0x30: /* LDZ2 */ t=T; SET(1, 1) N = ram[t++]; T = ram[(Uint8)t]; break; |
||||
case 0x11: /* STZ */ t=T;n=N; SET(2,-2) ram[t] = n; break; |
||||
case 0x31: /* STZ2 */ t=T;n=H2; SET(3,-3) ram[t++] = n >> 8; ram[(Uint8)t] = n; break; |
||||
case 0x12: /* LDR */ t=T; SET(1, 0) r = pc + (Sint8)t; T = ram[r]; break; |
||||
case 0x32: /* LDR2 */ t=T; SET(1, 1) r = pc + (Sint8)t; N = ram[r++]; T = ram[r]; break; |
||||
case 0x13: /* STR */ t=T;n=N; SET(2,-2) r = pc + (Sint8)t; ram[r] = n; break; |
||||
case 0x33: /* STR2 */ t=T;n=H2; SET(3,-3) r = pc + (Sint8)t; ram[r++] = n >> 8; ram[r] = n; break; |
||||
case 0x14: /* LDA */ t=T2; SET(2,-1) T = ram[t]; break; |
||||
case 0x34: /* LDA2 */ t=T2; SET(2, 0) N = ram[t++]; T = ram[t]; break; |
||||
case 0x15: /* STA */ t=T2;n=L; SET(3,-3) ram[t] = n; break; |
||||
case 0x35: /* STA2 */ t=T2;n=N2; SET(4,-4) ram[t++] = n >> 8; ram[t] = n; break; |
||||
case 0x16: /* DEI */ t=T; SET(1, 0) T = emu_dei(u, t); break; |
||||
case 0x36: /* DEI2 */ t=T; SET(1, 1) N = emu_dei(u, t++); T = emu_dei(u, t); break; |
||||
case 0x17: /* DEO */ t=T;n=N; SET(2,-2) emu_deo(u, t, n); break; |
||||
case 0x37: /* DEO2 */ t=T;n=N;l=L; SET(3,-3) emu_deo(u, t++, l); emu_deo(u, t, n); break; |
||||
case 0x18: /* ADD */ t=T;n=N; SET(2,-1) T = n + t; break; |
||||
case 0x38: /* ADD2 */ t=T2;n=N2; SET(4,-2) T2_(n + t) break; |
||||
case 0x19: /* SUB */ t=T;n=N; SET(2,-1) T = n - t; break; |
||||
case 0x39: /* SUB2 */ t=T2;n=N2; SET(4,-2) T2_(n - t) break; |
||||
case 0x1a: /* MUL */ t=T;n=N; SET(2,-1) T = n * t; break; |
||||
case 0x3a: /* MUL2 */ t=T2;n=N2; SET(4,-2) T2_(n * t) break; |
||||
case 0x1b: /* DIV */ t=T;n=N; SET(2,-1) T = t ? n / t : 0; break; |
||||
case 0x3b: /* DIV2 */ t=T2;n=N2; SET(4,-2) T2_(t ? n / t : 0) break; |
||||
case 0x1c: /* AND */ t=T;n=N; SET(2,-1) T = n & t; break; |
||||
case 0x3c: /* AND2 */ t=T2;n=N2; SET(4,-2) T2_(n & t) break; |
||||
case 0x1d: /* ORA */ t=T;n=N; SET(2,-1) T = n | t; break; |
||||
case 0x3d: /* ORA2 */ t=T2;n=N2; SET(4,-2) T2_(n | t) break; |
||||
case 0x1e: /* EOR */ t=T;n=N; SET(2,-1) T = n ^ t; break; |
||||
case 0x3e: /* EOR2 */ t=T2;n=N2; SET(4,-2) T2_(n ^ t) break; |
||||
case 0x1f: /* SFT */ t=T;n=N; SET(2,-1) T = n >> (t & 0xf) << (t >> 4); break; |
||||
case 0x3f: /* SFT2 */ t=T;n=H2; SET(3,-1) T2_(n >> (t & 0xf) << (t >> 4)) break; |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -1,16 +0,0 @@
|
||||
#!/bin/bash |
||||
|
||||
echo "Formatting.." |
||||
clang-format -i utos.c |
||||
|
||||
echo "Cleaning.." |
||||
rm -f ../../bin/utos |
||||
|
||||
echo "Building.." |
||||
mkdir -p ../../bin |
||||
cc -std=c89 -DDEBUG -Wall -Wno-unknown-pragmas -Wpedantic -Wshadow -Wextra -Werror=implicit-int -Werror=incompatible-pointer-types -Werror=int-conversion -Wvla -g -Og -fsanitize=address -fsanitize=undefined -lm utos.c -o ../../bin/utos |
||||
|
||||
echo "Running.." |
||||
../../bin/utos ../../projects/sounds/pad1.ss8 ../../projects/sounds/pad1.pcm |
||||
|
||||
echo "Done." |
||||
@ -1,39 +0,0 @@
|
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
|
||||
/*
|
||||
Copyright (c) 2020 Devine Lu Linvega |
||||
|
||||
Permission to use, copy, modify, and distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE. |
||||
*/ |
||||
|
||||
typedef unsigned char Uint8; |
||||
typedef signed char Sint8; |
||||
typedef unsigned short Uint16; |
||||
typedef signed short Sint16; |
||||
|
||||
int |
||||
main(int argc, char **argv) |
||||
{ |
||||
FILE *f; |
||||
Uint8 *buffer; |
||||
Uint16 filelen, i; |
||||
if(argc < 2 || !(f = fopen(argv[1], "rb"))) |
||||
return 1; |
||||
fseek(f, 0, SEEK_END); |
||||
filelen = ftell(f); |
||||
rewind(f); |
||||
buffer = (Uint8 *)malloc(filelen * sizeof(Uint8)); |
||||
fread(buffer, filelen, 1, f); |
||||
fclose(f); |
||||
for(i = 0; i < filelen; ++i) |
||||
buffer[i] += 0x80; |
||||
printf("\n\n"); |
||||
fwrite(buffer, filelen, 1, fopen(argv[2], "wb")); |
||||
return 0; |
||||
} |
||||
@ -1,103 +0,0 @@
|
||||
-- Used for porting Uxntal code for use with the old assembler |
||||
-- in commit 82f7103a55c21b13f898b20e5d1e174e501bc825 with the |
||||
-- assembler that replaced it straight afterwards. |
||||
|
||||
import P, R, S, C, Ct, Cp, V from require 'lpeg' |
||||
|
||||
local labels, filename |
||||
|
||||
opcode_translate = |
||||
LDZ2: 'LDA' |
||||
STZ2: 'STA' |
||||
LDR: 'LDZ2' |
||||
STR: 'STZ2' |
||||
LDR2: 'LDA2' |
||||
STR2: 'STA2' |
||||
|
||||
grammar = P { |
||||
'file' |
||||
file: Ct(V'ows' * (V'atom' * V'ows') ^ 0) * Cp! |
||||
ws: C S' \n\t' ^ 1 |
||||
ows: C S' \n\t' ^ 0 |
||||
atom: V'opcode' + V'comment' + V'variable' + V'addr' + V'literal' + V'setter' + V'getter' + V'short' + V'labeldef' + V'relative' + V'sublabel' + V'data' + V'macro' + V'macroref' + V'rawshort' |
||||
comment: C P'(' * (1-V'ws'*P')') ^ 0 * V'ws' * P')' |
||||
variable: (P';' / -> '@') * C(V'name') * V'ws' * (P'{' / ->'[') * V'ws' * ((P'' / -> '&') * C(V'name') * V'ws' * (P'' / -> '$') * C(V'name') * V'ws') ^ 0 * (P'}' / -> ']') / (...) -> |
||||
var = select 2, ... |
||||
r, w = if var\sub(1, 1) == var\sub(1, 1)\upper! |
||||
' DEI', ' DEO' |
||||
else |
||||
' LDZ', ' STZ' |
||||
for i = 7, select('#', ...), 6 |
||||
k = select i, ... |
||||
rr, ww = if '2' == select i + 3, ... |
||||
r .. '2', w .. '2' |
||||
else |
||||
r, w |
||||
labels['~' .. var .. '.' .. k] = '.' .. var .. '/' .. k .. rr |
||||
labels['=' .. var .. '.' .. k] = '.' .. var .. '/' .. k .. ww |
||||
if i == 7 |
||||
labels['~' .. var] = '.' .. var .. rr |
||||
labels['=' .. var] = '.' .. var .. ww |
||||
... |
||||
name: R('az', 'AZ', '09', '__', '--', '++', '**', '//', '??') ^ 1 |
||||
addr: C(P'|') * (C(V'hex') / (i) -> |
||||
if i == '0200' |
||||
return '0100' |
||||
if i\match '^01..$' |
||||
return i\sub 3 |
||||
return i |
||||
) |
||||
literal: C P'#' * V'hex' |
||||
hex: R('09', 'af', 'AF') ^ 1 |
||||
setter: C(P'=' * V'label') / (s) -> |
||||
if not labels[s] |
||||
error 'label not found: %q in %s'\format s, filename |
||||
return labels[s] |
||||
getter: C(P'~' * V'label') / (s) -> |
||||
if not labels[s] |
||||
error 'label not found: %q in %s'\format s, filename |
||||
return labels[s] |
||||
label: R('az', 'AZ', '09', '__', '--', '..', '$$', ']]', '))', '@@', '""', ',,', '##', '||', '{{', '}}', '%%', ';;', '^^', '~~', '==', '//') ^ 1 |
||||
short: (P',' / -> ';') * (C(V'label') / (s) -> (s\gsub '%$', '&')) |
||||
rawshort: (P'.' / -> ':') * (C(V'label') / (s) -> (s\gsub '%$', '&')) |
||||
opcode: (C(R'AZ' * R'AZ' * R'AZ' * P'2' ^ -1) / (s) -> opcode_translate[s] or s) * C P'r' ^ -1 * #V'ws' |
||||
labeldef: C P'@' * V'label' |
||||
relative: (P'^' / -> ',') * (C(V'label') / (s) -> (s\gsub '%$', '&')) |
||||
sublabel: (P'$' / -> '&') * (C(V'label') / (s) -> (s\gsub '%$', '&')) |
||||
data: C(P'[') * V'ws' * (V'data_item' * V'ws') ^ 0 * C(P']') |
||||
macro: C(P'%' * V'name' * V'ws' * P'{') * V'ws' * (V'atom' * V'ows') ^ 0 * C P'}' |
||||
macroref: C V'name' |
||||
data_item: C(V'hex' * #V'ws') + V'data_string' |
||||
data_string: C((1 - S' \n\t') ^ 1 - P']') / (s) -> '"', s |
||||
} |
||||
|
||||
translate = (_filename) -> |
||||
filename = _filename |
||||
labels = {} |
||||
f = assert io.open filename |
||||
contents = f\read '*a' |
||||
f\close! |
||||
t, len = grammar\match contents |
||||
if len <= #contents |
||||
print '\027[32m%s\027[0;1m%s\027[0m'\format contents\sub(len - 100, len - 1), contents\sub(len, len + 100) |
||||
error 'no match' |
||||
filename = filename\gsub 'attic', 'auto' |
||||
f = assert io.open filename, 'w' |
||||
f\write table.concat(t) |
||||
f\close! |
||||
f = assert io.popen 'bin/assembler %s bin/boot.rom'\format filename |
||||
for l in f\lines! |
||||
print l |
||||
if l == 'Error: Assembly[Failed]' |
||||
os.exit 1 |
||||
f\close! |
||||
os.exit 0 |
||||
|
||||
translate 'attic/software/assembler.tal' |
||||
os.exit 0 |
||||
|
||||
translate 'attic/tests/opcodes.tal' |
||||
translate 'attic/tests/basics.tal' |
||||
|
||||
-- for k, v in pairs t |
||||
-- print k |
||||
Loading…
Reference in new issue