mirror of
https://git.planet-casio.com/Lephenixnoir/fxsdk.git
synced 2024-12-29 13:03:37 +01:00
fxos: bring disassembling to a new level
Almost-complete implementation of fxos, the disassembler in particular is now able to detect syscalls and register addresses on the fly, plus support for SH4-only instructions.
This commit is contained in:
parent
ed8e199f47
commit
25db504c22
26 changed files with 3259 additions and 281 deletions
37
Makefile
37
Makefile
|
@ -6,12 +6,10 @@ include Makefile.cfg
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Compiler flags
|
# Compiler flags
|
||||||
cflags = -Wall -Wextra -std=c11 -O2 -I $(dir $<) -D_GNU_SOURCE \
|
cflags = -Wall -Wextra -std=c11 -g -I $(dir $<) -D_GNU_SOURCE \
|
||||||
-DFXSDK_PREFIX='"$(PREFIX)"' $(CFLAGS)
|
-DFXSDK_PREFIX='"$(PREFIX)"' $(CFLAGS)
|
||||||
# Linker flags
|
# Linker flags
|
||||||
lflags = -lpng
|
lflags = -lpng
|
||||||
# Bison generation flags
|
|
||||||
# bflags = -L C --defines=$(@:.c=.h) --verbose
|
|
||||||
# Dependency generation flags
|
# Dependency generation flags
|
||||||
dflags = -MT $@ -MMD -MP -MF $(@:%.o=%.d)
|
dflags = -MT $@ -MMD -MP -MF $(@:%.o=%.d)
|
||||||
|
|
||||||
|
@ -28,15 +26,18 @@ src = $(wildcard $1/*.c)
|
||||||
src-fxsdk := $(call src,fxsdk)
|
src-fxsdk := $(call src,fxsdk)
|
||||||
src-fxg1a := $(call src,fxg1a)
|
src-fxg1a := $(call src,fxg1a)
|
||||||
src-fxos := $(call src,fxos)
|
src-fxos := $(call src,fxos)
|
||||||
|
lex-fxos := $(wildcard fxos/*.l)
|
||||||
|
|
||||||
obj = $(src-$1:%=build/%.o)
|
obj = $($1:%=build/%.o)
|
||||||
obj-fxsdk := $(call obj,fxsdk)
|
lex = $($1:%.l=build/%.yy.c.o)
|
||||||
obj-fxg1a := $(call obj,fxg1a)
|
obj-fxsdk := $(call obj,src-fxsdk)
|
||||||
obj-fxos := $(call obj,fxos)
|
obj-fxg1a := $(call obj,src-fxg1a)
|
||||||
|
obj-fxos := $(call obj,src-fxos) $(call lex,lex-fxos)
|
||||||
|
|
||||||
# Symbolic targets
|
# Symbolic targets
|
||||||
|
|
||||||
all: $(bin)
|
all: $(bin)
|
||||||
|
@echo $(lex-fxos)
|
||||||
|
|
||||||
all-fxsdk: bin/fxsdk
|
all-fxsdk: bin/fxsdk
|
||||||
all-fxg1a: bin/fxg1a
|
all-fxg1a: bin/fxg1a
|
||||||
|
@ -62,17 +63,11 @@ build/%.c.o: %.c
|
||||||
@mkdir -p $(dir $@)
|
@mkdir -p $(dir $@)
|
||||||
gcc -c $< -o $@ $(cflags) $(dflags)
|
gcc -c $< -o $@ $(cflags) $(dflags)
|
||||||
|
|
||||||
# Flex lexers (unused since fxconv is written in Python)
|
# Flex lexers for the fxos database
|
||||||
# build/%/lexer.yy.c: %/lexer.l build/%/parser.tab.c
|
build/fxos/lexer-%.yy.c: fxos/lexer-%.l
|
||||||
# flex -o $@ -s $<
|
flex -o $@ -s $<
|
||||||
# build/%/lexer.yy.c.o: build/%/lexer.yy.c
|
build/fxos/lexer-%.yy.c.o: build/fxos/lexer-%.yy.c
|
||||||
# gcc -c $< -o $@ $(cflags) -Wno-unused-function $(dflags) -I $*
|
gcc -c $< -o $@ $(cflags) -Wno-unused-function $(dflags) -I fxos
|
||||||
|
|
||||||
# Bison parsers (unused since fxconv is written in Python)
|
|
||||||
# build/%/parser.tab.c: %/parser.y
|
|
||||||
# bison $< -o $@ $(bflags)
|
|
||||||
# build/%/parser.tab.c.o: build/%/parser.tab.c
|
|
||||||
# gcc -c $< -o $@ $(cflags) $(dflags) -I $*
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Dependency system, misc.
|
# Dependency system, misc.
|
||||||
|
@ -95,10 +90,16 @@ Makefile.cfg:
|
||||||
|
|
||||||
install: $(bin)
|
install: $(bin)
|
||||||
install -d $(PREFIX)/bin
|
install -d $(PREFIX)/bin
|
||||||
|
install -d $(PREFIX)/share/fxsdk
|
||||||
install $(bin) -m 755 $(PREFIX)/bin
|
install $(bin) -m 755 $(PREFIX)/bin
|
||||||
|
install fxos/*.txt -m 644 $(PREFIX)/share/fxsdk
|
||||||
install fxconv/fxconv-main.py -m 755 $(PREFIX)/bin/fxconv
|
install fxconv/fxconv-main.py -m 755 $(PREFIX)/bin/fxconv
|
||||||
install fxconv/fxconv.py -m 644 $(PREFIX)/bin
|
install fxconv/fxconv.py -m 644 $(PREFIX)/bin
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
rm -f $(PREFIX)/bin/{fxsdk,fxg1a,fxos,fxconv,fxconv.py}
|
||||||
|
rm -rf $(PREFIX)/share/fxsdk
|
||||||
|
|
||||||
#
|
#
|
||||||
# Cleaning
|
# Cleaning
|
||||||
#
|
#
|
||||||
|
|
4
configure
vendored
4
configure
vendored
|
@ -5,7 +5,7 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
# Path parameters
|
# Path parameters
|
||||||
PREFIX="/usr"
|
PREFIX="$HOME/.local"
|
||||||
# Individual component selection
|
# Individual component selection
|
||||||
BUILD_fxsdk=1
|
BUILD_fxsdk=1
|
||||||
BUILD_fxconv=1
|
BUILD_fxconv=1
|
||||||
|
@ -47,7 +47,7 @@ Install folders:
|
||||||
Executables will be installed in <prefix>/bin and runtime data in
|
Executables will be installed in <prefix>/bin and runtime data in
|
||||||
<prefix>/share/fxsdk.
|
<prefix>/share/fxsdk.
|
||||||
|
|
||||||
--prefix=<prefix> Base install folder [default /usr]
|
--prefix=<prefix> Base install folder [default $HOME/.local]
|
||||||
EOF
|
EOF
|
||||||
exit 0
|
exit 0
|
||||||
}
|
}
|
||||||
|
|
22
fxos/analysis.c
Normal file
22
fxos/analysis.c
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* analysis_short(): Print a one-line summary for an address */
|
||||||
|
void analysis_short(struct os const *os, uint32_t value)
|
||||||
|
{
|
||||||
|
/* Find out whether it is a syscall address */
|
||||||
|
int syscall = os_syscall_find(os, value);
|
||||||
|
|
||||||
|
if(syscall != -1)
|
||||||
|
{
|
||||||
|
printf(" %%%03x", syscall);
|
||||||
|
|
||||||
|
/* Also find out the syscall's name! */
|
||||||
|
struct sys_call const *call = sys_find(syscall);
|
||||||
|
if(call) printf(" %s", call->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Find out any peripheral register address */
|
||||||
|
struct reg_address const *reg = reg_find(value);
|
||||||
|
if(reg) printf(" %s", reg->name);
|
||||||
|
}
|
220
fxos/asm-sh3.txt
Normal file
220
fxos/asm-sh3.txt
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
# Instruction decoding table: 'sh3'
|
||||||
|
# Format: [01nmdi]{16}, followed by the mnemonic and the list of arguments.
|
||||||
|
# There should be at most one series of each argument letter in the opcode.
|
||||||
|
#
|
||||||
|
# Possible argument strings are predefined and include:
|
||||||
|
# rn rm #imm
|
||||||
|
# jump8 jump12 disp pcdisp
|
||||||
|
# @rn @rm @rn+ @rm+ @-rn
|
||||||
|
# @(disp,rn) @(disp,rm) @(r0,rn) @(r0,rm) @(disp,gbr)
|
||||||
|
#
|
||||||
|
# The disassembler substitutes some elements as follows:
|
||||||
|
# rn -> value of the "n"-sequence
|
||||||
|
# rm -> value of the "m"-sequence
|
||||||
|
# #imm -> value of the "i"-sequence
|
||||||
|
# disp -> value of the "d"-sequence
|
||||||
|
# jump8 -> value of the 8-bit "d"-sequence plus value of PC
|
||||||
|
# jump12 -> value of the 12-bit "d"-sequence plus value of PC
|
||||||
|
# pcdisp -> same as "jump8", but also prints pointed value (for data)
|
||||||
|
|
||||||
|
0000000001001000 clrs
|
||||||
|
0000000000001000 clrt
|
||||||
|
0000000000101000 clrmac
|
||||||
|
0000000000011001 div0u
|
||||||
|
0000000000111000 ldtlb
|
||||||
|
0000000000001001 nop
|
||||||
|
0000000000101011 rte
|
||||||
|
0000000000001011 rts
|
||||||
|
0000000001011000 sets
|
||||||
|
0000000000011000 sett
|
||||||
|
0000000000011011 sleep
|
||||||
|
|
||||||
|
0100nnnn00010101 cmp/pl rn
|
||||||
|
0100nnnn00010001 cmp/pz rn
|
||||||
|
0100nnnn00010000 dt rn
|
||||||
|
0000nnnn00101001 movt rn
|
||||||
|
0100nnnn00000100 rotl rn
|
||||||
|
0100nnnn00000101 rotr rn
|
||||||
|
0100nnnn00100100 rotcl rn
|
||||||
|
0100nnnn00100101 rotcr rn
|
||||||
|
0100nnnn00100000 shal rn
|
||||||
|
0100nnnn00100001 shar rn
|
||||||
|
0100nnnn00000000 shll rn
|
||||||
|
0100nnnn00000001 shlr rn
|
||||||
|
0100nnnn00001000 shll2 rn
|
||||||
|
0100nnnn00001001 shlr2 rn
|
||||||
|
0100nnnn00011000 shll8 rn
|
||||||
|
0100nnnn00011001 shlr8 rn
|
||||||
|
0100nnnn00101000 shll16 rn
|
||||||
|
0100nnnn00101001 shlr16 rn
|
||||||
|
|
||||||
|
0011nnnnmmmm1100 add rm, rn
|
||||||
|
0011nnnnmmmm1110 addc rm, rn
|
||||||
|
0011nnnnmmmm1111 addv rm, rn
|
||||||
|
0010nnnnmmmm1001 and rm, rn
|
||||||
|
0011nnnnmmmm0000 cmp/eq rm, rn
|
||||||
|
0011nnnnmmmm0010 cmp/hs rm, rn
|
||||||
|
0011nnnnmmmm0011 cmp/ge rm, rn
|
||||||
|
0011nnnnmmmm0110 cmp/hi rm, rn
|
||||||
|
0011nnnnmmmm0111 cmp/gt rm, rn
|
||||||
|
0010nnnnmmmm1100 cmp/str rm, rn
|
||||||
|
0011nnnnmmmm0100 div1 rm, rn
|
||||||
|
0010nnnnmmmm0111 div0s rm, rn
|
||||||
|
0011nnnnmmmm1101 dmuls.l rm, rn
|
||||||
|
0011nnnnmmmm0101 dmulu.l rm, rn
|
||||||
|
0110nnnnmmmm1110 exts.b rm, rn
|
||||||
|
0110nnnnmmmm1111 exts.w rm, rn
|
||||||
|
0110nnnnmmmm1100 extu.b rm, rn
|
||||||
|
0110nnnnmmmm1101 extu.w rm, rn
|
||||||
|
0110nnnnmmmm0011 mov rm, rn
|
||||||
|
0000nnnnmmmm0111 mul.l rm, rn
|
||||||
|
0010nnnnmmmm1111 muls.w rm, rn
|
||||||
|
0010nnnnmmmm1110 mulu.w rm, rn
|
||||||
|
0110nnnnmmmm1011 neg rm, rn
|
||||||
|
0110nnnnmmmm1010 negc rm, rn
|
||||||
|
0110nnnnmmmm0111 not rm, rn
|
||||||
|
0010nnnnmmmm1011 or rm, rn
|
||||||
|
0100nnnnmmmm1100 shad rm, rn
|
||||||
|
0100nnnnmmmm1101 shld rm, rn
|
||||||
|
0011nnnnmmmm1000 sub rm, rn
|
||||||
|
0011nnnnmmmm1010 subc rm, rn
|
||||||
|
0011nnnnmmmm1011 subv rm, rn
|
||||||
|
0110nnnnmmmm1000 swap.b rm, rn
|
||||||
|
0110nnnnmmmm1001 swap.w rm, rn
|
||||||
|
0010nnnnmmmm1000 tst rm, rn
|
||||||
|
0010nnnnmmmm1010 xor rm, rn
|
||||||
|
0010nnnnmmmm1101 xtrct rm, rn
|
||||||
|
|
||||||
|
0100mmmm00001110 ldc rm, sr
|
||||||
|
0100mmmm00011110 ldc rm, gbr
|
||||||
|
0100mmmm00101110 ldc rm, vbr
|
||||||
|
0100mmmm00111110 ldc rm, ssr
|
||||||
|
0100mmmm01001110 ldc rm, spc
|
||||||
|
0100mmmm10001110 ldc rm, r0_bank
|
||||||
|
0100mmmm10011110 ldc rm, r1_bank
|
||||||
|
0100mmmm10101110 ldc rm, r2_bank
|
||||||
|
0100mmmm10111110 ldc rm, r3_bank
|
||||||
|
0100mmmm11001110 ldc rm, r4_bank
|
||||||
|
0100mmmm11011110 ldc rm, r5_bank
|
||||||
|
0100mmmm11101110 ldc rm, r6_bank
|
||||||
|
0100mmmm11111110 ldc rm, r7_bank
|
||||||
|
0100mmmm00001010 lds rm, mach
|
||||||
|
0100mmmm00011010 lds rm, macl
|
||||||
|
0100mmmm00101010 lds rm, pr
|
||||||
|
0000nnnn00000010 stc sr, rn
|
||||||
|
0000nnnn00010010 stc gbr, rn
|
||||||
|
0000nnnn00100010 stc vbr, rn
|
||||||
|
0000nnnn00110010 stc ssr, rn
|
||||||
|
0000nnnn01000010 stc spc, rn
|
||||||
|
0000nnnn10000010 stc r0_bank, rn
|
||||||
|
0000nnnn10010010 stc r1_bank, rn
|
||||||
|
0000nnnn10100010 stc r2_bank, rn
|
||||||
|
0000nnnn10110010 stc r3_bank, rn
|
||||||
|
0000nnnn11000010 stc r4_bank, rn
|
||||||
|
0000nnnn11010010 stc r5_bank, rn
|
||||||
|
0000nnnn11100010 stc r6_bank, rn
|
||||||
|
0000nnnn11110010 stc r7_bank, rn
|
||||||
|
0000nnnn00001010 sts mach, rn
|
||||||
|
0000nnnn00011010 sts macl, rn
|
||||||
|
0000nnnn00101010 sts pr, rn
|
||||||
|
|
||||||
|
0100nnnn00101011 jmp @rn
|
||||||
|
0100nnnn00001011 jsr @rn
|
||||||
|
0000nnnn10000011 pref @rn
|
||||||
|
0100nnnn00011011 tas.b @rn
|
||||||
|
0010nnnnmmmm0000 mov.b rm, @rn
|
||||||
|
0010nnnnmmmm0001 mov.w rm, @rn
|
||||||
|
0010nnnnmmmm0010 mov.l rm, @rn
|
||||||
|
0110nnnnmmmm0000 mov.b @rm, rn
|
||||||
|
0110nnnnmmmm0001 mov.w @rm, rn
|
||||||
|
0110nnnnmmmm0010 mov.l @rm, rn
|
||||||
|
0000nnnnmmmm1111 mac.l @rm+, @rn+
|
||||||
|
0100nnnnmmmm1111 mac.w @rm+, @rn+
|
||||||
|
|
||||||
|
0110nnnnmmmm0100 mov.b @rm+, rn
|
||||||
|
0110nnnnmmmm0101 mov.w @rm+, rn
|
||||||
|
0110nnnnmmmm0110 mov.l @rm+, rn
|
||||||
|
|
||||||
|
0100mmmm00000111 ldc.l @rm+, sr
|
||||||
|
0100mmmm00010111 ldc.l @rm+, gbr
|
||||||
|
0100mmmm00100111 ldc.l @rm+, vbr
|
||||||
|
0100mmmm00110111 ldc.l @rm+, ssr
|
||||||
|
0100mmmm01000111 ldc.l @rm+, spc
|
||||||
|
0100mmmm10000111 ldc.l @rm+, r0_bank
|
||||||
|
0100mmmm10010111 ldc.l @rm+, r1_bank
|
||||||
|
0100mmmm10100111 ldc.l @rm+, r2_bank
|
||||||
|
0100mmmm10110111 ldc.l @rm+, r3_bank
|
||||||
|
0100mmmm11000111 ldc.l @rm+, r4_bank
|
||||||
|
0100mmmm11010111 ldc.l @rm+, r5_bank
|
||||||
|
0100mmmm11100111 ldc.l @rm+, r6_bank
|
||||||
|
0100mmmm11110111 ldc.l @rm+, r7_bank
|
||||||
|
0100mmmm00000110 lds.l @rm+, mach
|
||||||
|
0100mmmm00010110 lds.l @rm+, macl
|
||||||
|
0100mmmm00100110 lds.l @rm+, pr
|
||||||
|
|
||||||
|
0010nnnnmmmm0100 mov.b rm, @-rn
|
||||||
|
0010nnnnmmmm0101 mov.w rm, @-rn
|
||||||
|
0010nnnnmmmm0110 mov.l rm, @-rn
|
||||||
|
|
||||||
|
0100nnnn00000011 stc.l sr, @-rn
|
||||||
|
0100nnnn00010011 stc.l gbr, @-rn
|
||||||
|
0100nnnn00100011 stc.l vbr, @-rn
|
||||||
|
0100nnnn00110011 stc.l ssr, @-rn
|
||||||
|
0100nnnn01000011 stc.l spc, @-rn
|
||||||
|
0100nnnn10000011 stc.l r0_bank, @-rn
|
||||||
|
0100nnnn10010011 stc.l r1_bank, @-rn
|
||||||
|
0100nnnn10100011 stc.l r2_bank, @-rn
|
||||||
|
0100nnnn10110011 stc.l r3_bank, @-rn
|
||||||
|
0100nnnn11000011 stc.l r4_bank, @-rn
|
||||||
|
0100nnnn11010011 stc.l r5_bank, @-rn
|
||||||
|
0100nnnn11100011 stc.l r6_bank, @-rn
|
||||||
|
0100nnnn11110011 stc.l r7_bank, @-rn
|
||||||
|
0100nnnn00000010 sts.l mach, @-rn
|
||||||
|
0100nnnn00010010 sts.l macl, @-rn
|
||||||
|
0100nnnn00100010 sts.l pr, @-rn
|
||||||
|
|
||||||
|
10000000nnnndddd mov.b r0, @(disp, rn)
|
||||||
|
10000001nnnndddd mov.w r0, @(disp, rn)
|
||||||
|
0001nnnnmmmmdddd mov.l rm, @(disp, rn)
|
||||||
|
10000100mmmmdddd mov.b @(disp, rm), r0
|
||||||
|
10000101mmmmdddd mov.w @(disp, rm), r0
|
||||||
|
0101nnnnmmmmdddd mov.l @(disp, rm), rn
|
||||||
|
0000nnnnmmmm0100 mov.b rm, @(r0, rn)
|
||||||
|
0000nnnnmmmm0101 mov.w rm, @(r0, rn)
|
||||||
|
0000nnnnmmmm0110 mov.l rm, @(r0, rn)
|
||||||
|
0000nnnnmmmm1100 mov.b @(r0, rm), rn
|
||||||
|
0000nnnnmmmm1101 mov.w @(r0, rm), rn
|
||||||
|
0000nnnnmmmm1110 mov.l @(r0, rm), rn
|
||||||
|
11000000dddddddd mov.b r0, @(disp, gbr)
|
||||||
|
11000001dddddddd mov.w r0, @(disp, gbr)
|
||||||
|
11000010dddddddd mov.l r0, @(disp, gbr)
|
||||||
|
11000100dddddddd mov.b @(disp, gbr), r0
|
||||||
|
11000101dddddddd mov.w @(disp, gbr), r0
|
||||||
|
11000110dddddddd mov.l @(disp, gbr), r0
|
||||||
|
|
||||||
|
11001101iiiiiiii and.b #imm, @(r0, gbr)
|
||||||
|
11001111iiiiiiii or.b #imm, @(r0, gbr)
|
||||||
|
11001100iiiiiiii tst.b #imm, @(r0, gbr)
|
||||||
|
11001110iiiiiiii xor.b #imm, @(r0, gbr)
|
||||||
|
|
||||||
|
1001nnnndddddddd mov.w pcdisp, rn
|
||||||
|
1101nnnndddddddd mov.l pcdisp, rn
|
||||||
|
11000111dddddddd mova pcdisp, r0
|
||||||
|
|
||||||
|
0000mmmm00100011 braf rm
|
||||||
|
0000mmmm00000011 bsrf rm
|
||||||
|
10001011dddddddd bf jump8
|
||||||
|
10001111dddddddd bf/s jump8
|
||||||
|
10001001dddddddd bt jump8
|
||||||
|
10001101dddddddd bt/s jump8
|
||||||
|
1010dddddddddddd bra jump12
|
||||||
|
1011dddddddddddd bsr jump12
|
||||||
|
|
||||||
|
0111nnnniiiiiiii add #imm, rn
|
||||||
|
11001001iiiiiiii and #imm, r0
|
||||||
|
10001000iiiiiiii cmp/eq #imm, r0
|
||||||
|
1110nnnniiiiiiii mov #imm, rn
|
||||||
|
11001011iiiiiiii or #imm, r0
|
||||||
|
11001000iiiiiiii tst #imm, r0
|
||||||
|
11001010iiiiiiii xor #imm, r0
|
||||||
|
11000011iiiiiiii trapa #imm
|
26
fxos/asm-sh4.txt
Normal file
26
fxos/asm-sh4.txt
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
# Instruction decoding table: 'sh4'
|
||||||
|
# This table is an extension for SH4 processors. See 'asm-sh3.txt' for details
|
||||||
|
# on the format.
|
||||||
|
|
||||||
|
0000nnnn01110011 movco.l r0, @rn
|
||||||
|
0000mmmm01100011 movli.l @rm, r0
|
||||||
|
0100mmmm10101001 movua.l @rm, r0
|
||||||
|
0100mmmm11101001 movua.l @rm+, r0
|
||||||
|
0000nnnn11000011 movca.l r0, @rn
|
||||||
|
|
||||||
|
0000nnnn11100011 icbi @rn
|
||||||
|
0000nnnn10010011 ocbi @rn
|
||||||
|
0000nnnn10100011 ocbp @rn
|
||||||
|
0000nnnn10110011 ocbwb @rn
|
||||||
|
|
||||||
|
0000nnnn11010011 prefi @rn
|
||||||
|
0000000010101011 synco
|
||||||
|
|
||||||
|
0100mmmm00111010 ldc rm, sgr
|
||||||
|
0100mmmm11111010 ldc rm, dbr
|
||||||
|
0100mmmm00110110 ldc.l @rm+, sgr
|
||||||
|
0100mmmm11110110 ldc.l @rm+, dbr
|
||||||
|
0000nnnn00111010 stc sgr, rn
|
||||||
|
0000nnnn11111010 stc dbr, rn
|
||||||
|
0100nnnn00110010 stc.l sgr, @-rn
|
||||||
|
0100nnnn11110010 stc.l dbr, @-rn
|
74
fxos/asm.c
Normal file
74
fxos/asm.c
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <util.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* asm_free_item(): Free an assembly instruction details */
|
||||||
|
static void asm_free_item(void *item)
|
||||||
|
{
|
||||||
|
struct asm_insn *insn = item;
|
||||||
|
free(insn->mnemonic);
|
||||||
|
free(insn->literal1);
|
||||||
|
free(insn->literal2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* asm_load(): Load an assembly table */
|
||||||
|
void asm_load(char const *file)
|
||||||
|
{
|
||||||
|
err_context("assembly", file, NULL);
|
||||||
|
if(!table_available())
|
||||||
|
{
|
||||||
|
err("too many tables, skipping");
|
||||||
|
err_pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map the file to memory */
|
||||||
|
int fd;
|
||||||
|
size_t size;
|
||||||
|
void *data = map(file, &fd, &size);
|
||||||
|
if(!data) { err_pop(); return; }
|
||||||
|
|
||||||
|
/* If the file is named "asm-x.txt", use "x" as the table name */
|
||||||
|
char *name = match_table_name(file, "asm", ".txt");
|
||||||
|
|
||||||
|
/* Parse the contents; the lexer in is [lexer-asm.l] and the parser is
|
||||||
|
implemented as an automaton with basic error correction. */
|
||||||
|
int count;
|
||||||
|
struct asm_insn *ins = lex_asm(data, size, &count);
|
||||||
|
|
||||||
|
table_create("asm", name, asm_free_item, count, sizeof *ins, ins);
|
||||||
|
|
||||||
|
unmap(data, fd, size);
|
||||||
|
err_pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Global storage for asm_match() */
|
||||||
|
static uint16_t asm_match_opcode;
|
||||||
|
|
||||||
|
/* asm_match(): Check if an instruction matches a pattern */
|
||||||
|
int asm_match(void *item)
|
||||||
|
{
|
||||||
|
struct asm_insn *insn = item;
|
||||||
|
return ((insn->bits ^ asm_match_opcode) & insn->arg_mask) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* asm_decode(): Match a 16-bit opcode against the assembly database */
|
||||||
|
int asm_decode(uint16_t opcode, struct asm_match *match, int next)
|
||||||
|
{
|
||||||
|
asm_match_opcode = opcode;
|
||||||
|
char const *table;
|
||||||
|
struct asm_insn *insn = table_find("asm", asm_match, &table, next);
|
||||||
|
if(!insn) return 1;
|
||||||
|
|
||||||
|
/* Set match details */
|
||||||
|
match->insn = insn;
|
||||||
|
match->table = table;
|
||||||
|
|
||||||
|
match->n = (opcode >> insn->n_sh) & insn->n_mask;
|
||||||
|
match->m = (opcode >> insn->m_sh) & insn->m_mask;
|
||||||
|
match->d = (opcode >> insn->d_sh) & insn->d_mask;
|
||||||
|
match->i = (opcode >> insn->i_sh) & insn->i_mask;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
268
fxos/disassembly.c
Normal file
268
fxos/disassembly.c
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* Architecture we are disassembling for */
|
||||||
|
static enum mpu mpu = MPU_GUESS;
|
||||||
|
/* Current program counter */
|
||||||
|
static uint32_t pc = 0;
|
||||||
|
/* Data chunk under disassembly (whole file) */
|
||||||
|
static uint8_t *data;
|
||||||
|
static size_t len;
|
||||||
|
/* Non-NULL when disassembling an OS */
|
||||||
|
static struct os const *os = NULL;
|
||||||
|
|
||||||
|
/* pcdisp(): Compute the address of a PC-relative displacement
|
||||||
|
@pc Current PC value
|
||||||
|
@disp Displacement value (from opcode)
|
||||||
|
@unit Number of bytes per step (1, 2 or 4), depends on instruction
|
||||||
|
Returns the pointed location. */
|
||||||
|
static uint32_t pcdisp(uint32_t pc, uint32_t disp, int unit)
|
||||||
|
{
|
||||||
|
pc += 4;
|
||||||
|
if(unit == 4) pc &= ~3;
|
||||||
|
|
||||||
|
return pc + disp * unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* pcread(): Read data pointed through a PC-relative displacement
|
||||||
|
@pc Current PC value
|
||||||
|
@disp Displacement value (from opcode)
|
||||||
|
@unit Number of bytes per set (also number of bytes read)
|
||||||
|
@out If non-NULL, set to 1 if pointed address is out of the file
|
||||||
|
Returns the value pointed at, an undefined value if out of bounds. */
|
||||||
|
static uint32_t pcread(uint32_t pc, uint32_t disp, int unit, int *out)
|
||||||
|
{
|
||||||
|
/* Take physical addresses */
|
||||||
|
uint32_t addr = pcdisp(pc, disp, unit) & 0x1fffffff;
|
||||||
|
if(out) *out = (addr + unit > len);
|
||||||
|
|
||||||
|
uint32_t value = 0;
|
||||||
|
while(unit--) value = (value << 8) | data[addr++];
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* matches(): Count number of matches for a single instruction
|
||||||
|
@opcode 16-bit opcode value
|
||||||
|
Returns the number of matching instructions in the database. */
|
||||||
|
static int matches(uint16_t opcode)
|
||||||
|
{
|
||||||
|
struct asm_match match;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while(!asm_decode(opcode, &match, count))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void arg_output(int type, char const *literal,
|
||||||
|
struct asm_match const *match, int opsize)
|
||||||
|
{
|
||||||
|
int n = match->n;
|
||||||
|
int m = match->m;
|
||||||
|
int d = match->d;
|
||||||
|
int i = match->i;
|
||||||
|
|
||||||
|
/* Sign extensions of d to 8 and 12 bits */
|
||||||
|
int32_t d8 = (int8_t)d;
|
||||||
|
int32_t d12 = (d & 0x800) ? (int32_t)(d | 0xfffff000) : (d);
|
||||||
|
/* Sign extension of i to 8 bits */
|
||||||
|
int32_t i8 = (int8_t)i;
|
||||||
|
|
||||||
|
int out_of_bounds;
|
||||||
|
uint32_t addr;
|
||||||
|
uint32_t value;
|
||||||
|
|
||||||
|
switch(type)
|
||||||
|
{
|
||||||
|
case LITERAL:
|
||||||
|
printf("%s", literal);
|
||||||
|
break;
|
||||||
|
case IMM:
|
||||||
|
printf("#%d", i8);
|
||||||
|
break;
|
||||||
|
case RN:
|
||||||
|
printf("r%d", n);
|
||||||
|
break;
|
||||||
|
case RM:
|
||||||
|
printf("r%d", m);
|
||||||
|
break;
|
||||||
|
case JUMP8:
|
||||||
|
value = pcdisp(pc, d8, 2);
|
||||||
|
printf("<%x", value);
|
||||||
|
if(os) analysis_short(os, value | 0x80000000);
|
||||||
|
printf(">");
|
||||||
|
break;
|
||||||
|
case JUMP12:
|
||||||
|
value = pcdisp(pc, d12, 2);
|
||||||
|
printf("<%x", value);
|
||||||
|
if(os) analysis_short(os, value | 0x80000000);
|
||||||
|
printf(">");
|
||||||
|
break;
|
||||||
|
case PCDISP:
|
||||||
|
addr = pcdisp(pc, d, opsize);
|
||||||
|
value = pcread(pc, d, opsize, &out_of_bounds);
|
||||||
|
|
||||||
|
printf("<%x>", addr);
|
||||||
|
if(out_of_bounds) printf("(out of bounds)");
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("(#0x%0*x", opsize * 2, value);
|
||||||
|
if(os) analysis_short(os, value);
|
||||||
|
printf(")");
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case AT_RN:
|
||||||
|
printf("@r%d", n);
|
||||||
|
break;
|
||||||
|
case AT_RM:
|
||||||
|
printf("@r%d", m);
|
||||||
|
break;
|
||||||
|
case AT_RMP:
|
||||||
|
printf("@r%d+", m);
|
||||||
|
break;
|
||||||
|
case AT_RNP:
|
||||||
|
printf("@r%d+", n);
|
||||||
|
break;
|
||||||
|
case AT_MRN:
|
||||||
|
printf("@-r%d", n);
|
||||||
|
break;
|
||||||
|
case AT_DRN:
|
||||||
|
printf("@(%d, r%d)", d * opsize, n);
|
||||||
|
break;
|
||||||
|
case AT_DRM:
|
||||||
|
printf("@(%d, r%d)", d * opsize, m);
|
||||||
|
break;
|
||||||
|
case AT_R0RN:
|
||||||
|
printf("@(r0, r%d)", n);
|
||||||
|
break;
|
||||||
|
case AT_R0RM:
|
||||||
|
printf("@(r0, r%d)", m);
|
||||||
|
break;
|
||||||
|
case AT_DGBR:
|
||||||
|
printf("@(%d, gbr)", d * opsize);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instruction_output(uint16_t opcode, struct asm_match const *match)
|
||||||
|
{
|
||||||
|
char const *mnemonic = match->insn->mnemonic;
|
||||||
|
printf("%6x: %04x %s", pc, opcode, mnemonic);
|
||||||
|
|
||||||
|
/* Find out operation size */
|
||||||
|
|
||||||
|
size_t n = strlen(mnemonic);
|
||||||
|
int opsize = 0;
|
||||||
|
|
||||||
|
if(n >= 3 && mnemonic[n-2] == '.')
|
||||||
|
{
|
||||||
|
int c = mnemonic[n-1];
|
||||||
|
opsize = (c == 'b') + 2 * (c == 'w') + 4 * (c == 'l');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Output arguments */
|
||||||
|
|
||||||
|
if(!match->insn->arg1) return;
|
||||||
|
printf("%*s", (int)(8-n), "");
|
||||||
|
arg_output(match->insn->arg1, match->insn->literal1, match, opsize);
|
||||||
|
|
||||||
|
if(!match->insn->arg2) return;
|
||||||
|
printf(", ");
|
||||||
|
arg_output(match->insn->arg2, match->insn->literal2, match, opsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instruction_single(uint16_t opcode)
|
||||||
|
{
|
||||||
|
struct asm_match match;
|
||||||
|
asm_decode(opcode, &match, 0);
|
||||||
|
instruction_output(opcode, &match);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void instruction_conflicts(uint16_t opcode, int count)
|
||||||
|
{
|
||||||
|
struct asm_match match;
|
||||||
|
printf("\n # conflicts[%d] on <%x>(%04x)\n", count, pc, opcode);
|
||||||
|
|
||||||
|
for(int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
asm_decode(opcode, &match, i);
|
||||||
|
instruction_output(opcode, &match);
|
||||||
|
printf(" # table '%s'\n", match.table);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* disassembly_os(): Disassemble an address or a syscall */
|
||||||
|
void disassembly_os(struct os const *src, struct disassembly const *opt)
|
||||||
|
{
|
||||||
|
/* Initialize this file's global state */
|
||||||
|
mpu = src->mpu;
|
||||||
|
pc = opt->start;
|
||||||
|
data = src->data;
|
||||||
|
len = src->len;
|
||||||
|
os = src;
|
||||||
|
|
||||||
|
/* Override MPU guesses if user requested a specific platform */
|
||||||
|
if(opt->mpu != MPU_GUESS) mpu = opt->mpu;
|
||||||
|
|
||||||
|
/* Handle situations where the start address is a syscall */
|
||||||
|
if(opt->syscall)
|
||||||
|
{
|
||||||
|
pc = os_syscall(os, opt->start);
|
||||||
|
if(pc == (uint32_t)-1)
|
||||||
|
{
|
||||||
|
err("syscall 0x%04x does not exist", opt->start);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Take physical addresses */
|
||||||
|
pc &= 0x1fffffff;
|
||||||
|
|
||||||
|
/* Cut the length if it reaches past the end of the file */
|
||||||
|
uint32_t limit = (pc + opt->len) & ~1;
|
||||||
|
if(limit > os->len) limit = os->len;
|
||||||
|
|
||||||
|
/* Enforce alignment of PC */
|
||||||
|
if(pc & 1)
|
||||||
|
{
|
||||||
|
err("address is not 2-aligned, skipping 1 byte");
|
||||||
|
pc += 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t *data = os->data;
|
||||||
|
|
||||||
|
while(pc < limit)
|
||||||
|
{
|
||||||
|
if(os)
|
||||||
|
{
|
||||||
|
int syscall = os_syscall_find(os, pc | 0x80000000);
|
||||||
|
if(syscall == -1)
|
||||||
|
syscall = os_syscall_find(os, pc | 0xa0000000);
|
||||||
|
if(syscall != -1)
|
||||||
|
{
|
||||||
|
struct sys_call const *s = sys_find(syscall);
|
||||||
|
printf("\n<%x %%%03x", pc, syscall);
|
||||||
|
if(s) printf(" %s", s->name);
|
||||||
|
printf(">\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t opcode = (data[pc] << 8) | data[pc + 1];
|
||||||
|
int count = matches(opcode);
|
||||||
|
|
||||||
|
if(count == 0) printf("%6x: %04x\n", pc, opcode);
|
||||||
|
else if(count == 1) instruction_single(opcode);
|
||||||
|
else instruction_conflicts(opcode, count);
|
||||||
|
|
||||||
|
pc += 2;
|
||||||
|
}
|
||||||
|
}
|
84
fxos/errors.c
Normal file
84
fxos/errors.c
Normal file
|
@ -0,0 +1,84 @@
|
||||||
|
#include <errors.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#define MAX 32
|
||||||
|
|
||||||
|
/* Array of context strings. */
|
||||||
|
static char const *context[MAX] = { NULL };
|
||||||
|
/* Number of active elements. */
|
||||||
|
static int elements = 0;
|
||||||
|
|
||||||
|
/* push(): Push an element in the context buffer
|
||||||
|
@el New element
|
||||||
|
Returns non-zero if the buffer is full. */
|
||||||
|
static int push(char const *el)
|
||||||
|
{
|
||||||
|
if(elements >= MAX - 2) return 1;
|
||||||
|
context[elements++] = el;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* err_context(): Push one or more context elements */
|
||||||
|
int err_context(char const *context, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, context);
|
||||||
|
int x = 0;
|
||||||
|
|
||||||
|
/* Delimiter between calls to err_context(), for err_pop() */
|
||||||
|
x |= push(NULL);
|
||||||
|
x |= push(context);
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
char const *el = va_arg(args, char const *);
|
||||||
|
if(!el) break;
|
||||||
|
x |= push(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* err_pop(): Pop back context elements */
|
||||||
|
void err_pop(void)
|
||||||
|
{
|
||||||
|
/* Clear everything until the last NULL delimiter */
|
||||||
|
while(--elements >= 0 && context[elements])
|
||||||
|
{
|
||||||
|
context[elements] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void err_debug(void)
|
||||||
|
{
|
||||||
|
for(int i = 0; i < MAX; i++) fprintf(stderr, "%s: ", context[i]);
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* errf(): Emit an error message */
|
||||||
|
void errf(int flags, char const *str, ...)
|
||||||
|
{
|
||||||
|
int saved_errno = errno;
|
||||||
|
|
||||||
|
va_list args;
|
||||||
|
va_start(args, str);
|
||||||
|
|
||||||
|
for(int i = 0; i <= MAX-2 && (context[i] || context[i+1]); i++)
|
||||||
|
{
|
||||||
|
if(context[i]) fprintf(stderr, "%s: ", context[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
vfprintf(stderr, str, args);
|
||||||
|
|
||||||
|
if(flags & ERR_ERRNO)
|
||||||
|
{
|
||||||
|
fprintf(stderr, ": %s", strerror(saved_errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
va_end(args);
|
||||||
|
}
|
63
fxos/errors.h
Normal file
63
fxos/errors.h
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
//---
|
||||||
|
// errors: Error message management
|
||||||
|
//
|
||||||
|
// An attempt at producing elaborate error messages providing context from
|
||||||
|
// multiple function calls, with a small amount of code.
|
||||||
|
//
|
||||||
|
// Basically, caller functions define context and message parameters
|
||||||
|
// before doing anything risky. When an error occurs in a sub-function,
|
||||||
|
// the context is used to prepend relevant information and fill in the
|
||||||
|
// error message where relevant.
|
||||||
|
//
|
||||||
|
// This means that the caller functions must know it advance what kind of
|
||||||
|
// messages can be emitted to accurately set the context. Although it
|
||||||
|
// would work through library calls, it is not very suitable. It's rather
|
||||||
|
// meant for the logic of applications.
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef FXOS_ERRORS
|
||||||
|
#define FXOS_ERRORS
|
||||||
|
|
||||||
|
/* Error levels */
|
||||||
|
#define ERR_CRIT 0x01 /* Aborts part or whole of the program's task */
|
||||||
|
#define ERR_ERR 0x02 /* Unexpected behavior */
|
||||||
|
#define ERR_WARN 0x03 /* Internal consistency issues */
|
||||||
|
#define ERR_LOG 0x04 /* Internal logging */
|
||||||
|
/* Error flags */
|
||||||
|
#define ERR_ERRNO 0x10
|
||||||
|
|
||||||
|
/* err_context(): Push one or more context elements
|
||||||
|
@context Context string, must live until it is popped by err_pop()
|
||||||
|
@... More contexts, same requirements as the first (NULL-terminated)
|
||||||
|
Returns non-zero if the deepest context level (at least 15) is reached. */
|
||||||
|
int err_context(char const *context, ...);
|
||||||
|
|
||||||
|
/* err_pop(): Pop back context elements
|
||||||
|
Pops back all context elements that were added by the previous call to
|
||||||
|
err_context(), no matter their number. */
|
||||||
|
void err_pop(void);
|
||||||
|
|
||||||
|
/* errf(): Emit an error message
|
||||||
|
Error message is printed via fprintf() and supports the same format. All the
|
||||||
|
arguments are passed directly.
|
||||||
|
|
||||||
|
Available flags are any combination of at most one error level:
|
||||||
|
ERR_CRIT -- Unrecoverable error
|
||||||
|
ERR_ERR -- Normal error
|
||||||
|
ERR_WARN -- Warning
|
||||||
|
ERR_LOG -- Logging
|
||||||
|
and any of these boolean flags:
|
||||||
|
ERR_ERRNO -- Also print strerror(errno) as a suffix (as perror()).
|
||||||
|
|
||||||
|
Error levels might be used later on for filtering. Messages without level
|
||||||
|
will always be displayed.
|
||||||
|
|
||||||
|
@flags An OR-combination of the previous flags, or 0
|
||||||
|
@str Error messages
|
||||||
|
@... Arguments to format [str] through fprintf() */
|
||||||
|
void errf(int flags, char const *str, ...);
|
||||||
|
|
||||||
|
/* err(): Short error function */
|
||||||
|
#define err(str, ...) errf(0, str __VA_OPT__(,) __VA_ARGS__)
|
||||||
|
|
||||||
|
#endif /* FXOS_ERRORS */
|
446
fxos/fxos.h
446
fxos/fxos.h
|
@ -6,149 +6,405 @@
|
||||||
#define FX_FXOS
|
#define FX_FXOS
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
/* Microprocessor platforms */
|
/* Microprocessor platforms */
|
||||||
enum mpu
|
enum mpu {
|
||||||
{
|
MPU_GUESS = 0,
|
||||||
mpu_unknown = 0,
|
MPU_SH7705 = 1,
|
||||||
mpu_sh7705 = 1,
|
MPU_SH7305 = 2,
|
||||||
mpu_sh7305 = 2,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Data tables (tables.c)
|
** Memory (memory.c)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* tables_add_asm(): Append an instruction table to the table list
|
/* struct region: A valid memory region for at least one platform */
|
||||||
This function adds a new instruction table to fetch instructions from; it
|
|
||||||
will be consulted if searching any of the previously-declared tables fails.
|
|
||||||
|
|
||||||
@filename Name of instruction table file
|
|
||||||
Returns non-zero on error (and prints a message on stderr) */
|
|
||||||
int tables_add_asm(const char *filename);
|
|
||||||
|
|
||||||
/* tables_add_syscall(): Append a syscall table to the table list
|
|
||||||
This function adds a new syscall table to fetch syscalls information from;
|
|
||||||
if will be consulted if searching any of the previously-declared tables
|
|
||||||
fails.
|
|
||||||
|
|
||||||
@filename Name of instruction table file
|
|
||||||
Returns non-zero on error (and prints a message on stderr) */
|
|
||||||
int tables_add_syscall(const char *filename);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** RAM dumps (ram.c)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Region for a single RAM dump */
|
|
||||||
struct region
|
struct region
|
||||||
{
|
{
|
||||||
uint32_t start;
|
uint32_t start; /* Start address */
|
||||||
uint32_t length;
|
uint32_t end; /* End address */
|
||||||
void *data;
|
char const *name; /* Name, used to identify RAM dump files */
|
||||||
|
enum mpu platform; /* Platform hint or MPU_GUESS */
|
||||||
};
|
};
|
||||||
|
|
||||||
/* RAM dump */
|
/* memory_region(): Find the region where an address is located
|
||||||
struct ram_sh7705
|
Returns NULL if the address points to no valid memory. This function rejects
|
||||||
{
|
addresses of peripheral registers in P3 or P4 space and only heeds for
|
||||||
struct region RAM; /* Usual RAM (256k) */
|
contiguous RAM or ROM areas.
|
||||||
|
|
||||||
|
@address 32-bit virtual memory address
|
||||||
|
Returns a region description matching the address, NULL if none is known.*/
|
||||||
|
struct region const *memory_region(uint32_t address);
|
||||||
|
|
||||||
|
/*
|
||||||
|
** General table storage (tables.c)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* struct table: Parametric data table */
|
||||||
|
struct table {
|
||||||
|
char const *type; /* Table type, set by user */
|
||||||
|
char *name; /* Table name, also set by user */
|
||||||
|
void (*free_item)(void *); /* Function to free individual items */
|
||||||
|
|
||||||
|
int count; /* Number of items in the table */
|
||||||
|
size_t size; /* Size of each item */
|
||||||
|
void *items; /* Table data */
|
||||||
};
|
};
|
||||||
struct ram_sh7305
|
|
||||||
{
|
/* table_available(): Whether a table can be allocated
|
||||||
struct region RAM; /* Usual RAM (512k) */
|
Returns non-zero if there is space left for a new table, zero if not. */
|
||||||
struct region IL; /* On-chip instruction storage (16k) */
|
int table_available(void);
|
||||||
struct region RS; /* On-chip generic storage (2k) */
|
|
||||||
|
/* table_create(): Create a new table
|
||||||
|
Allocates a new table inside the global storage. The created table can be
|
||||||
|
searched immediately with table_find().
|
||||||
|
|
||||||
|
@type Table type, expectedly a string constant
|
||||||
|
@name Name string, this module takes ownership and will free() it
|
||||||
|
@free_item Function to use to destroy items in the future
|
||||||
|
@count Number of items
|
||||||
|
@size Size of each item
|
||||||
|
@items Full data array */
|
||||||
|
void table_create(char const *type, char *name, void (*free_item)(void *),
|
||||||
|
int count, size_t size, void *items);
|
||||||
|
|
||||||
|
/* table_find(): Find matching entries in the database tables
|
||||||
|
|
||||||
|
This function traverses all the tables of type @type and returns all the
|
||||||
|
elements [e] such that [match(e)] is non-zero.
|
||||||
|
|
||||||
|
The search starts with [next=0] and returns the first match; further calls
|
||||||
|
with [next!=0] will return more matching elements until no more are found
|
||||||
|
(in which case this function returns NULL) or this function is called again
|
||||||
|
with [next=0] to start a new search.
|
||||||
|
|
||||||
|
@type Table filter by type
|
||||||
|
@match Match function
|
||||||
|
@name Set to matching table name, if not NULL
|
||||||
|
@next Set it to 0 on the first call, and non-zero after that
|
||||||
|
Returns a match if one is found, NULL otherwise. */
|
||||||
|
void *table_find(char const *type, int (*match)(void *), char const **name,
|
||||||
|
int next);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Assembly tables (asm.c, lexer-asm.l)
|
||||||
|
** These tables reference all assembler instructions used by fxos to
|
||||||
|
** disassemble code. In case of conflict, fxos will disassemble the same
|
||||||
|
** opcode several times.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* struct asm_insn: Entry of an instruction table */
|
||||||
|
struct asm_insn {
|
||||||
|
uint16_t bits; /* Opcode; arbitrary values for arguments */
|
||||||
|
uint16_t arg_mask; /* 1 for constant bits, 0 for arguments */
|
||||||
|
|
||||||
|
/* Position of the arguments */
|
||||||
|
uint8_t n_sh, m_sh, d_sh, i_sh;
|
||||||
|
/* Masks indicating the length of arguments */
|
||||||
|
uint16_t n_mask, m_mask, d_mask, i_mask;
|
||||||
|
|
||||||
|
char *mnemonic; /* NUL-terminated mnemonic */
|
||||||
|
|
||||||
|
int arg1; /* asm_arg member */
|
||||||
|
int arg2; /* asm_arg member */
|
||||||
|
|
||||||
|
char *literal1; /* When arg1 == LITERAL, argument string */
|
||||||
|
char *literal2; /* When arg2 == LITERAL, argument string */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* enum asm_arg: Argument variants */
|
||||||
|
enum asm_arg {
|
||||||
|
LITERAL=1, /* Literal string, eg. "vbr" or "@(r0, gbr)" */
|
||||||
|
IMM, RN, RM, /* "#imm", "rn", "rm" */
|
||||||
|
JUMP8, JUMP12, /* Jump from displacement (PC + disp) */
|
||||||
|
PCDISP, /* PC-displacement with data */
|
||||||
|
AT_RN, AT_RM, /* "@rn", "@rm" */
|
||||||
|
AT_RMP, AT_RNP, AT_MRN, /* Post-increment and pre-decrement */
|
||||||
|
AT_DRN, AT_DRM, /* Displacement structure addressing */
|
||||||
|
AT_R0RN, AT_R0RM, /* r0 structure addressing */
|
||||||
|
AT_DGBR, /* GBR addressing */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* struct asm_match: Matching of a 16-bit code against an instruction
|
||||||
|
Specifies the source instruction and the value of the parameters. The value
|
||||||
|
of [m], [n], [d] or [i] is unspecified for parameters that are not used in
|
||||||
|
the matched instruction's opcode. */
|
||||||
|
struct asm_match {
|
||||||
|
/* Matching instruction */
|
||||||
|
struct asm_insn const *insn;
|
||||||
|
|
||||||
|
char const *table; /* Table name */
|
||||||
|
int m, n, d, i; /* Parameter assignment */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* asm_load(): Load an assembly table
|
||||||
|
Loads all instructions described by @file into a table named "x" is @file's
|
||||||
|
basename is on the form "asm-x.txt" and the whole basename otherwise. The
|
||||||
|
resulting table is available immediately to use with asm_match().
|
||||||
|
|
||||||
|
Skips every row that does not conform to the file's syntax after printing a
|
||||||
|
message to stderr.
|
||||||
|
|
||||||
|
@file Input file path */
|
||||||
|
void asm_load(char const *file);
|
||||||
|
|
||||||
|
/* asm_decode(): Match a 16-bit opcode against the assembly database
|
||||||
|
This function searches matches of a 16-bit instruction code inside the
|
||||||
|
instruction database. Depending on the database files currently loaded,
|
||||||
|
there can be several matches; this function uses static variables to
|
||||||
|
maintain state information through several calls.
|
||||||
|
|
||||||
|
First call this function with [next] set to 0. If there is no match, the
|
||||||
|
call will return non-zero and [*match] will be left unchanged. Otherwise,
|
||||||
|
the first matching instruction will be described in [*match], the call will
|
||||||
|
return 0 and internal static variables will be reset.
|
||||||
|
|
||||||
|
Repeatedly call this function with [next != 0] to get further matches. The
|
||||||
|
search ends when there are no more matches, in which case this function
|
||||||
|
returns non-zero and [*match] is left unchanged. Any non-zero value for
|
||||||
|
[next] is suitable.
|
||||||
|
|
||||||
|
The name of the table providing the match is set in [match->table]. Please
|
||||||
|
bear in mind, though, that table names do not uniquely identify tables.
|
||||||
|
|
||||||
|
@opcode 16-bit opcode to be matched against the database
|
||||||
|
@match Set to a description of the matching instruction (must not be NULL)
|
||||||
|
@next Set it to 0 on the first call, and non-zero after that
|
||||||
|
Returns 0 if a match is found, non-zero otherwise. */
|
||||||
|
int asm_decode(uint16_t opcode, struct asm_match *match, int next);
|
||||||
|
|
||||||
|
/* asm_quit(): Unload all assembly tables
|
||||||
|
Releases all memory held by the assembly table database. */
|
||||||
|
void asm_quit(void);
|
||||||
|
|
||||||
|
/* lex_asm(): Assembly table lexer and parser
|
||||||
|
Lexes and parses string @data of length @length, allocating and filling an
|
||||||
|
instruction array whose size is stored in [*count] if @count is non-NULL.
|
||||||
|
Prints messages to stderr for every syntax error in the file.
|
||||||
|
|
||||||
|
@data Input memory, not NUL-terminated (typically a memory-mapped file)
|
||||||
|
@length Length of input string
|
||||||
|
@count Set to number of successfully decoded instructions if non-NULL
|
||||||
|
Returns a free()able array of decoded instructions. */
|
||||||
|
struct asm_insn *lex_asm(void *data, size_t length, int *count);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Syscall tables (sys.c)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* struct sys_call: Entry of a syscall table */
|
||||||
|
struct sys_call {
|
||||||
|
uint32_t number; /* Syscall number */
|
||||||
|
char *name; /* Symbol or function name */
|
||||||
|
char *descr; /* Prototype or description */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* sys_load(): Load a syscall table
|
||||||
|
Loads a syscall description table. If @file is named "sys-x.txt" then the
|
||||||
|
table name is set to "x", otherwise @file's basename.
|
||||||
|
Prints syntax errors and skips invalid lines.
|
||||||
|
|
||||||
|
@file Input file path */
|
||||||
|
void sys_load(char const *path);
|
||||||
|
|
||||||
|
/* sys_find(): Find information on a given syscall number
|
||||||
|
Traverse the syscall tables currently loaded and returns the first entry
|
||||||
|
matching the provided syscall number, if any is found.
|
||||||
|
|
||||||
|
@number Syscall number
|
||||||
|
Returns a description of the syscall, NULL if none was found. */
|
||||||
|
struct sys_call const *sys_find(uint32_t number);
|
||||||
|
|
||||||
|
/* sys_quit(): Release memory held by the syscall tables */
|
||||||
|
void sys_quit(void);
|
||||||
|
|
||||||
|
/* lex_sys(): Syscall table lexer and parser
|
||||||
|
Lexes and parses string @data of length @len, allocating and filling a
|
||||||
|
syscall array whose size is stored in [*count] if @count is not NULL.
|
||||||
|
Prints syntax errors on stderr.
|
||||||
|
|
||||||
|
@data Input memory (typically memory-mapped file)
|
||||||
|
@len Length of input
|
||||||
|
@count Set to number of decoded entries if not NULL
|
||||||
|
Returns a free()able table of decoded syscall entries. */
|
||||||
|
struct sys_call *lex_sys(void *data, size_t len, int *count);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Peripheral register tables (reg.c)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* struct reg_address: Entry of a peripheral register table */
|
||||||
|
struct reg_address {
|
||||||
|
uint32_t address; /* Register address */
|
||||||
|
char *name; /* Typically an upper-case dotted specifier */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/* reg_load(): Load a peripheral register table
|
||||||
|
Loads a peripheral register listing. If @file is named "reg-x.txt" then the
|
||||||
|
table name is set to "x", otherwise @file's basename.
|
||||||
|
Prints syntax errors and skips invalid lines. Loaded data is available
|
||||||
|
immediately through reg_find().
|
||||||
|
|
||||||
|
@file Input file path */
|
||||||
|
void reg_load(char const *path);
|
||||||
|
|
||||||
|
/* reg_find(): Find information on a given peripheral register address
|
||||||
|
Looks up the loaded tables and returns the first entry matching the given
|
||||||
|
address (if any).
|
||||||
|
|
||||||
|
@address Any input address
|
||||||
|
Returns a pointer to the matching register, NULL if none was found. */
|
||||||
|
struct reg_address const *reg_find(uint32_t address);
|
||||||
|
|
||||||
|
/* reg_quit(): Release memory held by the peripheral register tables */
|
||||||
|
void reg_quit(void);
|
||||||
|
|
||||||
|
/* lex_reg(): Peripheral register table lexer and parser
|
||||||
|
Lexes and parses @data (of length @length). Allocates and fills a register
|
||||||
|
description array and stores its size in [*count] if @count is not NULL.
|
||||||
|
Prints messages on stderr if there are syntax errors.
|
||||||
|
|
||||||
|
@data Input string (needs not be NUL-terminated)
|
||||||
|
@len Length of input
|
||||||
|
@count Set to the number of decoded register addresses, if not NULL
|
||||||
|
Returns a free()able table with the decoded data. */
|
||||||
|
struct reg_address *lex_reg(void *data, size_t len, int *count);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
** General OS operations (os.c)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* struct os: Basic OS information */
|
||||||
|
struct os {
|
||||||
|
void *data; /* Operating system dump */
|
||||||
|
size_t len; /* File length */
|
||||||
|
int fd; /* Underlying file descriptor */
|
||||||
|
|
||||||
|
char version[15]; /* NUL-terminated OS version string */
|
||||||
|
enum mpu mpu; /* User-provided or guessed MPU type */
|
||||||
|
|
||||||
|
uint32_t syscall_table; /* Syscall table address */
|
||||||
|
int syscalls; /* Number of valid syscalls found */
|
||||||
|
|
||||||
|
uint32_t footer; /* Footer address (-1 if not found) */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* os_load(): Load an OS file and find out basic properties
|
||||||
|
Guesses the MPU type, finds the syscall table and its size, finds the footer
|
||||||
|
address.
|
||||||
|
|
||||||
|
@path File path
|
||||||
|
@os Will be filled with loaded data and information
|
||||||
|
Returns non-zero in case of loading error or file format error. */
|
||||||
|
int os_load(char const *path, struct os *os);
|
||||||
|
|
||||||
|
/* os_syscall(): Get the address of a syscall entry
|
||||||
|
Does not check bounds, only returns (uint32_t)-1 if the requested entry of
|
||||||
|
the table is past the end of the file.
|
||||||
|
|
||||||
|
@os Source OS
|
||||||
|
@syscall Syscall entry number
|
||||||
|
Returns the syscall address. */
|
||||||
|
uint32_t os_syscall(struct os const *os, int syscall);
|
||||||
|
|
||||||
|
/* os_syscall_find(): Find a syscall which points to an address
|
||||||
|
This function looks for a syscall entry (among the ones that point to valid
|
||||||
|
memory) whose value is @entry.
|
||||||
|
|
||||||
|
@os Loaded OS structure
|
||||||
|
@entry Researched value
|
||||||
|
Returns a syscall ID if some is found, -1 otherwise. */
|
||||||
|
int os_syscall_find(struct os const *os, uint32_t entry);
|
||||||
|
|
||||||
|
/* os_free(): Free an OS file opened with os_load()
|
||||||
|
@os Loaded OS structure */
|
||||||
|
void os_free(struct os const *os);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** File identification (info.c)
|
** File identification (info.c)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Info options */
|
/* info_os(): Print general information on an OS file
|
||||||
struct info
|
|
||||||
{
|
|
||||||
/* OS file (0) or binary file (1) */
|
|
||||||
int binary;
|
|
||||||
/* Force underlying architecture */
|
|
||||||
enum mpu mpu;
|
|
||||||
|
|
||||||
/* RAM dumps, if any */
|
This function prints the OS metadata, traverses the syscall table, and
|
||||||
union {
|
shows a few details of known binary regions such as the footer.
|
||||||
struct ram_sh7705 ram3;
|
|
||||||
struct ram_sh7305 ram4;
|
@os Input OS file */
|
||||||
};
|
void info_os(struct os const *os);
|
||||||
};
|
|
||||||
|
/* info_binary(): Print general information on a binary file
|
||||||
|
|
||||||
|
This function tries to determine the platform by looking for SH4-only
|
||||||
|
instructions or SH7705 and SH7305-specific registers addresses. The analysis
|
||||||
|
results are printed on stdout.
|
||||||
|
|
||||||
|
@data Input file data (memory-mapped)
|
||||||
|
@len Length of input */
|
||||||
|
void info_binary(void *data, size_t len);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Disassembling (disassembly.c)
|
** Disassembling (disassembly.c)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Disassembly options */
|
/* struct disassembly: Disassembly options */
|
||||||
struct disassembly
|
struct disassembly
|
||||||
{
|
{
|
||||||
/* OS file (0) or binary file (1) */
|
int binary; /* OS file (0) or binary file (1) */
|
||||||
int binary;
|
enum mpu mpu; /* Force architecture (or MPU_GUESS) */
|
||||||
/* Force underlying architecture */
|
|
||||||
enum mpu mpu;
|
|
||||||
|
|
||||||
/* RAM dumps, if any */
|
uint32_t start; /* Start address or syscall ID */
|
||||||
union {
|
int syscall; /* Non-zero if [start] is a syscall ID */
|
||||||
struct ram_sh7705 ram3;
|
uint32_t len; /* Length of disassembled region */
|
||||||
struct ram_sh7305 ram4;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Start address */
|
|
||||||
uint32_t start;
|
|
||||||
/* Length of disassembled region */
|
|
||||||
uint32_t length;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* disassembly_os(): Disassemble an address or a syscall
|
||||||
|
Produces a disassembly listing of the program on stdout, annotated with
|
||||||
|
every piece of information that can be extracted from the OS.
|
||||||
|
|
||||||
|
@os Operating system image to disassemble
|
||||||
|
@opt Disassembly region and options */
|
||||||
|
void disassembly_os(struct os const *os, struct disassembly const *opt);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Blind analysis (analysis.c)
|
** Blind analysis (analysis.c)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Analysis options */
|
/* analysis_short(): Print a one-line summary for an address
|
||||||
|
Prints a list of space-separated elements summarizing the information that
|
||||||
|
can be found about the provided value (typically an address). This summary
|
||||||
|
is often inserted in disassembled code as annotation.
|
||||||
|
|
||||||
|
@os Source OS
|
||||||
|
@value Analyzed value, often an address */
|
||||||
|
void analysis_short(struct os const *os, uint32_t value);
|
||||||
|
|
||||||
|
/* struct analysis: In-depth analysis options */
|
||||||
struct analysis
|
struct analysis
|
||||||
{
|
{
|
||||||
/* Force underlying architecture */
|
/* Force underlying architecture */
|
||||||
enum mpu mpu;
|
enum mpu mpu;
|
||||||
|
|
||||||
/* RAM dumps, if any */
|
|
||||||
union {
|
|
||||||
struct ram_sh7705 ram3;
|
|
||||||
struct ram_sh7305 ram4;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Analysis mode */
|
/* Analysis mode */
|
||||||
enum {
|
enum {
|
||||||
ANALYSIS_FULL = 0,
|
ANALYSIS_SYSCALL = 0x01,
|
||||||
ANALYSIS_SYSCALL = 1,
|
ANALYSIS_ADDRESS = 0x02,
|
||||||
ANALYSIS_ADDRESS = 2,
|
ANALYSIS_REGISTER = 0x04,
|
||||||
ANALYSIS_REGISTER = 3,
|
|
||||||
|
ANALYSIS_FULL = 0x07,
|
||||||
} type;
|
} type;
|
||||||
|
|
||||||
/* Max number of printed occurrences */
|
/* Max number of printed occurrences */
|
||||||
int occurrences;
|
int occurrences;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Utility functions (util.c)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* integer(): Convert base 8, 10 or 16 into integers
|
|
||||||
Prints an error message and sets *error to 1 in case of conversion error or
|
|
||||||
overflow.
|
|
||||||
|
|
||||||
@str Original integer representation ("10", "0x1f", "07")
|
|
||||||
@error Set to 1 on error, otherwise unchanged (can be NULL)
|
|
||||||
Returns result of conversion (valid if *error is not 1) */
|
|
||||||
long long integer(const char *str, int *error);
|
|
||||||
|
|
||||||
#endif /* FX_FXOS */
|
#endif /* FX_FXOS */
|
||||||
|
|
120
fxos/info.c
Normal file
120
fxos/info.c
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <endian.h>
|
||||||
|
|
||||||
|
char const *info_str =
|
||||||
|
"Header information:\n"
|
||||||
|
" Bootcode timestamp (DateA) (0x8000ffb0) : %s\n"
|
||||||
|
" Serial number (0x8000ffd0) : %s\n"
|
||||||
|
" Bootcode checksum (0x8000fffc) : 0x%s\n"
|
||||||
|
" OS version (0x80010020) : %s\n";
|
||||||
|
|
||||||
|
char const *footer_str =
|
||||||
|
"\nFooter information:\n"
|
||||||
|
" Detected footer address : 0x8%07x\n"
|
||||||
|
" Langdata entries found : %d\n"
|
||||||
|
" OS date (DateO) (0x8%07x)" " : %s\n"
|
||||||
|
" OS checksum (0x8%07x)" " : 0x%s\n";
|
||||||
|
|
||||||
|
char const *syscall_str =
|
||||||
|
"\nSyscall information:\n"
|
||||||
|
" Syscall table address (0x8001007c) : 0x%08x\n"
|
||||||
|
" Entries that point to valid memory : 0x%x\n"
|
||||||
|
" First seemingly invalid entry : 0x%08x\n"
|
||||||
|
" Syscall entries outside ROM:\n";
|
||||||
|
|
||||||
|
char const *syscall_nonrom_str =
|
||||||
|
" %%%04x -> 0x%08x (%s memory)\n";
|
||||||
|
|
||||||
|
/* extract_str(): Extract a string from the OS file
|
||||||
|
This function checks offsets and bounds and writes "(eof)" if the provided
|
||||||
|
file is too small for the tested offset. */
|
||||||
|
static void extract_str(struct os const * os, uint32_t address, size_t size,
|
||||||
|
char *dst)
|
||||||
|
{
|
||||||
|
if(address + size > os->len)
|
||||||
|
{
|
||||||
|
strcpy(dst, "(eof)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(dst, os->data + address, size);
|
||||||
|
dst[size] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* extract_int(): Extract a string from the OS file */
|
||||||
|
static void extract_int(struct os const *os, uint32_t address, char *dst)
|
||||||
|
{
|
||||||
|
if(address + 4 > os->len)
|
||||||
|
{
|
||||||
|
strcpy(dst, "(eof)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t x;
|
||||||
|
memcpy(&x, os->data + address, 4);
|
||||||
|
x = be32toh(x);
|
||||||
|
sprintf(dst, "%08x", x);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* info_os(): Print general information on an OS file */
|
||||||
|
void info_os(struct os const *os)
|
||||||
|
{
|
||||||
|
void *data = os->data;
|
||||||
|
size_t len = os->len;
|
||||||
|
|
||||||
|
char bios_timestamp[15];
|
||||||
|
extract_str(os, 0xffb0, 14, bios_timestamp);
|
||||||
|
|
||||||
|
char serial[9];
|
||||||
|
extract_str(os, 0xffd0, 8, serial);
|
||||||
|
|
||||||
|
char bios_checksum[9];
|
||||||
|
extract_int(os, 0xfffc, bios_checksum);
|
||||||
|
|
||||||
|
printf(info_str, bios_timestamp, serial, bios_checksum, os->version);
|
||||||
|
|
||||||
|
if(os->footer == (uint32_t)-1)
|
||||||
|
{
|
||||||
|
printf("\nFooter could not be found.\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
uint32_t addr = os->footer + 8;
|
||||||
|
int langdata = 0;
|
||||||
|
|
||||||
|
while(addr + 8 < len && !memcmp(data + addr, "Langdata", 8))
|
||||||
|
{
|
||||||
|
langdata++;
|
||||||
|
addr += 0x30;
|
||||||
|
}
|
||||||
|
|
||||||
|
char os_timestamp[15];
|
||||||
|
extract_str(os, addr, 14, os_timestamp);
|
||||||
|
|
||||||
|
char os_checksum[9];
|
||||||
|
extract_int(os, addr + 0x18, os_checksum);
|
||||||
|
|
||||||
|
printf(footer_str, os->footer, langdata, addr, os_timestamp,
|
||||||
|
addr + 0x18, os_checksum);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(syscall_str, os->syscall_table, os->syscalls,
|
||||||
|
os_syscall(os, os->syscalls));
|
||||||
|
|
||||||
|
int total = 0;
|
||||||
|
for(int i = 0; i < os->syscalls; i++)
|
||||||
|
{
|
||||||
|
uint32_t e = os_syscall(os, i);
|
||||||
|
struct region const *r = memory_region(e);
|
||||||
|
if(!r || !strcmp(r->name, "ROM")) continue;
|
||||||
|
|
||||||
|
printf(syscall_nonrom_str, i, e, r->name);
|
||||||
|
total++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!total) printf(" (none)\n");
|
||||||
|
}
|
187
fxos/lexer-asm.l
Normal file
187
fxos/lexer-asm.l
Normal file
|
@ -0,0 +1,187 @@
|
||||||
|
%{
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
/* Text value for parser */
|
||||||
|
static char *yylval;
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%option prefix="asm"
|
||||||
|
%option noyywrap
|
||||||
|
%option nounput
|
||||||
|
|
||||||
|
code ^[01nmdi]{16}
|
||||||
|
literal [^ ,\t\n]+|[^ ,\t\n(]*"("[^")"\n]*")"[^ ,\t\n]*
|
||||||
|
|
||||||
|
space [ \t]+
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
^#[^\n]* ;
|
||||||
|
{space} ;
|
||||||
|
, ;
|
||||||
|
[\n] yylineno++;
|
||||||
|
|
||||||
|
{code} { yylval = strdup(yytext); return 0; }
|
||||||
|
^.{0,16} { err("%d: invalid opcode at start of line", yylineno); }
|
||||||
|
|
||||||
|
"#imm" { return IMM; }
|
||||||
|
"rn" { return RN; }
|
||||||
|
"rm" { return RM; }
|
||||||
|
"jump8" { return JUMP8; }
|
||||||
|
"jump12" { return JUMP12; }
|
||||||
|
"pcdisp" { return PCDISP; }
|
||||||
|
"@rn" { return AT_RN; }
|
||||||
|
"@rm" { return AT_RM; }
|
||||||
|
"@rm+" { return AT_RMP; }
|
||||||
|
"@rn+" { return AT_RNP; }
|
||||||
|
"@-rn" { return AT_MRN; }
|
||||||
|
"@(disp,"[ ]*"rn)" { return AT_DRN; }
|
||||||
|
"@(disp,"[ ]*"rm)" { return AT_DRM; }
|
||||||
|
"@(r0,"[ ]*"rn)" { return AT_R0RN; }
|
||||||
|
"@(r0,"[ ]*"rm)" { return AT_R0RM; }
|
||||||
|
"@(disp",[ ]*"gbr)" { return AT_DGBR; }
|
||||||
|
{literal} { yylval = strdup(yytext); return LITERAL; }
|
||||||
|
|
||||||
|
<<EOF>> { return -1; }
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* set_code(): Build an efficient representation of an opcode
|
||||||
|
Takes a 16-byte string as argument, representing the parameterized opcode,
|
||||||
|
and computes a bit-based representation inside the assembly structure.
|
||||||
|
|
||||||
|
@code 16-bit opcode made of '0', '1', 'm', 'n', 'd' and 'i'
|
||||||
|
@insn Instruction object */
|
||||||
|
void set_code(char const *code, struct asm_insn *insn)
|
||||||
|
{
|
||||||
|
insn->bits = insn->arg_mask = 0;
|
||||||
|
insn->n_sh = insn->n_mask = 0;
|
||||||
|
insn->m_sh = insn->m_mask = 0;
|
||||||
|
insn->d_sh = insn->d_mask = 0;
|
||||||
|
insn->i_sh = insn->i_mask = 0;
|
||||||
|
|
||||||
|
for(int i = 0; i < 16; i++)
|
||||||
|
{
|
||||||
|
int c = code[i];
|
||||||
|
|
||||||
|
/* Constant bits */
|
||||||
|
if(c == '0' || c == '1')
|
||||||
|
{
|
||||||
|
insn->bits = (insn->bits << 1) | (c - '0');
|
||||||
|
insn->arg_mask <<= 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Argument bits */
|
||||||
|
insn->bits <<= 1;
|
||||||
|
insn->arg_mask = (insn->arg_mask << 1) | 1;
|
||||||
|
|
||||||
|
if(c == 'n')
|
||||||
|
{
|
||||||
|
insn->n_sh = 15 - i;
|
||||||
|
insn->n_mask = (insn->n_mask << 1) | 1;
|
||||||
|
}
|
||||||
|
if(c == 'm')
|
||||||
|
{
|
||||||
|
insn->m_sh = 15 - i;
|
||||||
|
insn->m_mask = (insn->m_mask << 1) | 1;
|
||||||
|
}
|
||||||
|
if(c == 'd')
|
||||||
|
{
|
||||||
|
insn->d_sh = 15 - i;
|
||||||
|
insn->d_mask = (insn->d_mask << 1) | 1;
|
||||||
|
}
|
||||||
|
if(c == 'i')
|
||||||
|
{
|
||||||
|
insn->i_sh = 15 - i;
|
||||||
|
insn->i_mask = (insn->i_mask << 1) | 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
insn->arg_mask = ~insn->arg_mask;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* lex_asm(): Assembly table lexer and parser */
|
||||||
|
struct asm_insn *lex_asm(void *data, size_t length, int *count)
|
||||||
|
{
|
||||||
|
/* First count the number of instruction codes */
|
||||||
|
|
||||||
|
YY_BUFFER_STATE buf = yy_scan_bytes(data, length);
|
||||||
|
yylineno = 1;
|
||||||
|
|
||||||
|
int total = 0, t;
|
||||||
|
while((t = yylex()) != -1)
|
||||||
|
{
|
||||||
|
total += (t == 0);
|
||||||
|
if(t == 0 || t == LITERAL) free(yylval);
|
||||||
|
}
|
||||||
|
|
||||||
|
yy_delete_buffer(buf);
|
||||||
|
|
||||||
|
/* Allocate a large enough instruction array */
|
||||||
|
|
||||||
|
struct asm_insn *table = calloc(total, sizeof *table);
|
||||||
|
if(!table)
|
||||||
|
{
|
||||||
|
errf(ERR_ERRNO, "cannot allocate memory for database");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lex all instructions and fill in the array */
|
||||||
|
|
||||||
|
buf = yy_scan_bytes(data, length);
|
||||||
|
yylineno = 1;
|
||||||
|
|
||||||
|
struct asm_insn *insn = table - 1;
|
||||||
|
int line = -1;
|
||||||
|
int named = 1;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
t = yylex();
|
||||||
|
|
||||||
|
if(yylineno != line || t == 0 || t == -1)
|
||||||
|
{
|
||||||
|
/* Finalize current instruction */
|
||||||
|
if(!named) err("%d: unnamed instruction", line);
|
||||||
|
insn++;
|
||||||
|
}
|
||||||
|
if(t == -1) break;
|
||||||
|
|
||||||
|
if(t == 0)
|
||||||
|
{
|
||||||
|
set_code(yylval, insn);
|
||||||
|
free(yylval);
|
||||||
|
line = yylineno;
|
||||||
|
named = 0;
|
||||||
|
}
|
||||||
|
else if(t == LITERAL && !named)
|
||||||
|
{
|
||||||
|
insn->mnemonic = yylval;
|
||||||
|
named = 1;
|
||||||
|
}
|
||||||
|
else if(!named)
|
||||||
|
{
|
||||||
|
err("%d: missing mnemonic", line);
|
||||||
|
}
|
||||||
|
else if(!insn->arg1)
|
||||||
|
{
|
||||||
|
insn->arg1 = t;
|
||||||
|
if(t == LITERAL) insn->literal1 = yylval;
|
||||||
|
}
|
||||||
|
else if(!insn->arg2)
|
||||||
|
{
|
||||||
|
insn->arg2 = t;
|
||||||
|
if(t == LITERAL) insn->literal2 = yylval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yy_delete_buffer(buf);
|
||||||
|
if(count) *count = insn - table;
|
||||||
|
return table;
|
||||||
|
}
|
117
fxos/lexer-reg.l
Normal file
117
fxos/lexer-reg.l
Normal file
|
@ -0,0 +1,117 @@
|
||||||
|
%{
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
/* Values for tokens generated by the lexer */
|
||||||
|
static union {
|
||||||
|
char *text;
|
||||||
|
long long integer;
|
||||||
|
} yylval;
|
||||||
|
|
||||||
|
/* Token list */
|
||||||
|
#define NUMBER 0
|
||||||
|
#define SYMBOL 1
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%option prefix="reg"
|
||||||
|
%option noyywrap
|
||||||
|
%option nounput
|
||||||
|
|
||||||
|
decimal 0|[1-9][0-9]*
|
||||||
|
octal 0[0-7]+
|
||||||
|
hexa 0x[0-9a-fA-F]+
|
||||||
|
number {decimal}|{octal}|{hexa}
|
||||||
|
|
||||||
|
symbol [^0-9 \t\n][^\n]*
|
||||||
|
|
||||||
|
space [ \t]+
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
^#[^\n]* ;
|
||||||
|
{space} ;
|
||||||
|
[\n] yylineno++;
|
||||||
|
|
||||||
|
{number} { yylval.integer = integer(yytext, NULL); return NUMBER; }
|
||||||
|
{symbol} { yylval.text = strdup(yytext); return SYMBOL; }
|
||||||
|
|
||||||
|
<<EOF>> return -1;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* lex_reg(): Peripheral register table lexer and parser */
|
||||||
|
struct reg_address *lex_reg(void *data, size_t len, int *count)
|
||||||
|
{
|
||||||
|
/* Count number of register descriptions (upper bound) */
|
||||||
|
|
||||||
|
YY_BUFFER_STATE buf = yy_scan_bytes(data, len);
|
||||||
|
yylineno = 1;
|
||||||
|
|
||||||
|
int total = 0, t;
|
||||||
|
while((t = yylex()) != -1)
|
||||||
|
{
|
||||||
|
total += (t == NUMBER);
|
||||||
|
if(t == SYMBOL) free(yylval.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
yy_delete_buffer(buf);
|
||||||
|
|
||||||
|
/* Allocate a large enough register array */
|
||||||
|
|
||||||
|
struct reg_address *table = calloc(total, sizeof *table);
|
||||||
|
if(!table)
|
||||||
|
{
|
||||||
|
errf(ERR_ERRNO, "cannot allocate memory for database");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lex all instructions and fill in the array */
|
||||||
|
|
||||||
|
buf = yy_scan_bytes(data, len);
|
||||||
|
yylineno = 1;
|
||||||
|
|
||||||
|
struct reg_address *reg = table - 1;
|
||||||
|
int line = -1;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
t = yylex();
|
||||||
|
|
||||||
|
if(t == NUMBER || t == -1)
|
||||||
|
{
|
||||||
|
/* Finalize current instruction */
|
||||||
|
if(reg >= table && !reg->name)
|
||||||
|
err("%d: unnamed register", line);
|
||||||
|
else reg++;
|
||||||
|
}
|
||||||
|
if(t == -1) break;
|
||||||
|
|
||||||
|
if(t == NUMBER)
|
||||||
|
{
|
||||||
|
reg->address = yylval.integer;
|
||||||
|
line = yylineno;
|
||||||
|
}
|
||||||
|
else if(t == SYMBOL && reg < table)
|
||||||
|
{
|
||||||
|
err("%d: expected register address", yylineno);
|
||||||
|
free(yylval.text);
|
||||||
|
}
|
||||||
|
else if(t == SYMBOL && !reg->name)
|
||||||
|
{
|
||||||
|
reg->name = yylval.text;
|
||||||
|
}
|
||||||
|
else if(t == SYMBOL)
|
||||||
|
{
|
||||||
|
err("%d: excess names for 0x%08x\n", reg->address);
|
||||||
|
free(yylval.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yy_delete_buffer(buf);
|
||||||
|
if(count) *count = reg - table;
|
||||||
|
return table;
|
||||||
|
}
|
123
fxos/lexer-sys.l
Normal file
123
fxos/lexer-sys.l
Normal file
|
@ -0,0 +1,123 @@
|
||||||
|
%{
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
/* Values for tokens generated by the lexer */
|
||||||
|
static union {
|
||||||
|
char *text;
|
||||||
|
long long integer;
|
||||||
|
} yylval;
|
||||||
|
|
||||||
|
/* Token list */
|
||||||
|
#define NUMBER 0
|
||||||
|
#define TEXT 1
|
||||||
|
|
||||||
|
%}
|
||||||
|
|
||||||
|
%option prefix="sys"
|
||||||
|
%option noyywrap
|
||||||
|
%option nounput
|
||||||
|
|
||||||
|
decimal 0|[1-9][0-9]*
|
||||||
|
octal 0[0-7]+
|
||||||
|
hexa 0x[0-9a-fA-F]+
|
||||||
|
number {decimal}|{octal}|{hexa}
|
||||||
|
|
||||||
|
space [ \t]+
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
^#[^\n]* ;
|
||||||
|
{space} ;
|
||||||
|
[\n] yylineno++;
|
||||||
|
|
||||||
|
{number} { yylval.integer = integer(yytext, NULL); return NUMBER; }
|
||||||
|
[^ \t\n0-9].* { yylval.text = strdup(yytext); return TEXT; }
|
||||||
|
|
||||||
|
<<EOF>> return -1;
|
||||||
|
|
||||||
|
%%
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
/* lex_sys(): Syscall table lexer and parser */
|
||||||
|
struct sys_call *lex_sys(void *data, size_t len, int *count)
|
||||||
|
{
|
||||||
|
/* Count the number of syscalls */
|
||||||
|
|
||||||
|
YY_BUFFER_STATE buf = yy_scan_bytes(data, len);
|
||||||
|
yylineno = 1;
|
||||||
|
|
||||||
|
int total = 0, t;
|
||||||
|
while((t = yylex()) != -1)
|
||||||
|
{
|
||||||
|
total += (t == NUMBER);
|
||||||
|
if(t == TEXT) free(yylval.text);
|
||||||
|
}
|
||||||
|
|
||||||
|
yy_delete_buffer(buf);
|
||||||
|
|
||||||
|
/* Allocate a large enough syscall array */
|
||||||
|
|
||||||
|
struct sys_call *table = calloc(total, sizeof *table);
|
||||||
|
if(!table)
|
||||||
|
{
|
||||||
|
errf(ERR_ERRNO, "cannot allocate memory for database");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lex all instructions and fill in the array */
|
||||||
|
|
||||||
|
buf = yy_scan_bytes(data, len);
|
||||||
|
yylineno = 1;
|
||||||
|
|
||||||
|
struct sys_call *call = table - 1;
|
||||||
|
int line = -1;
|
||||||
|
int named = 1;
|
||||||
|
|
||||||
|
while(1)
|
||||||
|
{
|
||||||
|
t = yylex();
|
||||||
|
|
||||||
|
if(t == NUMBER || t == -1)
|
||||||
|
{
|
||||||
|
/* Finalize current instruction */
|
||||||
|
if(!named) err("%d: unnamed syscall", line);
|
||||||
|
else call++;
|
||||||
|
}
|
||||||
|
if(t == -1) break;
|
||||||
|
|
||||||
|
if(t == NUMBER)
|
||||||
|
{
|
||||||
|
call->number = yylval.integer;
|
||||||
|
line = yylineno;
|
||||||
|
named = 0;
|
||||||
|
}
|
||||||
|
else if(t == TEXT && call < table)
|
||||||
|
{
|
||||||
|
err("%d: expected syscall id", yylineno);
|
||||||
|
free(yylval.text);
|
||||||
|
}
|
||||||
|
else if(t == TEXT && named == 0)
|
||||||
|
{
|
||||||
|
call->name = yylval.text;
|
||||||
|
named = 1;
|
||||||
|
}
|
||||||
|
else if(t == TEXT && named == 1)
|
||||||
|
{
|
||||||
|
call->descr = yylval.text;
|
||||||
|
named = 2;
|
||||||
|
}
|
||||||
|
else if(t == TEXT)
|
||||||
|
{
|
||||||
|
err("%d: excess qualifiers for syscall 0x%03x", line,
|
||||||
|
call->number);
|
||||||
|
free(yylval.text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yy_delete_buffer(buf);
|
||||||
|
if(count) *count = call - table;
|
||||||
|
return table;
|
||||||
|
}
|
354
fxos/main.c
354
fxos/main.c
|
@ -4,144 +4,253 @@
|
||||||
#include <getopt.h>
|
#include <getopt.h>
|
||||||
|
|
||||||
#include <fxos.h>
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
static const char *help_string =
|
static char const *help_string =
|
||||||
"usage: %1$s info (<os file> | -b <binary file>)\n"
|
"usage: %1$s info (<os file> | -b <binary file>)\n"
|
||||||
" %1$s disasm <os file> (-a <address> | -s <syscall id>) [options...]\n"
|
" %1$s disasm <os file> (-a <address> | -s <syscall id>) [options...]\n"
|
||||||
" %1$s disasm -b <binary file> [options...]\n"
|
" %1$s disasm -b <binary file> [options...]\n"
|
||||||
" %1$s analyze [-f|-s|-a|-r] <number> <os file> [options...]\n"
|
" %1$s analyze [-f] [-s] [-a] [-r] <number> <os file> [options...]\n"
|
||||||
"\n"
|
"\n"
|
||||||
"fxos disassembles or analyzes binary and OS files for efficient reverse-\n"
|
"fxos is a reverse-engineering tool to disassemble and analyze fx9860g-like\n"
|
||||||
"engineering. It currently only supports fx9860g binaries.\n"
|
"OS dumps, providing efficient annotations through an editable database.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Commands:\n"
|
"Commands:\n"
|
||||||
" info Identify an OS image: version, platform, date, checksums...\n"
|
" info Identify an OS image: version, platform, date, checksums...\n"
|
||||||
" Identify the architecture of a binary file.\n"
|
" Identify the architecture of a binary file.\n"
|
||||||
" disasm Disassemble and annotate code with relative address targets,\n"
|
" disasm Disassemble and annotate code with relative address targets,\n"
|
||||||
" syscall invocations and hints about memory structure.\n"
|
" syscall invocations and hints about memory structure.\n"
|
||||||
" analyze Dig an address or syscall number, finding syscall call graph,\n"
|
" analyze Dig an address or syscall number, finding syscall references,\n"
|
||||||
" 4-aligned occurrences, memory region and probable role.\n"
|
" 4-aligned occurrences, memory region and probable role.\n"
|
||||||
"\n"
|
"\n"
|
||||||
"General options:\n"
|
"General options:\n"
|
||||||
" -b Disassemble any binary file, not an OS file\n"
|
" -b Work with an arbitrary binary file, not an OS\n"
|
||||||
" -3, --sh3 Assume SH3 OS and platform (default: guess)\n"
|
|
||||||
" -4, --sh4 Assume SH4 OS and platform (default: guess)\n"
|
|
||||||
" --ram <folder> Read RAM dumps from <folder>\n"
|
|
||||||
" --table-asm <file> Read more instruction patterns in <file>\n"
|
|
||||||
" --table-call <file> Read more syscall prototypes in <file>\n"
|
|
||||||
"\n"
|
"\n"
|
||||||
"Disassembly region options:\n"
|
"Table extensions:\n"
|
||||||
|
" --table-asm <file> Use instruction codes and mnemonics from <file>\n"
|
||||||
|
" --table-sys <file> Use syscall prototypes and descriptions from <file>\n"
|
||||||
|
" --table-reg <file> Use peripheral register addresses from <file>\n"
|
||||||
|
"\n"
|
||||||
|
"Disassembly options:\n"
|
||||||
" -a <address> Start disassembling at this address\n"
|
" -a <address> Start disassembling at this address\n"
|
||||||
" -s <syscall id> Start disassembling at this syscall's address\n"
|
" -s <syscall id> Start disassembling at this syscall's address\n"
|
||||||
" -l <length> Length of region\n"
|
" -l <length> Length of region\n"
|
||||||
|
" -3, --sh3 Assume SH3 OS and platform (default: guess)\n"
|
||||||
|
" -4, --sh4 Assume SH4 OS and platform (default: guess)\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Analysis modes:\n"
|
"Analysis modes:\n"
|
||||||
" -f, --full Find everything that can be known about <number>\n"
|
" -f, --full Run all analysis passes on <number> (same as -sar)\n"
|
||||||
" -s, --syscall <number> is a syscall ID\n"
|
" -s, --syscall Run syscall ID analysis\n"
|
||||||
" -a, --address <number> is a code/data address in ROM or RAM\n"
|
" -a, --address Run code/data address analyis\n"
|
||||||
" -r, --register <number> is a register or peripheral address\n"
|
" -r, --register Run peripheral register analysis\n"
|
||||||
"\n"
|
"\n"
|
||||||
"Analysis options:\n"
|
"Analysis options:\n"
|
||||||
" --occurrences <num> Show at most <num> occurrences (integer or \"all\")\n";
|
" --occurrences <num> Show at most <num> occurrences (integer or \"all\")\n"
|
||||||
|
"\n"
|
||||||
|
"All numbers support base prefixes '0' (octal) and '0x' (hexadecimal).\n";
|
||||||
|
|
||||||
/* "Low-level" command-line option set */
|
#define OPT_ASM 1
|
||||||
struct options
|
#define OPT_SYS 2
|
||||||
|
#define OPT_REG 3
|
||||||
|
#define OPT_OCC 4
|
||||||
|
|
||||||
|
/*
|
||||||
|
** "info" command
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main_info(int argc, char **argv)
|
||||||
{
|
{
|
||||||
const char *input;
|
int error=0, option=0, binary=0;
|
||||||
|
|
||||||
int target;
|
struct option const longs[] = {
|
||||||
const char *ram;
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
};
|
||||||
|
|
||||||
const char *a;
|
while(option >= 0 && option != '?')
|
||||||
const char *s;
|
switch((option = getopt_long(argc, argv, "hb", longs, NULL)))
|
||||||
size_t l;
|
|
||||||
|
|
||||||
int f;
|
|
||||||
int r;
|
|
||||||
const char *occ;
|
|
||||||
};
|
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
|
||||||
{
|
|
||||||
int command = 0, error = 0;
|
|
||||||
struct options opt = { 0 };
|
|
||||||
/* For string -> int conversions, first non-int character */
|
|
||||||
|
|
||||||
|
|
||||||
/* Get command name */
|
|
||||||
if(argc >= 2)
|
|
||||||
{
|
{
|
||||||
if(!strcmp(argv[1], "info")) command = 'i';
|
case 'h':
|
||||||
if(!strcmp(argv[1], "disasm")) command = 'd';
|
err(help_string, argv[0]);
|
||||||
if(!strcmp(argv[1], "analyze")) command = 'a';
|
break;
|
||||||
|
case 'b':
|
||||||
if(!command && argv[1][0] != '-')
|
binary = 1;
|
||||||
{
|
break;
|
||||||
fprintf(stderr, "invalid operation: '%s'\n", argv[1]);
|
case '?':
|
||||||
fprintf(stderr, "Try '%s --help'.\n", argv[0]);
|
error = 1;
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(command) argv[1] = "";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum {
|
if(error) return 1;
|
||||||
OPT_RAM = 1,
|
char const *path = argv[optind + 1];
|
||||||
OPT_ASM = 2,
|
|
||||||
OPT_CALL = 3,
|
if(!path)
|
||||||
OPT_OCC = 4,
|
{
|
||||||
};
|
err(help_string, argv[0]);
|
||||||
const struct option longs[] = {
|
return 1;
|
||||||
{ "help", no_argument, NULL, 'h' },
|
}
|
||||||
{ "sh3", no_argument, NULL, '3' },
|
|
||||||
{ "sh4", no_argument, NULL, '4' },
|
err_context(path, NULL);
|
||||||
{ "ram", required_argument, NULL, OPT_RAM },
|
|
||||||
{ "table-asm", required_argument, NULL, OPT_ASM },
|
struct os os;
|
||||||
{ "table-call", required_argument, NULL, OPT_CALL },
|
if(os_load(path, &os)) { err_pop(); return 1; }
|
||||||
{ "full", no_argument, NULL, 'f' },
|
|
||||||
{ "syscall", no_argument, NULL, 's' },
|
if(binary)
|
||||||
{ "address", no_argument, NULL, 'a' },
|
{
|
||||||
{ "register", no_argument, NULL, 'r' },
|
err("TODO: Binary file info x_x");
|
||||||
{ "occurrences", required_argument, NULL, OPT_OCC },
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
info_os(&os);
|
||||||
|
}
|
||||||
|
|
||||||
|
os_free(&os);
|
||||||
|
err_pop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** "disasm" command
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main_disassembly(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int error=0, option=0;
|
||||||
|
|
||||||
|
/* First load some of fxos' default resources */
|
||||||
|
asm_load(FXSDK_PREFIX "/share/fxsdk/asm-sh3.txt");
|
||||||
|
asm_load(FXSDK_PREFIX "/share/fxsdk/asm-sh4.txt");
|
||||||
|
sys_load(FXSDK_PREFIX "/share/fxsdk/sys-simlo.txt");
|
||||||
|
sys_load(FXSDK_PREFIX "/share/fxsdk/sys-lephe.txt");
|
||||||
|
reg_load(FXSDK_PREFIX "/share/fxsdk/reg-sh7305.txt");
|
||||||
|
reg_load(FXSDK_PREFIX "/share/fxsdk/reg-simlo.txt");
|
||||||
|
|
||||||
|
struct disassembly opt = { 0 };
|
||||||
|
opt.mpu = MPU_GUESS;
|
||||||
|
opt.len = 0x20;
|
||||||
|
|
||||||
|
struct option const longs[] = {
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ "sh3", no_argument, NULL, '3' },
|
||||||
|
{ "sh4", no_argument, NULL, '4' },
|
||||||
|
{ "table-asm", required_argument, NULL, OPT_ASM },
|
||||||
|
{ "table-sys", required_argument, NULL, OPT_SYS },
|
||||||
|
{ "table-reg", required_argument, NULL, OPT_REG },
|
||||||
};
|
};
|
||||||
|
|
||||||
int option = 0;
|
|
||||||
while(option >= 0 && option != '?')
|
while(option >= 0 && option != '?')
|
||||||
switch((option = getopt_long(argc, argv, "hb34a::s::l:fr",longs,NULL)))
|
switch((option = getopt_long(argc, argv, "hb34a:s:l:", longs, NULL)))
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
err(help_string, argv[0]);
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
opt.binary = 1;
|
||||||
|
break;
|
||||||
|
case '3':
|
||||||
|
opt.mpu = MPU_SH7705;
|
||||||
|
break;
|
||||||
|
case '4':
|
||||||
|
opt.mpu = MPU_SH7305;
|
||||||
|
break;
|
||||||
|
case OPT_ASM:
|
||||||
|
asm_load(optarg);
|
||||||
|
break;
|
||||||
|
case OPT_SYS:
|
||||||
|
printf("TODO: Load additional syscall tables x_x\n");
|
||||||
|
break;
|
||||||
|
case OPT_REG:
|
||||||
|
printf("TODO: Load additional register tables x_x\n");
|
||||||
|
break;
|
||||||
|
case 'a':
|
||||||
|
case 's':
|
||||||
|
opt.start = integer(optarg, &error);
|
||||||
|
opt.syscall = (option == 's');
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
opt.len = integer(optarg, &error);
|
||||||
|
break;
|
||||||
|
case '?':
|
||||||
|
error = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(error) return 1;
|
||||||
|
char const *path = argv[optind + 1];
|
||||||
|
|
||||||
|
if(!path)
|
||||||
|
{
|
||||||
|
err(help_string, argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
err_context(path, NULL);
|
||||||
|
|
||||||
|
if(opt.binary)
|
||||||
|
{
|
||||||
|
printf("TODO: Disassembly binary x_x");
|
||||||
|
err_pop();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct os os;
|
||||||
|
if(os_load(path, &os)) { err_pop(); return 1; }
|
||||||
|
|
||||||
|
disassembly_os(&os, &opt);
|
||||||
|
|
||||||
|
os_free(&os);
|
||||||
|
err_pop();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** "analyze" command
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main_analyze(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int error=0, option=0;
|
||||||
|
struct analysis opt = { 0 };
|
||||||
|
|
||||||
|
struct option const longs[] = {
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ "table-asm", required_argument, NULL, OPT_ASM },
|
||||||
|
{ "table-sys", required_argument, NULL, OPT_SYS },
|
||||||
|
{ "table-reg", required_argument, NULL, OPT_REG },
|
||||||
|
{ "full", no_argument, NULL, 'f' },
|
||||||
|
{ "syscall", no_argument, NULL, 's' },
|
||||||
|
{ "address", no_argument, NULL, 'a' },
|
||||||
|
{ "register", no_argument, NULL, 'r' },
|
||||||
|
{ "occurrences", required_argument, NULL, OPT_OCC },
|
||||||
|
};
|
||||||
|
|
||||||
|
while(option >= 0 && option != '?')
|
||||||
|
switch((option = getopt_long(argc,argv,"hfsar", longs, NULL)))
|
||||||
{
|
{
|
||||||
case 'h':
|
case 'h':
|
||||||
fprintf(stderr, help_string, argv[0]);
|
fprintf(stderr, help_string, argv[0]);
|
||||||
return 0;
|
return 0;
|
||||||
case '3':
|
|
||||||
case '4':
|
|
||||||
opt.target = option;
|
|
||||||
break;
|
|
||||||
case OPT_RAM:
|
|
||||||
opt.ram = optarg;
|
|
||||||
break;
|
|
||||||
case OPT_ASM:
|
case OPT_ASM:
|
||||||
tables_add_asm(optarg);
|
asm_load(optarg);
|
||||||
break;
|
break;
|
||||||
case OPT_CALL:
|
case OPT_SYS:
|
||||||
tables_add_syscall(optarg);
|
// sys_load(optarg);
|
||||||
|
break;
|
||||||
|
case OPT_REG:
|
||||||
|
// reg_load(optarg);
|
||||||
break;
|
break;
|
||||||
case 'f':
|
case 'f':
|
||||||
opt.f = 1;
|
opt.type = ANALYSIS_FULL;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
opt.s = optarg;
|
opt.type |= ANALYSIS_SYSCALL;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
opt.a = optarg;
|
opt.type |= ANALYSIS_ADDRESS;
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
opt.l = integer(optarg, &error);
|
|
||||||
break;
|
break;
|
||||||
case 'r':
|
case 'r':
|
||||||
opt.r = 1;
|
opt.type |= ANALYSIS_REGISTER;
|
||||||
break;
|
break;
|
||||||
case OPT_OCC:
|
case OPT_OCC:
|
||||||
opt.occ = optarg;
|
opt.occurrences = integer(optarg, &error);
|
||||||
break;
|
break;
|
||||||
case '?':
|
case '?':
|
||||||
error = 1;
|
error = 1;
|
||||||
|
@ -149,35 +258,44 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(error) return 1;
|
if(error) return 1;
|
||||||
opt.input = argv[optind];
|
|
||||||
|
|
||||||
if(!opt.input)
|
/* If no analysis mode was specified, do everything */
|
||||||
{
|
if(!opt.type) opt.type = ANALYSIS_FULL;
|
||||||
fprintf(stderr, help_string, argv[0]);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Load default tables (user-specified tables will override them) */
|
|
||||||
tables_add_asm (FXSDK_PREFIX "/share/assembly-sh3.txt");
|
|
||||||
tables_add_syscall(FXSDK_PREFIX "/share/syscalls.txt");
|
|
||||||
|
|
||||||
/* Change interpretation of arguments depending on mode */
|
|
||||||
|
|
||||||
printf("Operation is '%c'\n", command);
|
|
||||||
printf(" input=%s\n", opt.input);
|
|
||||||
printf(" target='%c'\n", opt.target);
|
|
||||||
printf(" ram=%s\n", opt.ram);
|
|
||||||
printf(" a=%s\n", opt.a);
|
|
||||||
printf(" s=%s\n", opt.s);
|
|
||||||
printf(" l=%zu\n", opt.l);
|
|
||||||
printf(" f=%d\n", opt.f);
|
|
||||||
printf(" r=%d\n", opt.r);
|
|
||||||
printf(" occ=%s\n", opt.occ);
|
|
||||||
|
|
||||||
/* TODO: Execution procedure:
|
|
||||||
TODO: 1. Identify architecture
|
|
||||||
TODO: 2. Load RAM data, syscall tables, peripheral modules, etc
|
|
||||||
TODO: 3. Execute command */
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** Program entry
|
||||||
|
*/
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
if(argc < 2)
|
||||||
|
{
|
||||||
|
err(help_string, argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *cmd = argv[1];
|
||||||
|
argv[1] = "";
|
||||||
|
|
||||||
|
/* Switch on command name */
|
||||||
|
if(!strcmp(cmd, "info"))
|
||||||
|
return main_info(argc, argv);
|
||||||
|
else if(!strcmp(cmd, "disasm"))
|
||||||
|
return main_disassembly(argc, argv);
|
||||||
|
else if(!strcmp(cmd, "analyze"))
|
||||||
|
return main_analyze(argc, argv);
|
||||||
|
|
||||||
|
else if(!strcmp(cmd, "-?") || !strcmp(cmd, "-h") ||
|
||||||
|
!strcmp(cmd, "--help"))
|
||||||
|
{
|
||||||
|
err(help_string, argv[0]);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
err("invalid operation '%s'", cmd);
|
||||||
|
err("Try '%s --help'.", argv[0]);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
38
fxos/memory.c
Normal file
38
fxos/memory.c
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include <fxos.h>
|
||||||
|
|
||||||
|
/* Shared by all platforms (though ROM is 4M on most) */
|
||||||
|
|
||||||
|
static struct region ROM = { 0x80000000, 0x807fffff, "ROM", MPU_GUESS };
|
||||||
|
static struct region RAM = { 0x88000000, 0x88040000, "RAM", MPU_GUESS };
|
||||||
|
|
||||||
|
static struct region P2_ROM = { 0xa0000000, 0xa07fffff, "P2 ROM", MPU_GUESS };
|
||||||
|
static struct region P2_RAM = { 0xa8000000, 0xa8040000, "P2 RAM", MPU_GUESS };
|
||||||
|
|
||||||
|
/* SH7305 only */
|
||||||
|
|
||||||
|
static struct region RS = { 0xfd800000, 0xfd8007ff, "RS", MPU_SH7305 };
|
||||||
|
static struct region IL = { 0xe5200000, 0xe5203fff, "IL", MPU_SH7305 };
|
||||||
|
static struct region XRAM = { 0xe5007000, 0xe5008fff, "XRAM", MPU_SH7305 };
|
||||||
|
static struct region YRAM = { 0xe5017000, 0xe5018fff, "YRAM", MPU_SH7305 };
|
||||||
|
|
||||||
|
/* A summary */
|
||||||
|
static struct region *regions[] = {
|
||||||
|
&ROM, &RAM, &P2_ROM, &P2_RAM, &IL, &RS, NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* memory_in(): Check if an address if inside a given region */
|
||||||
|
static int memory_in(uint32_t address, struct region const *reg)
|
||||||
|
{
|
||||||
|
return reg && address >= reg->start && address <= reg->end;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* memory_region(): Find the region where an address is located */
|
||||||
|
struct region const *memory_region(uint32_t address)
|
||||||
|
{
|
||||||
|
for(int i = 0; regions[i]; i++)
|
||||||
|
{
|
||||||
|
if(memory_in(address, regions[i])) return regions[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
91
fxos/os.c
Normal file
91
fxos/os.c
Normal file
|
@ -0,0 +1,91 @@
|
||||||
|
#include <endian.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
/* os_load(): Load an OS file and find out basic properties */
|
||||||
|
int os_load(char const *path, struct os *os)
|
||||||
|
{
|
||||||
|
if(!path || !os) return 1;
|
||||||
|
|
||||||
|
os->data = map(path, &os->fd, &os->len);
|
||||||
|
if(!os->data) return 1;
|
||||||
|
if(os->len < 0x10080)
|
||||||
|
{
|
||||||
|
err("too small for the OS format I know (min. 0x10080 bytes)",
|
||||||
|
os->len);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the OS version */
|
||||||
|
|
||||||
|
memcpy(os->version, os->data + 0x10020, 14);
|
||||||
|
os->version[14] = 0;
|
||||||
|
|
||||||
|
/* Guess the MPU type (or assume SH7305). Until version 03.00, the last
|
||||||
|
digit of the version number indicated the presence of an SH7305 */
|
||||||
|
|
||||||
|
os->mpu = MPU_SH7305;
|
||||||
|
if(!strncmp(os->version, "02.", 3) && os->version[13] == '0')
|
||||||
|
os->mpu = MPU_SH7705;
|
||||||
|
|
||||||
|
/* Find the syscall table address */
|
||||||
|
|
||||||
|
memcpy(&os->syscall_table, os->data + 0x1007c, 4);
|
||||||
|
os->syscall_table = be32toh(os->syscall_table);
|
||||||
|
|
||||||
|
/* Count the number of valid syscall entries */
|
||||||
|
|
||||||
|
os->syscalls = 0;
|
||||||
|
while(memory_region(os_syscall(os, os->syscalls))) os->syscalls++;
|
||||||
|
|
||||||
|
/* Find the footer address (last occurrence of "CASIOABSLangdata") */
|
||||||
|
|
||||||
|
char const *signature = "CASIOABSLangdata";
|
||||||
|
void *occ = NULL, *next = memmem(os->data, os->len, signature, 16);
|
||||||
|
void *end = os->data + os->len;
|
||||||
|
|
||||||
|
while(next)
|
||||||
|
{
|
||||||
|
occ = next;
|
||||||
|
next = memmem(next + 1, end - (next + 1), signature, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
os->footer = (occ) ? (occ - os->data) : (uint32_t)-1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* os_syscall(): Get the address of a syscall entry */
|
||||||
|
uint32_t os_syscall(struct os const *os, int syscall)
|
||||||
|
{
|
||||||
|
uint32_t table_entry = (os->syscall_table & 0x1fffffff) + 4 * syscall;
|
||||||
|
if(table_entry + 4 > os->len) return (uint32_t)-1;
|
||||||
|
|
||||||
|
uint32_t address;
|
||||||
|
memcpy(&address, os->data + table_entry, 4);
|
||||||
|
address = be32toh(address);
|
||||||
|
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* os_syscall_find(): Find a syscall which points to an address */
|
||||||
|
int os_syscall_find(struct os const *os, uint32_t entry)
|
||||||
|
{
|
||||||
|
/* Try to make this slightly quicker */
|
||||||
|
uint32_t table_entry = (os->syscall_table & 0x1fffffff);
|
||||||
|
entry = htobe32(entry);
|
||||||
|
|
||||||
|
uint32_t *entries = os->data + table_entry;
|
||||||
|
for(int i = 0; i < os->syscalls; i++) if(entries[i] == entry) return i;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* os_free(): Free an OS file opened with os_load() */
|
||||||
|
void os_free(struct os const *os)
|
||||||
|
{
|
||||||
|
if(os && os->data) unmap(os->data, os->fd, os->len);
|
||||||
|
}
|
114
fxos/reg-sh7305.txt
Normal file
114
fxos/reg-sh7305.txt
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
# T6K11 interface
|
||||||
|
0xb4000000 T6K11.REG
|
||||||
|
0xb4010000 T6K11.DATA
|
||||||
|
|
||||||
|
# Exception handling
|
||||||
|
0xff000020 TRA
|
||||||
|
0xff000024 EXPEVT
|
||||||
|
0xff000028 INTEVT
|
||||||
|
0xff2f0004 EXPMASK
|
||||||
|
|
||||||
|
# Memory Management Unit
|
||||||
|
0xff000000 MMU.PTEH
|
||||||
|
0xff000004 MMU.PTEL
|
||||||
|
0xff00000c MMU.TEA
|
||||||
|
0xff000010 MMU.MMUCR
|
||||||
|
0xff000034 MMU.PTEA
|
||||||
|
0xff000070 MMU.PASCR
|
||||||
|
0xff000078 MMU.IRMCR
|
||||||
|
|
||||||
|
# Interrupt controller
|
||||||
|
0xa4140000 INTC.ICR0
|
||||||
|
0xa414001c INTC.ICR1
|
||||||
|
0xa4140010 INTC.INTPRI00
|
||||||
|
0xa4140024 INTC.INTREQ00
|
||||||
|
0xa4140044 INTC.INTMSK00
|
||||||
|
0xa4140064 INTC.INTMSKCLR00
|
||||||
|
0xa41400c0 INTC.NMIFCR
|
||||||
|
0xa4700000 INTC.USERIMSK
|
||||||
|
0xa4080000 INTC.IPRA
|
||||||
|
0xa4080004 INTC.IPRB
|
||||||
|
0xa4080008 INTC.IPRC
|
||||||
|
0xa408000c INTC.IPRD
|
||||||
|
0xa4080010 INTC.IPRE
|
||||||
|
0xa4080014 INTC.IPRF
|
||||||
|
0xa4080018 INTC.IPRG
|
||||||
|
0xa408001c INTC.IPRH
|
||||||
|
0xa4080020 INTC.IPRI
|
||||||
|
0xa4080024 INTC.IPRJ
|
||||||
|
0xa4080028 INTC.IPRK
|
||||||
|
0xa408002c INTC.IPRL
|
||||||
|
0xa4080080 INTC.IMR0
|
||||||
|
0xa4080084 INTC.IMR1
|
||||||
|
0xa4080088 INTC.IMR2
|
||||||
|
0xa408008c INTC.IMR3
|
||||||
|
0xa4080090 INTC.IMR4
|
||||||
|
0xa4080094 INTC.IMR5
|
||||||
|
0xa4080098 INTC.IMR6
|
||||||
|
0xa408009c INTC.IMR7
|
||||||
|
0xa40800a0 INTC.IMR8
|
||||||
|
0xa40800a4 INTC.IMR9
|
||||||
|
0xa40800a8 INTC.IMR10
|
||||||
|
0xa40800ac INTC.IMR11
|
||||||
|
0xa40800b0 INTC.IMR12
|
||||||
|
0xa40800c0 INTC.IMCR0
|
||||||
|
0xa40800c4 INTC.IMCR1
|
||||||
|
0xa40800c8 INTC.IMCR2
|
||||||
|
0xa40800cc INTC.IMCR3
|
||||||
|
0xa40800d0 INTC.IMCR4
|
||||||
|
0xa40800d4 INTC.IMCR5
|
||||||
|
0xa40800d8 INTC.IMCR6
|
||||||
|
0xa40800dc INTC.IMCR7
|
||||||
|
0xa40800e0 INTC.IMCR8
|
||||||
|
0xa40800e4 INTC.IMCR9
|
||||||
|
0xa40800e8 INTC.IMCR10
|
||||||
|
0xa40800ec INTC.IMCR11
|
||||||
|
0xa40800f0 INTC.IMCR12
|
||||||
|
|
||||||
|
# Direct Memory Access Controller: TODO
|
||||||
|
|
||||||
|
# Reset and power-down modes
|
||||||
|
0xa4150020 POWER.STBCR
|
||||||
|
0xa4150030 POWER.MSTPCR0
|
||||||
|
0xa4150034 POWER.MSTPCR1
|
||||||
|
0xa4150038 POWER.MSTPCR2
|
||||||
|
0xa4150040 POWER.BAR
|
||||||
|
|
||||||
|
# Real-Time Clock
|
||||||
|
0xa465fec0 RTC.R64CNT
|
||||||
|
0xa465fec2 RTC.RSECCNT
|
||||||
|
0xa465fec4 RTC.RMINCNT
|
||||||
|
0xa465fec6 RTC.RHRCNT
|
||||||
|
0xa465fec8 RTC.RWKCNT
|
||||||
|
0xa465feca RTC.RDAYCNT
|
||||||
|
0xa465fecc RTC.RMONCNT
|
||||||
|
0xa465fece RTC.RYRCNT
|
||||||
|
0xa465fed0 RTC.RSECAR
|
||||||
|
0xa465fed2 RTC.RMINAR
|
||||||
|
0xa465fed4 RTC.RHRAR
|
||||||
|
0xa465fed6 RTC.RWKAR
|
||||||
|
0xa465fed8 RTC.RDAYAR
|
||||||
|
0xa465feda RTC.RMONAR
|
||||||
|
0xa465fedc RTC.RCR1
|
||||||
|
0xa465fede RTC.RCR2
|
||||||
|
0xa465fee0 RTC.RYRAR
|
||||||
|
0xa465fee4 RTC.RCR3
|
||||||
|
|
||||||
|
# User Break Controller
|
||||||
|
0xff200000 UBC.CBR0
|
||||||
|
0xff200004 UBC.CRR0
|
||||||
|
0xff200008 UBC.CAR0
|
||||||
|
0xff20000c UBC.CAMR0
|
||||||
|
0xff200020 UBC.CBR1
|
||||||
|
0xff200024 UBC.CRR1
|
||||||
|
0xff200028 UBC.CAR1
|
||||||
|
0xff20002c UBC.CAMR1
|
||||||
|
0xff200030 UBC.CDR1
|
||||||
|
0xff200034 UBC.CDMR1
|
||||||
|
0xff200038 UBC.CETR1
|
||||||
|
0xff200600 UBC.CCMFR
|
||||||
|
0xff200620 UBC.CBCR
|
||||||
|
|
||||||
|
# RCLK Watchdog Timer
|
||||||
|
0xa4520000 RWDT.RWTCNT
|
||||||
|
0xA4520004 RWDT.RWTCSR
|
141
fxos/reg-simlo.txt
Normal file
141
fxos/reg-simlo.txt
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
# Processor version
|
||||||
|
0xff2f0000 CPUOPM
|
||||||
|
0xff000030 PVR
|
||||||
|
0xff000040 CVR
|
||||||
|
0xff000044 PRR
|
||||||
|
|
||||||
|
# Key Scan Interface
|
||||||
|
0xa44b0000 KEYSC.DATA
|
||||||
|
0xa44b000c KEYSC.UCNTREG
|
||||||
|
0xa44b000e KEYSC.AUTOFIXREG
|
||||||
|
0xa44b0010 KEYSC.UMODEREG
|
||||||
|
0xa44b0012 KEYSC.USTATEREG
|
||||||
|
0xa44b0014 KEYSC.UINTREG
|
||||||
|
0xa44b0016 KEYSC.UWSETREG
|
||||||
|
0xa44b0018 KEYSC.UINTERVALREG
|
||||||
|
0xa44b001a KEYSC.OUTPINSET
|
||||||
|
0xa44b001c KEYSC.INPINSET
|
||||||
|
|
||||||
|
# Timer Unit
|
||||||
|
0xa4490004 TMU.TSTR
|
||||||
|
0xa4490008 TMU0.TCOR
|
||||||
|
0xa449000c TMU0.TCNT
|
||||||
|
0xa4490010 TMU0.TCR
|
||||||
|
0xa4490014 TMU1.TCOR
|
||||||
|
0xa4490018 TMU1.TCNT
|
||||||
|
0xa449001c TMU1.TCR
|
||||||
|
0xa4490020 TMU2.TCOR
|
||||||
|
0xa4490024 TMU2.TCNT
|
||||||
|
0xa4490028 TMU2.TCR
|
||||||
|
|
||||||
|
# Serial Communication Interface
|
||||||
|
0xa4410000 SCIF.SCSMR
|
||||||
|
0xa4410004 SCIF.SCBRR
|
||||||
|
0xa4410008 SCIF.SCSCR
|
||||||
|
0xa441000c SCIF.SCFTDR
|
||||||
|
0xa4410010 SCIF.SCFSR
|
||||||
|
0xa4410014 SCIF.SCFRDR
|
||||||
|
0xa4410018 SCIF.SCFCR
|
||||||
|
0xa441001c SCIF.SCFDR
|
||||||
|
0xa4410024 SCIF.SCLSR
|
||||||
|
|
||||||
|
# Pin Function Controller
|
||||||
|
0xa4050100 PFC.PACR
|
||||||
|
0xa4050102 PFC.PBCR
|
||||||
|
0xa4050104 PFC.PCCR
|
||||||
|
0xa4050106 PFC.PDCR
|
||||||
|
0xa4050108 PFC.PECR
|
||||||
|
0xa405010a PFC.PFCR
|
||||||
|
0xa405010c PFC.PGCR
|
||||||
|
0xa405010e PFC.PHCR
|
||||||
|
0xa4050110 PFC.PJCR
|
||||||
|
0xa4050112 PFC.PKCR
|
||||||
|
0xa4050114 PFC.PLCR
|
||||||
|
0xa4050116 PFC.PMCR
|
||||||
|
0xa4050118 PFC.PNCR
|
||||||
|
0xa405014c PFC.PPCR
|
||||||
|
0xa405011a PFC.PQCR
|
||||||
|
0xa405011c PFC.PRCR
|
||||||
|
0xa405011e PFC.PSCR
|
||||||
|
0xa4050140 PFC.PTCR
|
||||||
|
0xa4050142 PFC.PUCR
|
||||||
|
0xa4050144 PFC.PVCR
|
||||||
|
0xa405014e PFC.PSELA
|
||||||
|
0xa4050150 PFC.PSELB
|
||||||
|
0xa4050152 PFC.PSELC
|
||||||
|
0xa4050154 PFC.PSELD
|
||||||
|
0xa4050156 PFC.PSELE
|
||||||
|
0xa405015e PFC.PSELF
|
||||||
|
0xa40501c8 PFC.PSELG
|
||||||
|
0xa40501d6 PFC.PSELH
|
||||||
|
0xa4050158 PFC.HIZCRA
|
||||||
|
0xa405015a PFC.HIZCRB
|
||||||
|
0xa405015c PFC.HIZCRC
|
||||||
|
0xa4050180 PFC.MSELCRA
|
||||||
|
0xa4050182 PFC.MSELCRB
|
||||||
|
0xa4050184 PFC.DRVCRD
|
||||||
|
0xa4050186 PFC.DRVCRA
|
||||||
|
0xa4050188 PFC.DRVCRB
|
||||||
|
0xa405018a PFC.DRVCRC
|
||||||
|
0xa40501c3 PFC.PULCRBSC
|
||||||
|
0xa40501c5 PFC.PULCRTRST
|
||||||
|
0xa4050190 PFC.PULCRA
|
||||||
|
0xa4050191 PFC.PULCRB
|
||||||
|
0xa4050192 PFC.PULCRC
|
||||||
|
0xa4050193 PFC.PULCRD
|
||||||
|
0xa4050194 PFC.PULCRE
|
||||||
|
0xa4050195 PFC.PULCRF
|
||||||
|
0xa4050196 PFC.PULCRG
|
||||||
|
0xa4050197 PFC.PULCRH
|
||||||
|
0xa4050198 PFC.PULCRJ
|
||||||
|
0xa4050199 PFC.PULCRK
|
||||||
|
0xa405019a PFC.PULCRL
|
||||||
|
0xa405019b PFC.PULCRM
|
||||||
|
0xa405019c PFC.PULCRN
|
||||||
|
0xa40501c6 PFC.PULCRP
|
||||||
|
0xa405019d PFC.PULCRQ
|
||||||
|
0xa405019e PFC.PULCRR
|
||||||
|
0xa405019f PFC.PULCRS
|
||||||
|
0xa40501c0 PFC.PULCRT
|
||||||
|
0xa40501c1 PFC.PULCRU
|
||||||
|
0xa40501c2 PFC.PULCRV
|
||||||
|
|
||||||
|
# Bus State Controller
|
||||||
|
0xfec10000 BSC.CMNCR
|
||||||
|
0xfec10004 BSC.CS0BCR
|
||||||
|
0xfec10008 BSC.CS2BCR
|
||||||
|
0xfec1000c BSC.CS3BCR
|
||||||
|
0xfec10010 BSC.CS4BCR
|
||||||
|
0xfec10014 BSC.CS5ABCR
|
||||||
|
0xfec10018 BSC.CS5BBCR
|
||||||
|
0xfec1001c BSC.CS6ABCR
|
||||||
|
0xfec10020 BSC.CS6BBCR
|
||||||
|
0xfec10024 BSC.CS0WCR
|
||||||
|
0xfec10028 BSC.CS2WCR
|
||||||
|
0xfec1002c BSC.CS3WCR
|
||||||
|
0xfec10030 BSC.CS4WCR
|
||||||
|
0xfec10034 BSC.CS5AWCR
|
||||||
|
0xfec10038 BSC.CS5BWCR
|
||||||
|
0xfec1003c BSC.CS6AWCR
|
||||||
|
0xfec10040 BSC.CS6BWCR
|
||||||
|
0xfec10044 BSC.SDCR
|
||||||
|
0xfec10048 BSC.RTCSR
|
||||||
|
0xfec1004c BSC.RTCNT
|
||||||
|
0xfec10050 BSC.RTCOR
|
||||||
|
0xfec14000 BSC.SDMR2
|
||||||
|
0xfec15000 BSC.SDMR3
|
||||||
|
|
||||||
|
# Clock Pulse Generator
|
||||||
|
0xa4150000 CPG.FRQCR
|
||||||
|
0xa4150008 CPG.FCLKCR
|
||||||
|
0xa4150010 CPG.DDCLKCR
|
||||||
|
0xa4150014 CPG.USBCLKCR
|
||||||
|
0xa4150024 CPG.PLLCR
|
||||||
|
0xa4150028 CPG.PLL2CR
|
||||||
|
0xa415003c CPG.SPUCLKCR
|
||||||
|
0xa4150044 CPG.SSCGCR
|
||||||
|
0xa4150050 CPG.FLLFRQ
|
||||||
|
0xa4150060 CPG.LSTATS
|
||||||
|
|
||||||
|
# More addresses are around on Casiopeia.
|
||||||
|
# See http://www.casiopeia.net/forum/viewtopic.php?f=11&t=1756#p14588.
|
58
fxos/reg.c
Normal file
58
fxos/reg.c
Normal file
|
@ -0,0 +1,58 @@
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <util.h>
|
||||||
|
|
||||||
|
/* reg_free_item(): Free a peripheral register item */
|
||||||
|
static void reg_free_item(void *item)
|
||||||
|
{
|
||||||
|
struct reg_address *reg = item;
|
||||||
|
free(reg->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reg_load(): Load a peripheral register table */
|
||||||
|
void reg_load(char const *file)
|
||||||
|
{
|
||||||
|
err_context("register", file, NULL);
|
||||||
|
if(!table_available())
|
||||||
|
{
|
||||||
|
err("too many tables, skipping");
|
||||||
|
err_pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map the file to memory */
|
||||||
|
int fd;
|
||||||
|
size_t size;
|
||||||
|
void *data = map(file, &fd, &size);
|
||||||
|
if(!data) { err_pop(); return; }
|
||||||
|
|
||||||
|
/* If the file is named "reg-x.txt", use "x" as the table name */
|
||||||
|
char *name = match_table_name(file, "reg", ".txt");
|
||||||
|
|
||||||
|
/* Parse the contents */
|
||||||
|
int count;
|
||||||
|
struct reg_address *regs = lex_reg(data, size, &count);
|
||||||
|
|
||||||
|
table_create("reg", name, reg_free_item, count, sizeof *regs, regs);
|
||||||
|
|
||||||
|
unmap(data, fd, size);
|
||||||
|
err_pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Global storage for reg_match() */
|
||||||
|
static uint32_t reg_match_address;
|
||||||
|
|
||||||
|
/* reg_match(): Search routine for reg_find() */
|
||||||
|
static int reg_match(void *item)
|
||||||
|
{
|
||||||
|
struct reg_address *reg = item;
|
||||||
|
return reg->address == reg_match_address;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* reg_find(): Find information on a given peripheral register address */
|
||||||
|
struct reg_address const *reg_find(uint32_t address)
|
||||||
|
{
|
||||||
|
reg_match_address = address;
|
||||||
|
return table_find("reg", reg_match, NULL, 0);
|
||||||
|
}
|
7
fxos/sys-lephe.txt
Normal file
7
fxos/sys-lephe.txt
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
0x000 sys_init
|
||||||
|
0x004 tlb_init
|
||||||
|
void tlb_init(void)
|
||||||
|
0x025 t6k11_read_datareg
|
||||||
|
uint8_t t6k11_read_datareg(void)
|
||||||
|
0x3fc tlb_map
|
||||||
|
void tlb_map(int shifted_vpn, int way, uint32_t data_field)
|
656
fxos/sys-simlo.txt
Normal file
656
fxos/sys-simlo.txt
Normal file
|
@ -0,0 +1,656 @@
|
||||||
|
0x001 vbr_tlb_error
|
||||||
|
0x002 vbr_cpu_address
|
||||||
|
0x003 vbr_tlb_exception
|
||||||
|
0x005 App_RegisterAddins
|
||||||
|
int App_RegisterAddins(void)
|
||||||
|
0x009 App_FindFreeAddinSlot
|
||||||
|
int FindFreeAddinSlot(void)
|
||||||
|
0x00a App_GetAddinHeaderAddr
|
||||||
|
int GetAddindHeaderAddr(int addin_no, int offset, void *result)
|
||||||
|
0x00e App_GetAddindEstrip
|
||||||
|
int App_GetAddindEstrip(int addin_no, int estrip_no, void *result)
|
||||||
|
0x013 GlibAddinAplExecutionCheck
|
||||||
|
0x014 GlibGetAddinLibInfo
|
||||||
|
0x015 GlibGetOSVersionInfo
|
||||||
|
int GlibGetOSVersionInfo(char *a, char *b, short *c, short *d)
|
||||||
|
0x018 MMU_FlushCache
|
||||||
|
0x01b DD_Clear
|
||||||
|
0x01c Bdisp_WriteGraph_VRAM
|
||||||
|
0x01d Bdisp_WriteGraph_DD
|
||||||
|
0x01e Bdisp_WriteGraph_DDVRAM
|
||||||
|
0x022 Bdisp_ReadArea_VRAM
|
||||||
|
0x023 Bdisp_ReadArea_DD
|
||||||
|
0x024 Bdisp_GetDisp_DD
|
||||||
|
0x025 DD_Read
|
||||||
|
0x026 DD_ReadFromPage
|
||||||
|
0x027 DD_WriteToPage
|
||||||
|
0x028 Bdisp_PutDisp_DD
|
||||||
|
0x02a Bdisp_DrawShapeToVRAM
|
||||||
|
0x02f Bdisp_DrawShapeToVRAM
|
||||||
|
0x030 Bdisp_DrawLineVRAM
|
||||||
|
0x031 Bdisp_ClearLineVRAM
|
||||||
|
0x032 Bdisp_DrawShapeToDD
|
||||||
|
0x033 Bdisp_DrawShapeToVRAM_DD
|
||||||
|
0x034 Bdisp_DrawShapeToDD
|
||||||
|
0x035 Bdisp_DrawShapeToVRAM_DD
|
||||||
|
0x039 RTC_Reset
|
||||||
|
void RTC_Reset(unsigned int mode)
|
||||||
|
0x03a RTC_GetTime
|
||||||
|
void RTC_GetTime(uint *hour, uint *minute, uint *second, uint *millisecond)
|
||||||
|
0x03b RTC_GetTicks
|
||||||
|
int RTC_GetTicks(void)
|
||||||
|
0x03c RTC_Elapsed_ms
|
||||||
|
int RTC_Elapsed_ms(int start_value, int duration_ms)
|
||||||
|
0x05c Num_UIntToBCD
|
||||||
|
0x05d Num_BCDToUInt
|
||||||
|
|
||||||
|
0x118 Timer_Install
|
||||||
|
int Timer_Install(int timerID, void *handler, int elapse), also known as Bcre_cychdr
|
||||||
|
0x119 Timer_Deinstall
|
||||||
|
int Timer_Deinstall(int timerID), also known as Bdel_cychdr
|
||||||
|
0x11a Timer_Start
|
||||||
|
int Timer_Start(int timerID)
|
||||||
|
0x11b Timer_Stop
|
||||||
|
int Timer_Stop(int timerID)
|
||||||
|
0x11f Bdisp_PutDispArea_DD
|
||||||
|
0x12d DD_Poweroff
|
||||||
|
0x130 Wait_ms
|
||||||
|
0x132 DD_SetContrast
|
||||||
|
0x133 DD_SetFRS
|
||||||
|
0x134 DD_SetBias
|
||||||
|
0x135 GetVRAMAddress
|
||||||
|
0x136 GetCharacterGlyph
|
||||||
|
0x137 GetCharacterMiniGlyph
|
||||||
|
0x138 Cursor_SetPosition
|
||||||
|
int Cursor_SetPosition(char column, char row)
|
||||||
|
0x139 Cursor_SetFlashStyle
|
||||||
|
int Cursor_SetFlashStyle(short flashStyle)
|
||||||
|
0x13a Cursor_SetFlashMode
|
||||||
|
void Cursor_SetFlashMode(long flashMode)
|
||||||
|
0x13b Cursor_GetSettings
|
||||||
|
uint Cursor_GetSettings(uint *settingsArray)
|
||||||
|
0x13c Print_OS
|
||||||
|
void Print_OS(unsigned char *msg, int type)
|
||||||
|
0x142 Bdisp_AllClr_DD
|
||||||
|
0x143 Bdisp_AllClr_VRAM
|
||||||
|
0x144 Bdisp_AllClr_DDVRAM
|
||||||
|
0x145 Bdisp_GetDisp_VRAM
|
||||||
|
0x146 Bdisp_SetPoint_VRAM
|
||||||
|
0x147 Bdisp_SetPoint_DD
|
||||||
|
0x148 Bdisp_SetPoint_DDVRAM
|
||||||
|
0x149 Bdisp_GetPoint_VRAM
|
||||||
|
0x14a Bdisp_AreaClr_DD
|
||||||
|
0x14b Bdisp_AreaClr_VRAM
|
||||||
|
0x14c Bdisp_AreaClr_DDVRAM
|
||||||
|
0x14d Bdisp_AreaReverseVRAM
|
||||||
|
0x150 PrintXY
|
||||||
|
void PrintXY(int x, int y, unsigned char *msg, int type)
|
||||||
|
0x153 Disp_Save
|
||||||
|
0x154 Disp_Restore
|
||||||
|
0x155 Disp_GetPtr
|
||||||
|
0x156 PopUpWin
|
||||||
|
0x158 Disp_Manage
|
||||||
|
0x159 System_UpdateOS
|
||||||
|
0x15d PrintCR
|
||||||
|
0x15f atoi
|
||||||
|
0x160 LongToAsc
|
||||||
|
int LongToAsc(int value, unsigned char *dest, int digits)
|
||||||
|
0x161 LongToAscHex
|
||||||
|
int LongToAscHex(int value, unsigned char *dest, int digits)
|
||||||
|
0x162 pc_toupper
|
||||||
|
void pc_toupper(char *str)
|
||||||
|
0x163 pc_tolower
|
||||||
|
void pc_tolower(char *str)
|
||||||
|
0x172 strcmp
|
||||||
|
0x173 strcmp
|
||||||
|
0x175 some_datatable
|
||||||
|
0x176 DiagnosticMode
|
||||||
|
0x18a InvertMem
|
||||||
|
void InvertMem(void *memoryrange, int count)
|
||||||
|
0x19f SMEM_Optimization
|
||||||
|
void SMEM_Optimization(void)
|
||||||
|
0x1a9 GUI_ProgressBar
|
||||||
|
0x1b7 Get8x8BitmapPointer_1
|
||||||
|
0x1b8 Get8x8BitmapPointer_2
|
||||||
|
0x1b9 Get8x8BitmapPointer_3
|
||||||
|
0x1ba Get8x8BitmapPointer_4
|
||||||
|
0x1bb Get8x8BitmapPointer_5
|
||||||
|
0x1bc Get8x8BitmapPointer_6
|
||||||
|
0x1bd Get8x8BitmapPointer_7
|
||||||
|
|
||||||
|
0x20e StorageMemory_GetFilePos
|
||||||
|
int StorageMemory_GetFilePos(int handle, int *pos)
|
||||||
|
0x236 RebootOS
|
||||||
|
0x23d RTC_TriggerAlarm
|
||||||
|
void RTC_TriggerAlarm(void)
|
||||||
|
0x23e RTC_SetDateTime
|
||||||
|
void RTC_SetDateTime(unsigned char *[7] time)
|
||||||
|
0x241 Keyboard_ClrBuffer
|
||||||
|
0x242 Bkey_Set_RepeatTime
|
||||||
|
0x243 Bkey_Get_RepeatTime
|
||||||
|
0x244 Bkey_Set_RepeatTime_Default
|
||||||
|
0x245 Keyboard_EnableAutoRepeat
|
||||||
|
0x246 Keyboard_DisableAutoRepeat
|
||||||
|
0x247 Keyboard_GetKeyWait
|
||||||
|
0x248 Keyboard_PutKeycode
|
||||||
|
0x249 Keyboard_GetKeyDownTime
|
||||||
|
short Keyboard_GetKeyDownTime(void)
|
||||||
|
0x24a Keyboard_IsAnyKeyDown
|
||||||
|
int Keyboard_IsAnyKeyDown(short *matrixcode)
|
||||||
|
0x24b Keyboard_IsSpecialKeyDown
|
||||||
|
int Keyboard_IsSpecialKeyDown(short *matrixcode)
|
||||||
|
0x24c Keyboard_IsSpecialKeyDown
|
||||||
|
int Keyboard_IsSpecialKeyDown(short *matrixcode)
|
||||||
|
0x24d Keyboard_KeyDown
|
||||||
|
int Keyboard_KeyDown(void)
|
||||||
|
0x24e Keyboard_SecondaryInterruptHandler
|
||||||
|
0x24f Keyboard_PutKeymatrixCode
|
||||||
|
int Keyboard_PutKeymatrixCode(short *matrixcode)
|
||||||
|
0x251 Keyboard_TimerHandler
|
||||||
|
0x25e Keyboard_PrimaryInterruptHandler
|
||||||
|
0x268 GetFKeyIconPointer
|
||||||
|
void GetFKeyIconPointer(int fkeyno, unsigned char *bitmap)
|
||||||
|
0x284 BCD_GetNaN
|
||||||
|
int BCD_GetNaN(unsigned char *value, unsigned char *result)
|
||||||
|
0x285 Serial_Open_57600
|
||||||
|
int Serial_Open_57600(void)
|
||||||
|
0x286 BCD_AnsToSerial
|
||||||
|
0x28d Comm_Open
|
||||||
|
int Comm_Open(unsigned short parameters)
|
||||||
|
0x28e Comm_Close
|
||||||
|
0x28f Comm_WaitForAnyBuffer
|
||||||
|
int Comm_WaitForAnyBuffer(int timeout_ms, int P2, int *P3)
|
||||||
|
0x290 Comm_ReadOneByte
|
||||||
|
int Comm_ReadOneByte(unsigned char *result)
|
||||||
|
0x291 Comm_TransmitOneByte
|
||||||
|
0x292 Comm_WaitForAndReadNBytes
|
||||||
|
int Comm_WaitForAndReadNBytes(char *buffer, int bytes)
|
||||||
|
0x293 Comm_TransmitNBytes
|
||||||
|
0x294 Comm_ClearReceiveBuffer
|
||||||
|
0x295 Comm_ClearTransmitBuffer
|
||||||
|
0x296 Comm_IsValidPacketAvailable
|
||||||
|
int Comm_IsValidPacketAvailable(unsigned char *result)
|
||||||
|
0x298 Comm_IsOpen
|
||||||
|
0x299 Comm_GetCurrentSelector
|
||||||
|
int Comm_GetCurrentSelector(void)
|
||||||
|
0x2a1 HexToByte
|
||||||
|
int HexToByte(short *hex, char *result)
|
||||||
|
0x2a2 HexToWord
|
||||||
|
int HexToWord(int *hex, short *result)
|
||||||
|
0x2a3 ByteToHex
|
||||||
|
0x2a4 WordToHex
|
||||||
|
0x2a5 Comm_Padding_5C
|
||||||
|
0x2a6 Comm_ReversePadding_5C
|
||||||
|
0x2a7 AscHexToNibble
|
||||||
|
void AscHexToNibble(char hex, char *result)
|
||||||
|
0x2a8 NibbleToAscHex
|
||||||
|
0x2a9 strlen
|
||||||
|
0x2aa slow_memcpy
|
||||||
|
0x2ab Serial_Open2
|
||||||
|
int Serial_Open2(unsigned short parameters)
|
||||||
|
0x2af Comm_Spy0thByte
|
||||||
|
int Comm_Spy0thByte(unsigned char *result)
|
||||||
|
0x2db Comm_ProcessInPacket
|
||||||
|
int Comm_ProcessInPacket(TReceivePacketDesc *rpd)
|
||||||
|
0x2e1 Comm_PrepareAckPacket
|
||||||
|
int Comm_PrepareAckPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
|
||||||
|
0x2e2 Comm_PrepareErrorPacket
|
||||||
|
void Comm_PrepareErrorPacket(TReceivePacketDesc *rpd, unsigned char subtype)
|
||||||
|
0x2e3 Comm_PrepareTerminatePacket
|
||||||
|
void Comm_PrepareTerminatePacket(TReceivePacketDesc *rpd, unsigned char subtype)
|
||||||
|
0x2e4 Comm_PrepareRoleswapPacket
|
||||||
|
void Comm_PrepareRoleswapPacket(TReceivePacketDesc *rpd, unsigned char subtype)
|
||||||
|
0x2e5 Comm_PrepareCheckPacket
|
||||||
|
void Comm_PrepareCheckPacket(TReceivePacketDesc *rpd, unsigned char subtype)
|
||||||
|
0x2e6 Comm_PrepareCommandPacket
|
||||||
|
int Comm_PrepareCommandPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
|
||||||
|
0x2e7 Comm_PrepareDataPacket
|
||||||
|
int Comm_PrepareDataPacket(TReceivePacketDesc *rpd, unsigned char subtype, void *datapointer, unsigned short datasize)
|
||||||
|
0x2ee System_GetOSVersion
|
||||||
|
void System_GetOSVersion(unsigned char *version)
|
||||||
|
|
||||||
|
0x35e memset_range
|
||||||
|
0x35f memset
|
||||||
|
0x363 MCS_CreateDirectory
|
||||||
|
int MCS_CreateDirectory(unsigned char *dir, char *dirno)
|
||||||
|
0x364 MCS_WriteItem
|
||||||
|
int MCS_WriteItem(unsigned char *dir, unsigned char *item, short itemType, int data_length, int buffer)
|
||||||
|
0x366 MCS_DeleteDirectory
|
||||||
|
int MCS_DeleteDirectory(unsigned char *dir)
|
||||||
|
0x367 MCS_DeleteItem
|
||||||
|
int MCS_DeleteItem(unsigned char *dir, unsigned char *item)
|
||||||
|
0x368 MCS_GetState
|
||||||
|
int MCS_GetState(int *maxspace, int *currentload, int *remainingspace)
|
||||||
|
0x369 MCS_GetSystemDirectoryInfo
|
||||||
|
int MCS_GetSystemDirectoryInfo(unsigned char *dir, unsigned int *pdir, char *dirno)
|
||||||
|
0x370 MCS_RenameItem
|
||||||
|
int MCS_RenameItem(unsigned char *srcdir, unsigned char *srcitem, unsigned char *tgtdir, int tgtitem)
|
||||||
|
0x371 MCS_OverwriteData
|
||||||
|
int MCS_OverwriteData(unsigned char *dir, unsigned char *item, int write_offset, int bytes_to_write, void *buffer)
|
||||||
|
0x372 MCS_GetItemData
|
||||||
|
int MCS_GetItemData(unsigned char *dir, unsigned char *item, int offset, int bytes_to_read, void *buffer)
|
||||||
|
0x373 MCS_RenameDirectory
|
||||||
|
int MCS_RenameDirectory(unsigned char *oldname, unsigned char *newname)
|
||||||
|
0x374 BMCSRenameVariable
|
||||||
|
0x375 MCS_SearchDirectory
|
||||||
|
int MCS_SearchDirectory(unsigned char *dir, TMainMemoryDirectoryEntry *dir, char *dirno)
|
||||||
|
0x376 MCS_SearchDirectoryItem
|
||||||
|
int MCS_SearchDirectoryItem(unsigned char *dir, unsigned char *item, char *flags_0, TDirectoryItem *item, int *data, int *data_length)
|
||||||
|
0x37c MCS_GetFirstDataPointerByDirno
|
||||||
|
int MCS_GetFirstDataPointerByDirno(char *dirno, void *pdata)
|
||||||
|
0x37d MCS_GetDirectoryEntryByNumber
|
||||||
|
int MCS_GetDirectoryEntryByNumber(char dirno, TMainMemoryDirectoryEntry *pdir)
|
||||||
|
0x37e MCS_SearchItem
|
||||||
|
int MCS_SearchItem(unsigned char *item, TMainMemoryDirectoryEntry *pdir, unsigned short *itemno)
|
||||||
|
0x37f MCS_str8cpy
|
||||||
|
int MCS_str8cpy(unsigned char *source, unsigned char *target, int mode)
|
||||||
|
0x380 MCS_GetDirectoryEntryAddress
|
||||||
|
void MCS_GetDirectoryEntryAddress(void *directory_entry_address)
|
||||||
|
0x381 MCS_GetCurrentBottomAddress
|
||||||
|
void MCS_GetCurrentBottomAddress(void *current_bottom_address)
|
||||||
|
0x383 MCS_GetCapa
|
||||||
|
int MCS_GetCapa(int *current_bottom)
|
||||||
|
0x392 MCS_GetMainMemoryStart
|
||||||
|
int MCS_GetMainMemoryStart(void)
|
||||||
|
0x3dc Setup_GetInfo
|
||||||
|
int Setup_GetInfo(unsigned char *, int, TSetupInfo *info), where the first arguments are used only in fx-CG 10/20
|
||||||
|
0x3ea the start of a datatable ***
|
||||||
|
0x3ed Interrupt_SetOrClrStatusFlags
|
||||||
|
int Interrupt_SetOrClrStatusFlags(int flagmask, int set)
|
||||||
|
0x3ee Interrupt_QueryStatusFlags
|
||||||
|
int Interrupt_QueryStatusFlags(int flagmask, int clear)
|
||||||
|
0x3f4 PowerOff
|
||||||
|
0x3f5 ClearMainMemory
|
||||||
|
0x3f6 SH7337_TMU_Stop
|
||||||
|
0x3f7 SH7337_TMU_int_handler
|
||||||
|
0x3fa Hmem_SetMMU
|
||||||
|
void Hmem_SetMMU(int virtualPageNumber, int physicalPageNumber, int pageManagement)
|
||||||
|
0x3fb MMU_ConfigureAndFlush
|
||||||
|
void MMU_ConfigureAndFlush(void)
|
||||||
|
0x3fc TLB_SetAddressValue
|
||||||
|
void TLB_SetAddressValue(int entryAddress, int way, int value)
|
||||||
|
0x3fe GetStackPtr
|
||||||
|
0x3ff MMU_FlushCache
|
||||||
|
|
||||||
|
0x400 MMU_ConfigureAndEnable
|
||||||
|
void MMU_ConfigureAndEnable(void)
|
||||||
|
0x404 GetPhysicalROMstart
|
||||||
|
0x405 GetPhysicalRAMstart
|
||||||
|
0x409 Serial_ResetAndDisable
|
||||||
|
void *Serial_ResetAndDisable(void)
|
||||||
|
0x40a Serial_GetInterruptHandler
|
||||||
|
void *Serial_GetInterruptHandler(void)
|
||||||
|
0x40b Serial_SetInterruptHandler
|
||||||
|
int Serial_SetInterruptHandler(int type, void *handler)
|
||||||
|
0x40c Serial_ReadOneByte
|
||||||
|
int Serial_ReadOneByte(unsigned char *result)
|
||||||
|
0x40d Serial_ReadNBytes
|
||||||
|
int Serial_ReadNBytes(unsigned char *result, int max_size, short *actually_transferred)
|
||||||
|
0x40e Serial_BufferedTransmitOneByte
|
||||||
|
int Serial_BufferedTransmitOneByte(unsigned char byte)
|
||||||
|
0x40f Serial_BufferedTransmitNBytes
|
||||||
|
int Serial_BufferedTransmitNBytes(unsigned char *bytes, int requested_count)
|
||||||
|
0x410 Serial_DirectTransmitOneByte
|
||||||
|
int Serial_DirectTransmitOneByte(unsigned char byte)
|
||||||
|
0x411 Serial_GetReceivedBytesAvailable
|
||||||
|
int Serial_GetReceivedBytesAvailable(void)
|
||||||
|
0x412 Serial_GetFreeTransmitSpace
|
||||||
|
int Serial_GetFreeTransmitSpace(void)
|
||||||
|
0x413 Serial_ClearReceiveBuffer
|
||||||
|
int Serial_ClearReceiveBuffer(void)
|
||||||
|
0x414 Serial_ClearTransmitBuffer
|
||||||
|
int Serial_ClearTransmitBuffer(void)
|
||||||
|
0x418 Serial_Open
|
||||||
|
int Serial_Open(unsigned char *mode)
|
||||||
|
0x419 Serial_Close(int mode)
|
||||||
|
0x41b Serial_CallReceiveIntErrorResetHandler
|
||||||
|
void *Serial_CallReceiveIntErrorResetHandler(void)
|
||||||
|
0x41c Serial_CallReceiveIntHandler
|
||||||
|
void *Serial_CallReceiveIntHandler(void)
|
||||||
|
0x41d Serial_CallTransmitIntErrorResetHandler
|
||||||
|
void *Serial_CallTransmitIntErrorResetHandler(void)
|
||||||
|
0x41e Serial_CallTransmitIntHandler
|
||||||
|
void *Serial_CallTransmitIntHandler(void)
|
||||||
|
0x420 OS_inner_Sleep
|
||||||
|
0x422 Serial_SpyNthByte
|
||||||
|
int Serial_SpyNthByte(int byteno_to_spy, unsigned char *result)
|
||||||
|
0x423 Serial_GetStatus
|
||||||
|
void Serial_GetStatus(unsigned int *serial_status)
|
||||||
|
0x425 Serial_IsOpen
|
||||||
|
int Serial_IsOpen(void)
|
||||||
|
0x429 Bfile_identify_device_OS
|
||||||
|
int Bfile_identify_device_OS(const FONTCHARACTER *filename)
|
||||||
|
0x42c Bfile_OpenFile_OS
|
||||||
|
0x42d Bfile_CloseFile_OS
|
||||||
|
0x42e Bfile_GetMediaFree_OS
|
||||||
|
0x42f Bfile_GetFileSize_OS
|
||||||
|
0x431 Bfile_SeekFile_OS
|
||||||
|
0x432 Bfile_ReadFile_OS
|
||||||
|
0x434 Bfile_CreateEntry_OS
|
||||||
|
0x435 Bfile_WriteFile_OS
|
||||||
|
0x438 Bfile_RenameEntry
|
||||||
|
0x439 Bfile_DeleteEntry
|
||||||
|
0x43b Bfile_FindFirst
|
||||||
|
0x43c Bfile_FindNext
|
||||||
|
0x43d Bfile_FindClose
|
||||||
|
0x44e memcpy
|
||||||
|
0x44f memcmp
|
||||||
|
0x450 Bfile_GetFilenameLength
|
||||||
|
int Bfile_GetFilenameLength(const FONTCHARACTER *filename)
|
||||||
|
0x451 Bfile_Name_cmp
|
||||||
|
0x452 Bfile_Name_cpy
|
||||||
|
0x453 Bfile_Name_ncpy
|
||||||
|
0x456 Bfile_NameToStr_ncpy
|
||||||
|
void Bfile_NameToStr_ncpy(char *dest, FONTCHARACTER *src, int n)
|
||||||
|
0x457 Bfile_StrToName_ncpy
|
||||||
|
void Bfile_StrToName_ncpy(FONTCHARACTER *dest, char *src, int n)
|
||||||
|
0x462 GetAppName
|
||||||
|
char *GetAppName(char *dest)
|
||||||
|
0x463 SetAppName
|
||||||
|
int SetAppName(char *src)
|
||||||
|
0x464 CmpAppName
|
||||||
|
int CmpAppName(char *name)
|
||||||
|
0x465 GetIntPtrContent
|
||||||
|
int GetIntPtrContent(unsigned char *ptr)
|
||||||
|
0x467 LongToAscHex
|
||||||
|
int LongToAscHex(int value, char *dest, int digits)
|
||||||
|
0x468 hasSDOption
|
||||||
|
0x469 Battery_DisplayLowStatus
|
||||||
|
int Battery_DisplayLowStatus(int delayflag)
|
||||||
|
0x46b App_BuiltInCount
|
||||||
|
int App_BuiltInCount(void)
|
||||||
|
0x476 Battery_IsLow
|
||||||
|
int Battery_IsLow(void)
|
||||||
|
0x477 EnableGetkeyToMainFunctionReturn
|
||||||
|
void EnableGetkeyToMainFunctionReturn(void)
|
||||||
|
0x478 DisableGetkeyToMainFunctionReturn
|
||||||
|
void DisableGetkeyToMainFunctionReturn(void)
|
||||||
|
0x47f SetAutoPowerOffTime
|
||||||
|
0x480 GetAutoPowerOffTime
|
||||||
|
0x486 GetdatatablePtr
|
||||||
|
0x48d SetAutoPowerOffFlag
|
||||||
|
0x48e GetAutoPowerOffFlag
|
||||||
|
0x492 Battery_IsLow
|
||||||
|
int Battery_IsLow(int delayflag)
|
||||||
|
0x494 CallbackAtQuitMainFunction
|
||||||
|
0x495 Battery_DisplayLowStatus
|
||||||
|
int Battery_DisplayLowStatus(int delayflag)
|
||||||
|
0x499 Heap_SetTopChunk
|
||||||
|
int Heap_SetTopChunk(int size)
|
||||||
|
0x49a App_Start
|
||||||
|
int App_Start(int r4, int r5, int index, int force)
|
||||||
|
0x49c Battery_GetStatus
|
||||||
|
int Battery_GetStatus(int delayflag)
|
||||||
|
0x49e RebootOS
|
||||||
|
0x4a0 AUX_DisplayErrorMessage
|
||||||
|
void AUX_DisplayErrorMessage(void)
|
||||||
|
0x4ad USB_InterruptHandler
|
||||||
|
0x4ae USB_TimerHandler
|
||||||
|
void USB_TimerHandler(void)
|
||||||
|
0x4b0 AUX_DisplayFKeyIcons
|
||||||
|
void AUX_DisplayFKeyIcons(void)
|
||||||
|
0x4cb Keyboard_RemapFKeyCode
|
||||||
|
void Keyboard_RemapFKeyCode(int mode, TFKeyDef *source)
|
||||||
|
0x4d1 AUX_DisplayFKeyIcon
|
||||||
|
void AUX_DisplayFKeyIcon(int pos, unsigned char *bitmap)
|
||||||
|
0x4dc char Setup_GetEntry(unsigned int index)
|
||||||
|
0x4dd Setup_SetEntry
|
||||||
|
char *Setup_SetEntry(unsigned int index, char setting)
|
||||||
|
0x4de Setup_GetEntryPtr
|
||||||
|
char *Setup_GetEntryPtr(unsigned int index)
|
||||||
|
0x4df Alpha_GetData
|
||||||
|
char *Alpha_GetData(char var, char *dest)
|
||||||
|
0x4e0 Alpha_SetData
|
||||||
|
char *Alpha_SetData(char var, char *src)
|
||||||
|
0x4e1 Alpha_ClearAll
|
||||||
|
void Alpha_ClearAll(void)
|
||||||
|
0x4e6 HourGlass
|
||||||
|
void HourGlass(void)
|
||||||
|
0x4e9 LocalizeStringID
|
||||||
|
0x4f5 BCD_ToStrAsNumber1
|
||||||
|
int BCD_ToStrAsNumber1(char *data, char *string)
|
||||||
|
0x4f6 BCD_ToStrAsNumber2
|
||||||
|
int BCD_ToStrAsNumber2(char *data, char *string)
|
||||||
|
|
||||||
|
0x500 BCDToInternal
|
||||||
|
int BCDToInternal(TBCDinternal *target, TBCDvalue *source)
|
||||||
|
0x518 Setup_GetEntry_3E
|
||||||
|
0x519 Setup_GetEntry_40
|
||||||
|
0x51a Setup_SetEntry_3E
|
||||||
|
0x51b Setup_SetEntry_40
|
||||||
|
0x531 MB_IsLead
|
||||||
|
int MB_IsLead(char c)
|
||||||
|
0x533 MB_ElementCount
|
||||||
|
int MB_ElementCount(char *str)
|
||||||
|
0x534 MB_ByteCount
|
||||||
|
int MB_ByteCount(char *str)
|
||||||
|
0x536 MB_strcat
|
||||||
|
char *MB_strcat(char *dest, char *src)
|
||||||
|
0x537 MB_strncat
|
||||||
|
char *MB_strncat(char *dest, char *src, int bytes)
|
||||||
|
0x538 MB_strcpy
|
||||||
|
char *MB_strcpy(char *dest, char *src)
|
||||||
|
0x53c MB_GetSecondElemPtr
|
||||||
|
char *MB_GetSecondElemPtr(char *str)
|
||||||
|
0x53d MB_GetElement
|
||||||
|
short MB_GetElement(char *str)
|
||||||
|
0x53e MB_CopyToHeap
|
||||||
|
char *MB_CopyToHeap(char *src)
|
||||||
|
0x53f memcmp
|
||||||
|
0x541 itoa
|
||||||
|
0x542 to_uppercase
|
||||||
|
0x543 to_lowercase
|
||||||
|
0x544 BCD_0
|
||||||
|
0x545 BCD_1
|
||||||
|
0x546 BCD_2
|
||||||
|
0x547 BCD_10
|
||||||
|
0x548 BCD_1/3
|
||||||
|
0x549 BCD_0.5
|
||||||
|
0x54a BCD_32767
|
||||||
|
0x54b BCD_-32768
|
||||||
|
0x54c BCD_65536
|
||||||
|
0x54d BCD_0x7fffffff
|
||||||
|
0x54e BCD_-2Gi
|
||||||
|
0x54f BCD_4Gi
|
||||||
|
0x550 BCD_pi
|
||||||
|
0x551 BCD_2pi
|
||||||
|
0x552 BCD_pi/2
|
||||||
|
0x553 BCD_e
|
||||||
|
0x554 BCD_5
|
||||||
|
0x5a6 BCD_SetAsInt
|
||||||
|
int BCD_SetAsInt(int input, TBCDValue *result)
|
||||||
|
0x5af BCD_pi/4
|
||||||
|
0x5b0 BCD_ln(10)
|
||||||
|
0x5b1 BCD_ln(2)
|
||||||
|
0x5b2 BCD_9.99e+99
|
||||||
|
0x5b3 BCD_-9.99e+99
|
||||||
|
0x5b4 BCD_9.99999999999999e+99
|
||||||
|
0x5b5 BCD_227.85
|
||||||
|
0x5b6 BCD_sqrt(2)
|
||||||
|
0x5b7 BCD_sqrt(2)/2
|
||||||
|
0x5b8 BCD_506.6282746310
|
||||||
|
|
||||||
|
0x645 CalculateExpression
|
||||||
|
void CalculateExpression(char **formula, char opcode[2], TBCDValue *result, int p4)
|
||||||
|
0x64a CalculateExpression0
|
||||||
|
0x652 PRGM_NextOpcode
|
||||||
|
void PRGM_NextOpcode(char opcode[2], char **program)
|
||||||
|
0x6a6 PRGM_IsEndOfLine
|
||||||
|
int PRGM_IsEndOfLine(char *opcode)
|
||||||
|
0x6c4 Keyboard_PRGM_GetKey
|
||||||
|
int Keyboard_PRGM_GetKey(TBCDValue *result)
|
||||||
|
0x6d4 Alpha_GetData2
|
||||||
|
int Alpha_GetData2(char var, char *dest)
|
||||||
|
|
||||||
|
0x713 Print_ClearLine
|
||||||
|
0x763 Bdisp_DrawRectangle
|
||||||
|
void Bdisp_DrawRectangle(int x1, int y1, int x2, int y2)
|
||||||
|
0x7fc OpcodeToStr
|
||||||
|
int OpcodeToStr(unsigned short opcode, unsigned char *string)
|
||||||
|
|
||||||
|
0x804 CLIP_Store
|
||||||
|
int CLIP_Store(unsigned char *buffer, int length)
|
||||||
|
0x807 locate
|
||||||
|
0x808 Print
|
||||||
|
0x809 PrintRev
|
||||||
|
0x80a PrintC
|
||||||
|
0x80b PrintRevC
|
||||||
|
0x80c PrintLine
|
||||||
|
0x80d PrintRLine
|
||||||
|
0x80e Cursor_GetFlashStyle
|
||||||
|
int Cursor_GetFlashStyle(void)
|
||||||
|
0x80f Cursor_GetSettings
|
||||||
|
int Cursor_GetSettings(struct CursorSettings *settings)
|
||||||
|
0x811 Cursor_SetFlashOn
|
||||||
|
void Cursor_SetFlashOn(char flash_style)
|
||||||
|
0x812 Cursor_SetFlashOff
|
||||||
|
void Cursor_SetFlashOff(void)
|
||||||
|
0x813 SaveDisp
|
||||||
|
0x814 RestoreDisp
|
||||||
|
0x829 MCS_CreateDirectory
|
||||||
|
unsigned char *MCS_CreateDirectory(unsigned char *dir)
|
||||||
|
0x82a MCS_PutInternalItem
|
||||||
|
int MCS_PutInternalItem(char dirtype, unsigned char *item, int data_len, void *buffer)
|
||||||
|
0x82b MCSPutVar2
|
||||||
|
int MCSPutVar2(unsigned char *dir, unsigned char *item, int data_len, void *buffer)
|
||||||
|
0x830 MCSOvwDat2
|
||||||
|
int MCSOvwDat2(unsigned char *dir, unsigned char *item, int bytes_to_write, void *buffer, int write_offset)
|
||||||
|
0x832 MCS_OverwriteOpenItem
|
||||||
|
int MCS_OverwriteOpenItem(int bytes_to_write, void *buffer, int write_offset)
|
||||||
|
0x833 MCS_ClearInternalDirectory
|
||||||
|
int MCS_ClearInternalDirectory(char dirtype)
|
||||||
|
0x834 MCS_ClearDirectory
|
||||||
|
int MCS_ClearDirectory(unsigned char *dir)
|
||||||
|
0x835 MCS_DeleteInternalItem
|
||||||
|
int MCS_DeleteInternalItem(char dirtype, unsigned char *dir)
|
||||||
|
0x836 MCSDelVar2
|
||||||
|
int MCSDelVar2(unsigned char *dir, unsigned char *item)
|
||||||
|
0x83a MCS_GotoInternalItem
|
||||||
|
int MCS_GotoInternalItem(char dirtype, unsigned char *item, int direction)
|
||||||
|
0x83b MCS_OpenMainMemoryItem
|
||||||
|
int MCS_OpenMainMemoryItem(unsigned char *dir, unsigned char *item, char direction)
|
||||||
|
0x83c MCS_GotoHandleNeighbour
|
||||||
|
int MCS_GotoHandleNeighbour(char direction)
|
||||||
|
0x83d MCS_CheckOpenedItem
|
||||||
|
int MCS_CheckOpenedItem(char *dirtype, int *data_len)
|
||||||
|
0x83e MCS_GetOpenItem
|
||||||
|
int MCS_GetOpenItem(unsigned char *item)
|
||||||
|
0x83f MCS_OpenInternalDirectoryItem
|
||||||
|
int MCS_OpenInternalDirectoryItem(char dirtype, unsigned char *item, int *data_len)
|
||||||
|
0x840 MCSGetDlen2
|
||||||
|
int MCSGetDlen2(unsigned char *dir, unsigned char *item, int *data_len)
|
||||||
|
0x841 MCSGetData1
|
||||||
|
int MCSGetData1(int offset, int len_to_copy, void *buffer)
|
||||||
|
0x843 MCS_MapMCS_Result
|
||||||
|
int MCS_MapMCS_Result(void)
|
||||||
|
0x844 MCSGetCapa
|
||||||
|
0x84d MCS_OpenAlphaMemItem
|
||||||
|
int MCS_OpenAlphaMemItem(char variablename, int *data_len, void *data_ptr)
|
||||||
|
0x852 MCS_DirtypeToItemtype
|
||||||
|
int MCS_DirtypeToItemtype(char dirtype)
|
||||||
|
0x853 MCS_ItemtypeToDirtype
|
||||||
|
int MCS_ItemtypeToDirtype(char itemtype)
|
||||||
|
0x863 MCS_DirtypeToName
|
||||||
|
unsigned char *MCS_DirtypeToName(char dirtype)
|
||||||
|
0x866 MCS_MapError
|
||||||
|
int MCS_MapError(int error_in)
|
||||||
|
0x869 Alpha_ClearAllAndAns
|
||||||
|
void Alpha_ClearAllAndAns(void)
|
||||||
|
0x86f MCS_DeleteDirectoryItems
|
||||||
|
void MCS_DeleteDirectoryItems(unsigned char *dir)
|
||||||
|
0x8db EditExpression
|
||||||
|
int EditExpression(int mode, short key, int row, TBCDValue *value, char *editbuffer, short editbufferlen, char *pretext, int mode2)
|
||||||
|
0x8dc EditValue
|
||||||
|
int EditValue(int mode, short key, int row, TBCDValue *value, char *pretext)
|
||||||
|
0x8e6 EditMBStringCtrl
|
||||||
|
void EditMBStringCtrl(unsigned char *, int xposmax, void *, void *, void *, int, int)
|
||||||
|
0x8ea DisplayMBString
|
||||||
|
void DisplayMBString(unsigned char *, int, int xpos, int x, int y)
|
||||||
|
0x8ec EditMBStringChar
|
||||||
|
void EditMBStringChar(unsigned char *, int xposmax, int xpos, int char)
|
||||||
|
0x8f7 DisplayMBString2
|
||||||
|
void DisplayMBString2(int, unsigned char *, int, int xpos, int zero, int x, int y, int, int, int)
|
||||||
|
0x8fe PopupWin
|
||||||
|
void PopupWin(int nlines)
|
||||||
|
|
||||||
|
0x901 DisplayMessageBox
|
||||||
|
void DisplayMessageBox(int height, unsigned char *message)
|
||||||
|
0x905 DisplayErrorMessage
|
||||||
|
void DisplayErrorMessage(int id)
|
||||||
|
0x90b SetShiftAlphaState
|
||||||
|
0x90c GetInsOverwriteState
|
||||||
|
0x90d SetInsOverwriteState
|
||||||
|
0x90e ClrShiftAlphaState
|
||||||
|
0x90f GetKey
|
||||||
|
int GetKey(unsigned int *keycode)
|
||||||
|
0x910 PutKey
|
||||||
|
int PutKey(int keycode, int mode)
|
||||||
|
0x91b GetShiftAlphaState
|
||||||
|
0x924 TestMode
|
||||||
|
void TestMode(void)
|
||||||
|
0x954 DisplayErrorMessage
|
||||||
|
0x985 App_CONICS
|
||||||
|
0x998 App_DYNA
|
||||||
|
0x9ad PrintXY
|
||||||
|
0x9df App_EACT
|
||||||
|
0x9e1 App_Equation
|
||||||
|
0x9e2 App_EQUA
|
||||||
|
0x9f5 App_Program
|
||||||
|
|
||||||
|
0xa00 App_FINANCE
|
||||||
|
0xa1f Keyboard_RemapFKeyCode
|
||||||
|
void Keyboard_RemapFKeyCode(TKeyDef *workspace, TKeyDef *source, int mode)
|
||||||
|
0xa35 AUX_DisplayMessage
|
||||||
|
0xa48 App_GRAPH_TABLE
|
||||||
|
0xa4a App_LINK
|
||||||
|
0xa6a App_Optimization
|
||||||
|
0xa6b App_Memory
|
||||||
|
0xa75 App_RECUR
|
||||||
|
0xa97 App_RUN_MAT_EXE
|
||||||
|
0xaae App_RUN_MAT
|
||||||
|
0xac6 App_STAT
|
||||||
|
0xac8 App_SYSTEM
|
||||||
|
0xacc free
|
||||||
|
0xacd malloc
|
||||||
|
0xace memcmp
|
||||||
|
0xacf smart_memcpy
|
||||||
|
0xad0 memset
|
||||||
|
0xad4 strcat
|
||||||
|
0xad5 smart_strcmp
|
||||||
|
0xad6 strlen
|
||||||
|
0xad7 strncat
|
||||||
|
0xad8 strncmp
|
||||||
|
0xad9 strncpy
|
||||||
|
0xada strrchr
|
||||||
|
0xae8 CatalogDialog
|
||||||
|
|
||||||
|
0xc4f PrintMiniSd
|
||||||
|
0xca7 OpcodeType
|
||||||
|
int OpcodeType(char *);
|
||||||
|
0xcb0 Basic_Send_Send38k
|
||||||
|
0xcb1 Basic_Receive_Receive38k
|
||||||
|
0xcb2 Basic_OpenComPort38k_CloseComPort38k
|
||||||
|
0xcc4 InputNumber
|
||||||
|
int InputNumber(unsigned char *heading, int maxlen, int mode)
|
||||||
|
0xcc5 InputString
|
||||||
|
int InputString(unsigned char *buffer, unsigned char *heading, int maxlen)
|
||||||
|
0xccb GetRAMSize
|
||||||
|
int GetRAMSize(void)
|
||||||
|
0xcd0 another_diagnostic_dialog
|
||||||
|
|
||||||
|
0xd64 InputDateDialog
|
||||||
|
int InputDateDialog(int *day, int *month, int *year, int *p4)
|
||||||
|
0xd65 InputMonthDialog
|
||||||
|
int InputMonthDialog(int *month, int *p2)
|
||||||
|
0xd66 InputDayDialog
|
||||||
|
int InputDayDialog(int *day, int *p2)
|
||||||
|
0xd67 InputYearDialog
|
||||||
|
int InputYearDialog(int *year, int *p2)
|
||||||
|
0xdab StoreExpressionToGraphFuncMemory
|
||||||
|
void StoreExpressionToGraphFuncMemory(int fun_no, int, char *expression)
|
||||||
|
|
||||||
|
0xe6b calloc
|
||||||
|
0xe6c memmove
|
||||||
|
0xe6d realloc
|
||||||
|
0xe6e strchr
|
||||||
|
0xe6f strstr
|
59
fxos/sys.c
Normal file
59
fxos/sys.c
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <util.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* sys_free_item(): Free a syscall description item */
|
||||||
|
static void sys_free_item(void *item)
|
||||||
|
{
|
||||||
|
struct sys_call *call = item;
|
||||||
|
free(call->name);
|
||||||
|
free(call->descr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sys_load(): Load a syscall table */
|
||||||
|
void sys_load(char const *file)
|
||||||
|
{
|
||||||
|
err_context("syscall", file, NULL);
|
||||||
|
if(!table_available())
|
||||||
|
{
|
||||||
|
err("too many tables, skipping");
|
||||||
|
err_pop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Map the file to memory */
|
||||||
|
int fd;
|
||||||
|
size_t size;
|
||||||
|
void *data = map(file, &fd, &size);
|
||||||
|
if(!data) { err_pop(); return; }
|
||||||
|
|
||||||
|
/* If the file is named "sys-x.txt", use "x" as the table name */
|
||||||
|
char *name = match_table_name(file, "sys", ".txt");
|
||||||
|
|
||||||
|
/* Parse the contents */
|
||||||
|
int count;
|
||||||
|
struct sys_call *calls = lex_sys(data, size, &count);
|
||||||
|
|
||||||
|
table_create("sys", name, sys_free_item, count, sizeof *calls, calls);
|
||||||
|
|
||||||
|
unmap(data, fd, size);
|
||||||
|
err_pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Global storage for the sys_match() function */
|
||||||
|
static uint32_t sys_match_number;
|
||||||
|
|
||||||
|
/* sys_match(): Search routine for sys_find() */
|
||||||
|
static int sys_match(void *item)
|
||||||
|
{
|
||||||
|
struct sys_call *call = item;
|
||||||
|
return call->number == sys_match_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sys_find(): Find information on a given syscall number */
|
||||||
|
struct sys_call const *sys_find(uint32_t number)
|
||||||
|
{
|
||||||
|
sys_match_number = number;
|
||||||
|
return table_find("sys", sys_match, NULL, 0);
|
||||||
|
}
|
115
fxos/tables.c
115
fxos/tables.c
|
@ -1,59 +1,82 @@
|
||||||
#include <stdlib.h>
|
|
||||||
#include <fxos.h>
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* A linked list of pointers (either file names or tables) */
|
/* Up to 128 tables can be defined */
|
||||||
struct element
|
#define MAX 128
|
||||||
|
static struct table db[MAX] = { 0 };
|
||||||
|
/* Number of tables currently used */
|
||||||
|
static int db_size = 0;
|
||||||
|
|
||||||
|
/* table_free(): Free a table and its contents
|
||||||
|
@t Table pointer */
|
||||||
|
static void table_free(struct table *t)
|
||||||
{
|
{
|
||||||
void *data;
|
if(!t) return;
|
||||||
struct element *next;
|
free(t->name);
|
||||||
};
|
|
||||||
|
|
||||||
/* list_append(): Append a pointer to a linked list
|
if(t->items) for(int i = 0; i < t->count; i++)
|
||||||
Returns a pointer to the new node, NULL on error. */
|
|
||||||
struct element *list_append(struct element **head, void *data)
|
|
||||||
{
|
|
||||||
struct element *el = malloc(sizeof *el);
|
|
||||||
if(!el) return NULL;
|
|
||||||
el->data = data;
|
|
||||||
el->next = NULL;
|
|
||||||
|
|
||||||
while(*head) head = &((*head)->next);
|
|
||||||
*head = el;
|
|
||||||
|
|
||||||
return el;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* list_free(): Free a linked list */
|
|
||||||
void list_free(struct element *head, void (*destructor)(void *))
|
|
||||||
{
|
|
||||||
struct element *next;
|
|
||||||
while(head)
|
|
||||||
{
|
{
|
||||||
destructor(head->data);
|
t->free_item(t->items + i * t->size);
|
||||||
next = head->next;
|
|
||||||
free(head);
|
|
||||||
head = next;
|
|
||||||
}
|
}
|
||||||
|
free(t->items);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Table of assembly instruction listings */
|
/* table_quit(): Destroy all allocated tables and release memory */
|
||||||
static struct element *tasm = NULL;
|
__attribute__((destructor))
|
||||||
/* Table of system call information listings */
|
static void table_quit(void)
|
||||||
static struct element *tcall = NULL;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
** Public API
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* tables_add_asm(): Append an instruction table to the table list */
|
|
||||||
int tables_add_asm(const char *filename)
|
|
||||||
{
|
{
|
||||||
return !list_append(&tasm, (void *)filename);
|
for(int i = 0; i < db_size; i++) table_free(&db[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* tables_add_syscall(): Append a syscall table to the table list */
|
/* table_available(): Whether a table can be allocated */
|
||||||
int tables_add_syscall(const char *filename)
|
int table_available(void)
|
||||||
{
|
{
|
||||||
return !list_append(&tcall, (void *)filename);
|
return db_size < MAX;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* table_create(): Create a new table */
|
||||||
|
void table_create(char const *type, char *name, void (*free_item)(void *),
|
||||||
|
int count, size_t size, void *items)
|
||||||
|
{
|
||||||
|
if(!table_available()) return;
|
||||||
|
struct table *t = &db[db_size++];
|
||||||
|
|
||||||
|
t->type = type;
|
||||||
|
t->name = name;
|
||||||
|
t->free_item = free_item;
|
||||||
|
t->count = count;
|
||||||
|
t->size = size;
|
||||||
|
t->items = items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* table_find(): Find matching entries in the database tables */
|
||||||
|
void *table_find(char const *type, int (*match)(void *), char const **name,
|
||||||
|
int next)
|
||||||
|
{
|
||||||
|
static int table = 0;
|
||||||
|
static int index = 0;
|
||||||
|
if(!next) table = index = 0;
|
||||||
|
|
||||||
|
while(table < db_size)
|
||||||
|
{
|
||||||
|
struct table const *t = &db[table];
|
||||||
|
|
||||||
|
if(!strcmp(t->type, type))
|
||||||
|
while(index < t->count)
|
||||||
|
{
|
||||||
|
void *entry = t->items + index * t->size;
|
||||||
|
index++;
|
||||||
|
if(match(entry))
|
||||||
|
{
|
||||||
|
if(name) *name = t->name;
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
table++;
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
72
fxos/util.c
72
fxos/util.c
|
@ -1,10 +1,18 @@
|
||||||
#include <fxos.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
|
||||||
|
#include <fxos.h>
|
||||||
|
#include <errors.h>
|
||||||
|
|
||||||
/* integer(): Convert base 8, 10 or 16 into integers */
|
/* integer(): Convert base 8, 10 or 16 into integers */
|
||||||
long long integer(const char *str, int *error)
|
long long integer(char const *str, int *error)
|
||||||
{
|
{
|
||||||
char *end;
|
char *end;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
|
@ -28,3 +36,63 @@ long long integer(const char *str, int *error)
|
||||||
|
|
||||||
return ll;
|
return ll;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* match_table_name(): Some specific matching on filenames */
|
||||||
|
char *match_table_name(char const *path, char const *type, char const *suffix)
|
||||||
|
{
|
||||||
|
char const *base = strrchr(path, '/');
|
||||||
|
base = (base) ? (base + 1) : (path);
|
||||||
|
|
||||||
|
size_t len = strlen(base);
|
||||||
|
size_t len_t = strlen(type);
|
||||||
|
size_t len_s = strlen(suffix);
|
||||||
|
|
||||||
|
if(len > len_t + len_s + 1
|
||||||
|
&& !strncmp(type, base, len_t)
|
||||||
|
&& base[len_t] == '-'
|
||||||
|
&& !strcmp(suffix, base + len - len_s))
|
||||||
|
{
|
||||||
|
return strndup(base + len_t + 1, len - len_t - len_s - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return strdup(base);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* map(): Map a file to memory */
|
||||||
|
void *map(char const *path, int *fd, size_t *size)
|
||||||
|
{
|
||||||
|
int x;
|
||||||
|
struct stat statbuf;
|
||||||
|
|
||||||
|
*fd = open(path, O_RDONLY);
|
||||||
|
if(*fd < 0)
|
||||||
|
{
|
||||||
|
errf(ERR_ERRNO, "cannot open file");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
x = fstat(*fd, &statbuf);
|
||||||
|
if(x < 0)
|
||||||
|
{
|
||||||
|
errf(ERR_ERRNO, "cannot stat file");
|
||||||
|
close(*fd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = statbuf.st_size;
|
||||||
|
|
||||||
|
void *data = mmap(NULL, *size, PROT_READ, MAP_PRIVATE, *fd, 0);
|
||||||
|
if(data == MAP_FAILED)
|
||||||
|
{
|
||||||
|
errf(ERR_ERRNO, "cannot map file");
|
||||||
|
close(*fd);
|
||||||
|
}
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unmap(): Unmap a file loaded with map() */
|
||||||
|
void unmap(void *data, int fd, size_t size)
|
||||||
|
{
|
||||||
|
munmap(data, size);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
44
fxos/util.h
Normal file
44
fxos/util.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//---
|
||||||
|
// util: Utility functions
|
||||||
|
//---
|
||||||
|
|
||||||
|
#ifndef FXOS_UTIL
|
||||||
|
#define FXOS_UTIL
|
||||||
|
|
||||||
|
/* integer(): Convert base 8, 10 or 16 into integers
|
||||||
|
Prints an error message and sets *error to 1 in case of conversion error or
|
||||||
|
overflow.
|
||||||
|
|
||||||
|
@str Original integer representation ("10", "0x1f", "07")
|
||||||
|
@error Set to 1 on error, otherwise unchanged (can be NULL)
|
||||||
|
Returns result of conversion (valid if *error is not 1) */
|
||||||
|
long long integer(const char *str, int *error);
|
||||||
|
|
||||||
|
/* match_table_name(): Some specific matching on filenames
|
||||||
|
Returns the table name to associate with the file located at @path for a
|
||||||
|
table of type @type, with file suffix @suffix.
|
||||||
|
|
||||||
|
Essentially if the basename of the file at @path is on the form
|
||||||
|
{@type}-{x}{@suffix}
|
||||||
|
then an malloc'ed copy of x is returned. Otherwise an malloc'ed copy of the
|
||||||
|
basename is returned. */
|
||||||
|
char *match_table_name(char const *path, char const *type, char const *suffix);
|
||||||
|
|
||||||
|
/* map(): Map a file to memory
|
||||||
|
Maps a file given by its path to memory, and return the associated region,
|
||||||
|
a file descriptor and the size.
|
||||||
|
|
||||||
|
@path File path
|
||||||
|
@fd Will be set to fd of open file
|
||||||
|
@size Will be set to file size
|
||||||
|
Returns NULL no error, in which case the file is closed and [*fd] and
|
||||||
|
[*size] are undefined; otherwise, returns a pointer to mapped data. */
|
||||||
|
void *map(char const *path, int *fd, size_t *size);
|
||||||
|
|
||||||
|
/* unmap(): Unmap a file loaded with map()
|
||||||
|
@data Region returned by map()
|
||||||
|
@fd File descriptor set by map()
|
||||||
|
@size Size set by map() */
|
||||||
|
void unmap(void *data, int fd, size_t size);
|
||||||
|
|
||||||
|
#endif /* FXOS_UTIL */
|
Loading…
Reference in a new issue