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