Compare commits
2 Commits
08f1fe0aa6
...
2bb6661834
Author | SHA1 | Date | |
---|---|---|---|
2bb6661834 | |||
63fa737aed |
1
.gitignore
vendored
1
.gitignore
vendored
@ -5,6 +5,7 @@
|
|||||||
*.csv
|
*.csv
|
||||||
*.class
|
*.class
|
||||||
*.out
|
*.out
|
||||||
|
*.elf
|
||||||
main
|
main
|
||||||
print_class
|
print_class
|
||||||
__pycache__
|
__pycache__
|
37
Makefile
37
Makefile
@ -1,48 +1,23 @@
|
|||||||
%.csv: %.ods
|
%.csv: %.ods
|
||||||
libreoffice --headless --convert-to csv:"Text - txt - csv (StarCalc)":44,34,76,,,,true --outdir $(dir $@) $<
|
libreoffice --headless --convert-to csv:"Text - txt - csv (StarCalc)":44,34,76,,,,true --outdir $(dir $@) $<
|
||||||
|
|
||||||
%.class: %.java
|
include java.mk
|
||||||
javac $<
|
|
||||||
|
|
||||||
java/lang/%.class: java/lang/%.java
|
|
||||||
javac --source 8 --target 8 --boot-class-path . $<
|
|
||||||
|
|
||||||
OBJ = \
|
|
||||||
c/decode.o \
|
|
||||||
c/class_file.o \
|
|
||||||
c/debug_class_file.o \
|
|
||||||
c/malloc.o \
|
|
||||||
c/file.o \
|
|
||||||
c/execute.o \
|
|
||||||
c/memory_allocator.o \
|
|
||||||
c/class_resolver.o \
|
|
||||||
c/hash_table.o \
|
|
||||||
c/frame.o \
|
|
||||||
c/printf.o \
|
|
||||||
c/parse.o \
|
|
||||||
c/unparse.o
|
|
||||||
|
|
||||||
MAIN_OBJ = \
|
|
||||||
$(OBJ) \
|
|
||||||
c/main.o
|
|
||||||
|
|
||||||
PRINT_CLASS_OBJ = \
|
|
||||||
$(OBJ) \
|
|
||||||
c/print_class.o \
|
|
||||||
|
|
||||||
CC ?= gcc
|
CC ?= gcc
|
||||||
ARCH = -m32
|
ARCH = -m32
|
||||||
CFLAGS ?= -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -DDEBUG -g
|
CFLAGS += -Wall -Werror -Wfatal-errors -Wno-error=unused-variable -fstack-protector -std=c2x -g
|
||||||
|
CFLAGS += -DDEBUG
|
||||||
|
#CFLAGS += -DDEBUG_PRINT
|
||||||
OPT ?= -O0
|
OPT ?= -O0
|
||||||
DEPFLAGS = -MMD -MP
|
DEPFLAGS = -MMD -MP
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(ARCH) $(CFLAGS) $(OPT) $(DEPFLAGS) -MF ${<}.d -c $< -o $@
|
$(CC) $(ARCH) $(CFLAGS) $(OPT) $(DEPFLAGS) -MF ${<}.d -c $< -o $@
|
||||||
|
|
||||||
print_class: $(PRINT_CLASS_OBJ)
|
print_class: $(OBJ) $(PRINT_CLASS_OBJ)
|
||||||
$(CC) $(ARCH) $^ -o $@
|
$(CC) $(ARCH) $^ -o $@
|
||||||
|
|
||||||
main: $(MAIN_OBJ)
|
main: $(OBJ) $(MAIN_HOSTED_OBJ)
|
||||||
$(CC) $(ARCH) $^ -o $@
|
$(CC) $(ARCH) $^ -o $@
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
|
57
Makefile.dreamcast.mk
Normal file
57
Makefile.dreamcast.mk
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
all: $(patsubst %.cpp,%.elf,$(wildcard example/*.cpp))
|
||||||
|
|
||||||
|
OPT = -O0
|
||||||
|
|
||||||
|
MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST)))))
|
||||||
|
LIB ?= $(MAKEFILE_PATH)/dreamcast
|
||||||
|
CFLAGS += -D__dreamcast__
|
||||||
|
CFLAGS += -DDEBUG
|
||||||
|
#CFLAGS += -DDEBUG_PRINT
|
||||||
|
CFLAGS += -I$(MAKEFILE_PATH)
|
||||||
|
CFLAGS += -I$(MAKEFILE_PATH)/dreamcast/
|
||||||
|
CARCH = -m4-single -ml
|
||||||
|
|
||||||
|
include dreamcast/base.mk
|
||||||
|
include dreamcast/common.mk
|
||||||
|
include dreamcast/headers.mk
|
||||||
|
|
||||||
|
include java.mk
|
||||||
|
|
||||||
|
%.class.o: %.class
|
||||||
|
$(BUILD_BINARY_O)
|
||||||
|
|
||||||
|
%.class.h: %.class
|
||||||
|
$(BUILD_BINARY_H)
|
||||||
|
|
||||||
|
libgcc/%.o: $(LIBGCC)
|
||||||
|
@mkdir -p $(dir $@)
|
||||||
|
ar x --output $(dir $@) $(LIBGCC) $(notdir $@)
|
||||||
|
sh4-none-elf-objdump -t $@ \
|
||||||
|
| grep -E '[.]hidden' \
|
||||||
|
| grep -vE 'UND' \
|
||||||
|
| cut -d' ' -f10 \
|
||||||
|
| xargs rebind --visibility=default $@
|
||||||
|
|
||||||
|
LIBGCC_OBJ = \
|
||||||
|
libgcc/_divdi3.o \
|
||||||
|
libgcc/_udiv_qrnnd_16.o \
|
||||||
|
libgcc/_clz.o \
|
||||||
|
libgcc/_moddi3.o \
|
||||||
|
libgcc/_fixdfdi.o \
|
||||||
|
libgcc/_fixunsdfdi.o \
|
||||||
|
libgcc/_fixunssfdi.o \
|
||||||
|
libgcc/_floatdisf.o \
|
||||||
|
libgcc/_floatdidf.o \
|
||||||
|
libgcc/_sdivsi3.o \
|
||||||
|
libgcc/_fixsfdi.o \
|
||||||
|
libgcc/_div_table.o
|
||||||
|
|
||||||
|
CLASS_FILES = \
|
||||||
|
p/Native.class.o \
|
||||||
|
java/lang/String.class.o \
|
||||||
|
java/lang/System.class.o \
|
||||||
|
java/io/PrintStream.class.o \
|
||||||
|
java/lang/Object.class.o
|
||||||
|
|
||||||
|
main.elf: LDSCRIPT = $(LIB)/main.lds
|
||||||
|
main.elf: $(START_OBJ) $(OBJ) $(MAIN_OBJ) $(MAIN_DREAMCAST_OBJ) $(LIBGCC_OBJ) $(CLASS_FILES)
|
10
c/assert.h
10
c/assert.h
@ -1,11 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#if defined(__linux__)
|
#if defined(__dreamcast__)
|
||||||
#include "assert_hosted.h"
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
#include "assert_hosted.h"
|
|
||||||
#elif defined(__APPLE__)
|
|
||||||
#include "assert_hosted.h"
|
|
||||||
#else
|
|
||||||
#include "assert_dreamcast.h"
|
#include "assert_dreamcast.h"
|
||||||
|
#else
|
||||||
|
#include "assert_hosted.h"
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,3 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define assert(b)
|
#include "printf.h"
|
||||||
|
|
||||||
|
#define assert(b) \
|
||||||
|
do { \
|
||||||
|
if (!(b)) { \
|
||||||
|
printf("%s:%d %s: assertion `%s` failed\n", __FILE__, __LINE__, __func__, #b); \
|
||||||
|
while (1); \
|
||||||
|
} \
|
||||||
|
} while (0);
|
||||||
|
@ -147,9 +147,7 @@ static void class_resolver_allocate_attribute_entry(struct class_entry * class_e
|
|||||||
class_entry->attribute_entry = attribute_entry;
|
class_entry->attribute_entry = attribute_entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t * class_names[],
|
struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buffers,
|
||||||
const int class_names_length[],
|
|
||||||
uint8_t * buffers[],
|
|
||||||
int length,
|
int length,
|
||||||
int * hash_table_length)
|
int * hash_table_length)
|
||||||
{
|
{
|
||||||
@ -167,10 +165,15 @@ struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t * class
|
|||||||
class_entry[i].class_file = class_file;
|
class_entry[i].class_file = class_file;
|
||||||
class_entry[i].initialization_state = CLASS_UNINITIALIZED;
|
class_entry[i].initialization_state = CLASS_UNINITIALIZED;
|
||||||
|
|
||||||
|
struct constant * class_constant = &class_file->constant_pool[class_file->this_class - 1];
|
||||||
|
assert(class_constant->tag == CONSTANT_Class);
|
||||||
|
struct constant * class_name_constant = &class_file->constant_pool[class_constant->class.name_index - 1];
|
||||||
|
assert(class_name_constant->tag == CONSTANT_Utf8);
|
||||||
|
|
||||||
hash_table_add(class_hash_table_length,
|
hash_table_add(class_hash_table_length,
|
||||||
class_hash_table,
|
class_hash_table,
|
||||||
class_names[i],
|
class_name_constant->utf8.bytes,
|
||||||
class_names_length[i],
|
class_name_constant->utf8.length,
|
||||||
&class_entry[i]);
|
&class_entry[i]);
|
||||||
|
|
||||||
// make hash table for interfaces
|
// make hash table for interfaces
|
||||||
|
@ -48,9 +48,7 @@ struct class_entry {
|
|||||||
} methods;
|
} methods;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t * class_names[],
|
struct hash_table_entry * class_resolver_load_from_buffers(const uint8_t ** buffers,
|
||||||
const int class_names_length[],
|
|
||||||
uint8_t * buffers[],
|
|
||||||
int length,
|
int length,
|
||||||
int * hash_table_length);
|
int * hash_table_length);
|
||||||
struct class_entry * class_resolver_lookup_class(int class_hash_table_length,
|
struct class_entry * class_resolver_lookup_class(int class_hash_table_length,
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <inttypes.h>
|
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "class_file.h"
|
#include "class_file.h"
|
||||||
@ -51,7 +50,7 @@ void print_constant(struct constant * constant)
|
|||||||
*(float *)(&constant->_float.bytes));
|
*(float *)(&constant->_float.bytes));
|
||||||
break;
|
break;
|
||||||
case CONSTANT_Long:
|
case CONSTANT_Long:
|
||||||
debugf("CONSTANT_Long bytes=%" PRId64 "\n",
|
debugf("CONSTANT_Long bytes=%l\n",
|
||||||
constant->_long.bytes);
|
constant->_long.bytes);
|
||||||
break;
|
break;
|
||||||
case CONSTANT_Double:
|
case CONSTANT_Double:
|
||||||
|
@ -94,4 +94,7 @@ static inline int32_t aligned_s4(const void * buf)
|
|||||||
|
|
||||||
#define WIDE_NEXT_PC 0
|
#define WIDE_NEXT_PC 0
|
||||||
|
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||||
#include "decode.inc.c"
|
#include "decode.inc.c"
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
130
c/frame.c
130
c/frame.c
@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "class_file.h"
|
#include "class_file.h"
|
||||||
#include "memory.h"
|
|
||||||
#include "debug_class_file.h"
|
#include "debug_class_file.h"
|
||||||
#include "bytes.h"
|
#include "bytes.h"
|
||||||
#include "decode.h"
|
#include "decode.h"
|
||||||
@ -10,6 +9,7 @@
|
|||||||
#include "class_resolver.h"
|
#include "class_resolver.h"
|
||||||
#include "printf.h"
|
#include "printf.h"
|
||||||
#include "string.h"
|
#include "string.h"
|
||||||
|
#include "native.h"
|
||||||
|
|
||||||
struct Code_attribute * get_code_attribute(int code_name_index,
|
struct Code_attribute * get_code_attribute(int code_name_index,
|
||||||
int attributes_count,
|
int attributes_count,
|
||||||
@ -75,9 +75,17 @@ static int descriptor_nargs(struct constant * descriptor_constant, uint8_t * ret
|
|||||||
nargs += 1;
|
nargs += 1;
|
||||||
while (descriptor_constant->utf8.bytes[i] != ';') i += 1;
|
while (descriptor_constant->utf8.bytes[i] != ';') i += 1;
|
||||||
break;
|
break;
|
||||||
default:
|
case 'B': [[fallthrough]];
|
||||||
|
case 'C': [[fallthrough]];
|
||||||
|
case 'F': [[fallthrough]];
|
||||||
|
case 'I': [[fallthrough]];
|
||||||
|
case 'S': [[fallthrough]];
|
||||||
|
case 'Z':
|
||||||
nargs += 1;
|
nargs += 1;
|
||||||
break;
|
break;
|
||||||
|
default:
|
||||||
|
assert(false);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
@ -187,18 +195,49 @@ bool vm_initialize_class(struct vm * vm, struct class_entry * class_entry)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info)
|
void vm_native_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info, int nargs, uint8_t return_type)
|
||||||
{
|
{
|
||||||
/* If the method is not native, the nargs argument values are popped from the
|
debugf("vm_static_native_method_call: nargs %d\n", nargs);
|
||||||
operand stack. A new frame is created on the Java Virtual Machine stack for
|
|
||||||
the method being invoked. The nargs argument values are consecutively made
|
|
||||||
the values of local variables of the new frame, with arg1 in local variable
|
|
||||||
0 (or, if arg1 is of type long or double, in local variables 0 and 1) and
|
|
||||||
so on. The new frame is then made current, and the Java Virtual Machine pc
|
|
||||||
is set to the opcode of the first instruction of the method to be
|
|
||||||
invoked. Execution continues with the first instruction of the method.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
uint32_t args[nargs];
|
||||||
|
for (int i = 0; i < nargs; i++) {
|
||||||
|
uint32_t value = operand_stack_pop_u32(vm->current_frame);
|
||||||
|
debugf("args[%d] = %x\n", nargs - i - 1, value);
|
||||||
|
args[nargs - i - 1] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
debugf("native:\n ");
|
||||||
|
struct constant * class_constant = &class_entry->class_file->constant_pool[class_entry->class_file->this_class - 1];
|
||||||
|
struct constant * class_name_constant = &class_entry->class_file->constant_pool[class_constant->class.name_index - 1];
|
||||||
|
print_constant(class_name_constant);
|
||||||
|
debugf(" ");
|
||||||
|
struct constant * method_name_constant = &class_entry->class_file->constant_pool[method_info->name_index - 1];
|
||||||
|
print_constant(method_name_constant);
|
||||||
|
|
||||||
|
int java_io_printstream_length = 19;
|
||||||
|
bool java_io_printstream =
|
||||||
|
class_name_constant->utf8.length == java_io_printstream_length &&
|
||||||
|
hash_table_key_equal(class_name_constant->utf8.bytes, (const uint8_t *)"java/io/PrintStream", class_name_constant->utf8.length);
|
||||||
|
if (java_io_printstream) {
|
||||||
|
int write_length = 5;
|
||||||
|
bool write =
|
||||||
|
method_name_constant->utf8.length == write_length &&
|
||||||
|
hash_table_key_equal(method_name_constant->utf8.bytes, (const uint8_t *)"write", method_name_constant->utf8.length);
|
||||||
|
if (write) {
|
||||||
|
if (nargs == 1) {
|
||||||
|
native_java_io_printstream_write_1(args);
|
||||||
|
return;
|
||||||
|
} else if (nargs == 2) {
|
||||||
|
native_java_io_printstream_write_2(args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void vm_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info, int nargs, uint8_t return_type)
|
||||||
|
{
|
||||||
int code_name_index = find_code_name_index(class_entry->class_file);
|
int code_name_index = find_code_name_index(class_entry->class_file);
|
||||||
assert(code_name_index > 0);
|
assert(code_name_index > 0);
|
||||||
|
|
||||||
@ -215,11 +254,8 @@ void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, st
|
|||||||
vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack);
|
vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack);
|
||||||
vm->current_frame->operand_stack_ix = 0;
|
vm->current_frame->operand_stack_ix = 0;
|
||||||
vm->current_frame->initialization_frame = 0;
|
vm->current_frame->initialization_frame = 0;
|
||||||
|
vm->current_frame->return_type = return_type;
|
||||||
|
|
||||||
struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1];
|
|
||||||
int nargs = descriptor_nargs(descriptor_constant, &vm->current_frame->return_type);
|
|
||||||
nargs += 1;
|
|
||||||
debugf("nargs+1: %d\n", nargs);
|
|
||||||
for (int i = 0; i < nargs; i++) {
|
for (int i = 0; i < nargs; i++) {
|
||||||
uint32_t value = operand_stack_pop_u32(old_frame);
|
uint32_t value = operand_stack_pop_u32(old_frame);
|
||||||
debugf("local[%d] = %x\n", nargs - i - 1, value);
|
debugf("local[%d] = %x\n", nargs - i - 1, value);
|
||||||
@ -233,6 +269,31 @@ void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, st
|
|||||||
debugf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix);
|
debugf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info)
|
||||||
|
{
|
||||||
|
/* If the method is not native, the nargs argument values are popped from the
|
||||||
|
operand stack. A new frame is created on the Java Virtual Machine stack for
|
||||||
|
the method being invoked. The nargs argument values are consecutively made
|
||||||
|
the values of local variables of the new frame, with arg1 in local variable
|
||||||
|
0 (or, if arg1 is of type long or double, in local variables 0 and 1) and
|
||||||
|
so on. The new frame is then made current, and the Java Virtual Machine pc
|
||||||
|
is set to the opcode of the first instruction of the method to be
|
||||||
|
invoked. Execution continues with the first instruction of the method.
|
||||||
|
*/
|
||||||
|
|
||||||
|
uint8_t return_type;
|
||||||
|
struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1];
|
||||||
|
int nargs = descriptor_nargs(descriptor_constant, &return_type);
|
||||||
|
nargs += 1;
|
||||||
|
debugf("nargs+1: %d\n", nargs);
|
||||||
|
|
||||||
|
if (method_info->access_flags & METHOD_ACC_NATIVE) {
|
||||||
|
vm_native_method_call(vm, class_entry, method_info, nargs, return_type);
|
||||||
|
} else {
|
||||||
|
vm_method_call(vm, class_entry, method_info, nargs, return_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info)
|
void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, struct method_info * method_info)
|
||||||
{
|
{
|
||||||
/* If the method is not native, the nargs argument values are popped from the
|
/* If the method is not native, the nargs argument values are popped from the
|
||||||
@ -245,38 +306,16 @@ void vm_static_method_call(struct vm * vm, struct class_entry * class_entry, str
|
|||||||
invoked. Execution continues with the first instruction of the method.
|
invoked. Execution continues with the first instruction of the method.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int code_name_index = find_code_name_index(class_entry->class_file);
|
uint8_t return_type;
|
||||||
assert(code_name_index > 0);
|
|
||||||
|
|
||||||
struct Code_attribute * code = get_code_attribute(code_name_index,
|
|
||||||
method_info->attributes_count,
|
|
||||||
method_info->attributes);
|
|
||||||
assert(code != nullptr);
|
|
||||||
|
|
||||||
struct frame * old_frame = vm->current_frame;
|
|
||||||
|
|
||||||
vm->current_frame = stack_push_frame(&vm->frame_stack, 1);
|
|
||||||
vm->current_frame->code = code;
|
|
||||||
vm->current_frame->local_variable = stack_push_data(&vm->data_stack, code->max_locals);
|
|
||||||
vm->current_frame->operand_stack = stack_push_data(&vm->data_stack, code->max_stack);
|
|
||||||
vm->current_frame->operand_stack_ix = 0;
|
|
||||||
vm->current_frame->initialization_frame = 0;
|
|
||||||
|
|
||||||
struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1];
|
struct constant * descriptor_constant = &class_entry->class_file->constant_pool[method_info->descriptor_index - 1];
|
||||||
int nargs = descriptor_nargs(descriptor_constant, &vm->current_frame->return_type);
|
int nargs = descriptor_nargs(descriptor_constant, &return_type);
|
||||||
debugf("nargs %d\n", nargs);
|
debugf("nargs %d\n", nargs);
|
||||||
for (int i = 0; i < nargs; i++) {
|
|
||||||
uint32_t value = operand_stack_pop_u32(old_frame);
|
if (method_info->access_flags & METHOD_ACC_NATIVE) {
|
||||||
debugf("local[%d] = %x\n", nargs - i - 1, value);
|
vm_native_method_call(vm, class_entry, method_info, nargs, return_type);
|
||||||
vm->current_frame->local_variable[nargs - i - 1] = value;
|
} else {
|
||||||
|
vm_method_call(vm, class_entry, method_info, nargs, return_type);
|
||||||
}
|
}
|
||||||
;
|
|
||||||
|
|
||||||
vm->current_frame->pc = 0;
|
|
||||||
vm->current_frame->class_entry = class_entry;
|
|
||||||
vm->current_frame->method = method_info;
|
|
||||||
|
|
||||||
debugf("operand_stack_ix: %d\n", vm->current_frame->operand_stack_ix);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void vm_method_return(struct vm * vm)
|
void vm_method_return(struct vm * vm)
|
||||||
@ -399,6 +438,7 @@ void vm_start(int class_hash_table_length,
|
|||||||
class_hash_table,
|
class_hash_table,
|
||||||
main_class,
|
main_class,
|
||||||
main_class_length);
|
main_class_length);
|
||||||
|
|
||||||
assert(class_entry != nullptr);
|
assert(class_entry != nullptr);
|
||||||
|
|
||||||
const char * method_name = "main";
|
const char * method_name = "main";
|
||||||
|
@ -77,15 +77,6 @@ void hash_table_add(int hash_table_length,
|
|||||||
e->value = value;
|
e->value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline bool key_equal(const uint8_t * a, const uint8_t * b, int length)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < length; i++) {
|
|
||||||
if (a[i] != b[i])
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct hash_table_entry * hash_table_find(int hash_table_length,
|
struct hash_table_entry * hash_table_find(int hash_table_length,
|
||||||
struct hash_table_entry * entry,
|
struct hash_table_entry * entry,
|
||||||
const uint8_t * key,
|
const uint8_t * key,
|
||||||
@ -99,7 +90,7 @@ struct hash_table_entry * hash_table_find(int hash_table_length,
|
|||||||
while (e != nullptr && e->key != nullptr) {
|
while (e != nullptr && e->key != nullptr) {
|
||||||
//debugf("key find: %p ", e->key);
|
//debugf("key find: %p ", e->key);
|
||||||
//print_key(e->key, e->key_length);
|
//print_key(e->key, e->key_length);
|
||||||
if (e->key_length == key_length && key_equal(key, e->key, e->key_length)) {
|
if (e->key_length == key_length && hash_table_key_equal(key, e->key, e->key_length)) {
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
e = e->next;
|
e = e->next;
|
||||||
|
@ -40,13 +40,11 @@ struct hash_table_entry * hash_table_find2(int hash_table_length,
|
|||||||
const uint8_t * key2,
|
const uint8_t * key2,
|
||||||
int key2_length);
|
int key2_length);
|
||||||
|
|
||||||
/*
|
static inline bool hash_table_key_equal(const uint8_t * a, const uint8_t * b, int length)
|
||||||
void hash_table_add_int(int hash_table_length,
|
{
|
||||||
struct hash_table_entry * entry,
|
for (int i = 0; i < length; i++) {
|
||||||
int key,
|
if (a[i] != b[i])
|
||||||
void * value);
|
return false;
|
||||||
|
}
|
||||||
struct hash_table_entry * hash_table_find_int(int hash_table_length,
|
return true;
|
||||||
struct hash_table_entry * entry,
|
}
|
||||||
int key);
|
|
||||||
*/
|
|
||||||
|
41
c/main_dreamcast.c
Normal file
41
c/main_dreamcast.c
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "class_resolver.h"
|
||||||
|
#include "frame.h"
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
#include "sh7091_scif.h"
|
||||||
|
|
||||||
|
#include "p/Native.class.h"
|
||||||
|
#include "java/lang/String.class.h"
|
||||||
|
#include "java/lang/System.class.h"
|
||||||
|
#include "java/io/PrintStream.class.h"
|
||||||
|
#include "java/lang/Object.class.h"
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
scif_init(0);
|
||||||
|
|
||||||
|
const uint8_t * class_file_buffers[] = {
|
||||||
|
(const uint8_t *)&_binary_p_Native_class_start,
|
||||||
|
(const uint8_t *)&_binary_java_lang_String_class_start,
|
||||||
|
(const uint8_t *)&_binary_java_lang_System_class_start,
|
||||||
|
(const uint8_t *)&_binary_java_io_PrintStream_class_start,
|
||||||
|
(const uint8_t *)&_binary_java_lang_Object_class_start,
|
||||||
|
};
|
||||||
|
int class_file_buffers_length = (sizeof (class_file_buffers)) / (sizeof (class_file_buffers[0]));
|
||||||
|
|
||||||
|
const uint8_t * main_class = (const uint8_t *)"p/Native";
|
||||||
|
int main_class_length = string_length((const char *)main_class);
|
||||||
|
|
||||||
|
int class_hash_table_length;
|
||||||
|
struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(class_file_buffers,
|
||||||
|
class_file_buffers_length,
|
||||||
|
&class_hash_table_length);
|
||||||
|
|
||||||
|
vm_start(class_hash_table_length,
|
||||||
|
class_hash_table,
|
||||||
|
main_class,
|
||||||
|
main_class_length);
|
||||||
|
}
|
@ -9,29 +9,15 @@
|
|||||||
|
|
||||||
static struct hash_table_entry * load_from_filenames(const char * filenames[], int length, int * hash_table_length)
|
static struct hash_table_entry * load_from_filenames(const char * filenames[], int length, int * hash_table_length)
|
||||||
{
|
{
|
||||||
const uint8_t ** class_names = (const uint8_t **)filenames;
|
|
||||||
int class_names_length[length];
|
|
||||||
uint8_t * buffers[length];
|
uint8_t * buffers[length];
|
||||||
size_t file_size[length];
|
size_t file_size[length];
|
||||||
|
|
||||||
for (int i = 0; i < length; i++) {
|
for (int i = 0; i < length; i++) {
|
||||||
uint32_t filename_length = string_length(filenames[i]);
|
|
||||||
const char * suffix = ".class";
|
|
||||||
uint32_t suffix_length = string_length(suffix);
|
|
||||||
const char * filename_suffix = &filenames[i][filename_length - suffix_length];
|
|
||||||
if (filename_length <= suffix_length || !string_equal(suffix, filename_suffix)) {
|
|
||||||
printf("invalid class filename: %s\n", filenames[i]);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
class_names_length[i] = filename_length - suffix_length;
|
|
||||||
printf("load class: %s\n", filenames[i]);
|
printf("load class: %s\n", filenames[i]);
|
||||||
|
|
||||||
buffers[i] = file_read(filenames[i], &file_size[i]);
|
buffers[i] = file_read(filenames[i], &file_size[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(class_names,
|
struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers((const uint8_t **)buffers,
|
||||||
class_names_length,
|
|
||||||
buffers,
|
|
||||||
length,
|
length,
|
||||||
hash_table_length);
|
hash_table_length);
|
||||||
|
|
22
c/native.c
Normal file
22
c/native.c
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#include "native.h"
|
||||||
|
#include "printf.h"
|
||||||
|
|
||||||
|
void native_java_io_printstream_write(uint32_t * arrayref)
|
||||||
|
{
|
||||||
|
uint32_t length = arrayref[0];
|
||||||
|
char * buf = (char *)&arrayref[1];
|
||||||
|
print_string(buf, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
void native_java_io_printstream_write_1(uint32_t * args)
|
||||||
|
{
|
||||||
|
uint32_t * arrayref = (uint32_t *)args[0];
|
||||||
|
native_java_io_printstream_write(arrayref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void native_java_io_printstream_write_2(uint32_t * args)
|
||||||
|
{
|
||||||
|
//uint32_t this = args[0];
|
||||||
|
uint32_t * arrayref = (uint32_t *)args[1];
|
||||||
|
native_java_io_printstream_write(arrayref);
|
||||||
|
}
|
7
c/native.h
Normal file
7
c/native.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
void native_java_io_printstream_write(uint32_t * arrayref);
|
||||||
|
void native_java_io_printstream_write_1(uint32_t * args);
|
||||||
|
void native_java_io_printstream_write_2(uint32_t * args);
|
@ -25,9 +25,16 @@ void print_cstring(const char * s);
|
|||||||
void _printf(const char * format, ...);
|
void _printf(const char * format, ...);
|
||||||
|
|
||||||
#define printf(...) _printf(__VA_ARGS__)
|
#define printf(...) _printf(__VA_ARGS__)
|
||||||
|
|
||||||
|
#if defined(DEBUG_PRINT)
|
||||||
#define debugf(...) _printf(__VA_ARGS__)
|
#define debugf(...) _printf(__VA_ARGS__)
|
||||||
#define debugc(c) print_char(c)
|
#define debugc(c) print_char(c)
|
||||||
#define debugs(s) print_cstring(s)
|
#define debugs(s) print_cstring(s)
|
||||||
|
#else
|
||||||
|
#define debugf(...)
|
||||||
|
#define debugc(c)
|
||||||
|
#define debugs(c)
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@ -3,6 +3,62 @@
|
|||||||
|
|
||||||
#include "sh7091_scif.h"
|
#include "sh7091_scif.h"
|
||||||
|
|
||||||
|
void scif_init_wait()
|
||||||
|
{
|
||||||
|
sh7091.TMU.TSTR &= (~tmu::tstr::str1::counter_start) & 0xff; // stop TCNT1
|
||||||
|
sh7091.TMU.TOCR = tmu::tocr::tcoe::tclk_is_external_clock_or_input_capture;
|
||||||
|
sh7091.TMU.TCR1 = tmu::tcr1::tpsc::p_phi_1024; // 1024 / 50MHz = 20.48 μs
|
||||||
|
sh7091.TMU.TCOR1 = 0xffff'ffff;
|
||||||
|
sh7091.TMU.TCNT1 = 0xffff'ffff;
|
||||||
|
sh7091.TMU.TSTR |= tmu::tstr::str1::counter_start;
|
||||||
|
|
||||||
|
uint32_t start = sh7091.TMU.TCNT1;
|
||||||
|
while ((start - sh7091.TMU.TCNT1) < 20);
|
||||||
|
|
||||||
|
sh7091.TMU.TSTR &= (~tmu::tstr::str1::counter_start) & 0xff; // stop TCNT1
|
||||||
|
}
|
||||||
|
|
||||||
|
void scif_init(int bit_rate)
|
||||||
|
{
|
||||||
|
using namespace scif;
|
||||||
|
|
||||||
|
sh7091.SCIF.SCSCR2 = 0; // disable transmission / reception
|
||||||
|
|
||||||
|
sh7091.SCIF.SCSPTR2 = 0; // clear output data pins
|
||||||
|
|
||||||
|
sh7091.SCIF.SCFCR2 = scfcr2::tfrst::reset_operation_enabled
|
||||||
|
| scfcr2::rfrst::reset_operation_enabled;
|
||||||
|
|
||||||
|
sh7091.SCIF.SCSMR2 = scsmr2::chr::_8_bit_data
|
||||||
|
| scsmr2::pe::parity_disabled
|
||||||
|
| scsmr2::stop::_1_stop_bit
|
||||||
|
| scsmr2::cks::p_phi_clock;
|
||||||
|
|
||||||
|
sh7091.SCIF.SCBRR2 = bit_rate; // bps = 1562500 / (SCBRR2 + 1)
|
||||||
|
|
||||||
|
sh7091.SCIF.SCFSR2 = (~scfsr2::er::bit_mask)
|
||||||
|
& (~scfsr2::tend::bit_mask)
|
||||||
|
& (~scfsr2::tdfe::bit_mask)
|
||||||
|
& (~scfsr2::brk::bit_mask)
|
||||||
|
& (~scfsr2::rdf::bit_mask)
|
||||||
|
& (~scfsr2::dr::bit_mask)
|
||||||
|
& 0xffff;
|
||||||
|
|
||||||
|
|
||||||
|
// wait 1 bit interval
|
||||||
|
scif_init_wait();
|
||||||
|
|
||||||
|
sh7091.SCIF.SCFCR2 = scfcr2::rtrg::trigger_on_1_byte
|
||||||
|
| scfcr2::ttrg::trigger_on_8_bytes
|
||||||
|
//| scfcr2::mce::modem_signals_enabled
|
||||||
|
;
|
||||||
|
|
||||||
|
sh7091.SCIF.SCSCR2 = scscr2::te::transmission_enabled
|
||||||
|
| scscr2::re::reception_enabled;
|
||||||
|
|
||||||
|
sh7091.SCIF.SCLSR2 = 0; // clear ORER
|
||||||
|
}
|
||||||
|
|
||||||
void scif_character(const char c)
|
void scif_character(const char c)
|
||||||
{
|
{
|
||||||
using namespace scif;
|
using namespace scif;
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void scif_init_wait();
|
||||||
|
void scif_init(int bit_rate);
|
||||||
void scif_character(const char c);
|
void scif_character(const char c);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
|
32
java.mk
Normal file
32
java.mk
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
%.class: %.java
|
||||||
|
javac $<
|
||||||
|
|
||||||
|
java/%.class: java/%.java
|
||||||
|
javac --source 8 --target 8 --boot-class-path . $<
|
||||||
|
|
||||||
|
OBJ = \
|
||||||
|
c/decode.o \
|
||||||
|
c/class_file.o \
|
||||||
|
c/debug_class_file.o \
|
||||||
|
c/malloc.o \
|
||||||
|
c/execute.o \
|
||||||
|
c/memory_allocator.o \
|
||||||
|
c/class_resolver.o \
|
||||||
|
c/hash_table.o \
|
||||||
|
c/frame.o \
|
||||||
|
c/printf.o \
|
||||||
|
c/parse.o \
|
||||||
|
c/unparse.o \
|
||||||
|
c/native.o
|
||||||
|
|
||||||
|
MAIN_DREAMCAST_OBJ = \
|
||||||
|
c/sh7091_scif.o \
|
||||||
|
c/main_dreamcast.o
|
||||||
|
|
||||||
|
MAIN_HOSTED_OBJ = \
|
||||||
|
c/file.o \
|
||||||
|
c/main_hosted.o
|
||||||
|
|
||||||
|
PRINT_CLASS_OBJ = \
|
||||||
|
c/file.o \
|
||||||
|
c/print_class.o
|
15
java/io/PrintStream.class.h
Normal file
15
java/io/PrintStream.class.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint32_t _binary_java_io_PrintStream_class_start __asm("_binary_java_io_PrintStream_class_start");
|
||||||
|
extern uint32_t _binary_java_io_PrintStream_class_end __asm("_binary_java_io_PrintStream_class_end");
|
||||||
|
extern uint32_t _binary_java_io_PrintStream_class_size __asm("_binary_java_io_PrintStream_class_size");
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
35
java/io/PrintStream.java
Normal file
35
java/io/PrintStream.java
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package java.io;
|
||||||
|
|
||||||
|
import java.lang.String;
|
||||||
|
|
||||||
|
public class PrintStream
|
||||||
|
{
|
||||||
|
public PrintStream() {
|
||||||
|
}
|
||||||
|
|
||||||
|
private final byte[] newline = {'\n'};
|
||||||
|
|
||||||
|
public static native void write(byte[] buf);
|
||||||
|
|
||||||
|
public void println() {
|
||||||
|
write(newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(byte[] buf) {
|
||||||
|
write(buf);
|
||||||
|
write(newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void println(String s) {
|
||||||
|
write(s.getBytes());
|
||||||
|
write(newline);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(byte[] buf) {
|
||||||
|
write(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void print(String s) {
|
||||||
|
write(s.getBytes());
|
||||||
|
}
|
||||||
|
}
|
15
java/lang/Object.class.h
Normal file
15
java/lang/Object.class.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint32_t _binary_java_lang_Object_class_start __asm("_binary_java_lang_Object_class_start");
|
||||||
|
extern uint32_t _binary_java_lang_Object_class_end __asm("_binary_java_lang_Object_class_end");
|
||||||
|
extern uint32_t _binary_java_lang_Object_class_size __asm("_binary_java_lang_Object_class_size");
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,5 +1,5 @@
|
|||||||
package java.lang;
|
package java.lang;
|
||||||
|
|
||||||
class Object {
|
public class Object {
|
||||||
public Object() {}
|
public Object() {}
|
||||||
}
|
}
|
||||||
|
15
java/lang/String.class.h
Normal file
15
java/lang/String.class.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint32_t _binary_java_lang_String_class_start __asm("_binary_java_lang_String_class_start");
|
||||||
|
extern uint32_t _binary_java_lang_String_class_end __asm("_binary_java_lang_String_class_end");
|
||||||
|
extern uint32_t _binary_java_lang_String_class_size __asm("_binary_java_lang_String_class_size");
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -1,6 +1,6 @@
|
|||||||
package java.lang;
|
package java.lang;
|
||||||
|
|
||||||
class String {
|
public class String {
|
||||||
private final byte[] value;
|
private final byte[] value;
|
||||||
|
|
||||||
public String() {
|
public String() {
|
||||||
|
15
java/lang/System.class.h
Normal file
15
java/lang/System.class.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint32_t _binary_java_lang_System_class_start __asm("_binary_java_lang_System_class_start");
|
||||||
|
extern uint32_t _binary_java_lang_System_class_end __asm("_binary_java_lang_System_class_end");
|
||||||
|
extern uint32_t _binary_java_lang_System_class_size __asm("_binary_java_lang_System_class_size");
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
13
java/lang/System.java
Normal file
13
java/lang/System.java
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package java.lang;
|
||||||
|
|
||||||
|
import java.io.PrintStream;
|
||||||
|
|
||||||
|
public final class System {
|
||||||
|
public static PrintStream out = null;
|
||||||
|
|
||||||
|
private System() {
|
||||||
|
}
|
||||||
|
static {
|
||||||
|
out = new PrintStream();
|
||||||
|
}
|
||||||
|
}
|
15
p/Multiply.class.h
Normal file
15
p/Multiply.class.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint32_t _binary_p_Multiply_class_start __asm("_binary_p_Multiply_class_start");
|
||||||
|
extern uint32_t _binary_p_Multiply_class_end __asm("_binary_p_Multiply_class_end");
|
||||||
|
extern uint32_t _binary_p_Multiply_class_size __asm("_binary_p_Multiply_class_size");
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
10
p/Multiply.java
Normal file
10
p/Multiply.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package p;
|
||||||
|
|
||||||
|
class Multiply {
|
||||||
|
static int test(int a, int b) {
|
||||||
|
return a * b;
|
||||||
|
}
|
||||||
|
public static void main() {
|
||||||
|
test(6, 8);
|
||||||
|
}
|
||||||
|
}
|
15
p/Native.class.h
Normal file
15
p/Native.class.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern uint32_t _binary_p_Native_class_start __asm("_binary_p_Native_class_start");
|
||||||
|
extern uint32_t _binary_p_Native_class_end __asm("_binary_p_Native_class_end");
|
||||||
|
extern uint32_t _binary_p_Native_class_size __asm("_binary_p_Native_class_size");
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
10
p/Native.java
Normal file
10
p/Native.java
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
package p;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
class Native {
|
||||||
|
public static void main() {
|
||||||
|
String foo = "hello Dreamcast";
|
||||||
|
System.out.println(foo);
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user