Compare commits

...

2 Commits

Author SHA1 Message Date
635e71ffac initial dreamcast build system 2024-12-26 02:53:35 -06:00
af87766f50 main: remove all non-platform-specific code 2024-12-26 00:57:36 -06:00
19 changed files with 354 additions and 152 deletions

View File

@ -1,34 +1,7 @@
%.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
@ -39,10 +12,10 @@ 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:

51
Makefile.dreamcast.mk Normal file
View File

@ -0,0 +1,51 @@
all: $(patsubst %.cpp,%.elf,$(wildcard example/*.cpp))
OPT = -O0
MAKEFILE_PATH := $(patsubst %/,%,$(dir $(abspath $(firstword $(MAKEFILE_LIST)))))
LIB ?= $(MAKEFILE_PATH)/dreamcast
CFLAGS += -D__dreamcast__ -DDEBUG
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/Multiply.class.o
main.elf: LDSCRIPT = $(LIB)/main.lds
main.elf: $(START_OBJ) $(OBJ) $(MAIN_OBJ) $(MAIN_DREAMCAST_OBJ) $(LIBGCC_OBJ) $(CLASS_FILES)

View File

@ -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

View File

@ -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);

View File

@ -147,9 +147,9 @@ 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 ** class_names,
const int class_names_length[], const int * class_names_length,
uint8_t * buffers[], const uint8_t ** buffers,
int length, int length,
int * hash_table_length) int * hash_table_length)
{ {

View File

@ -48,9 +48,9 @@ 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 ** class_names,
const int class_names_length[], const int * class_names_length,
uint8_t * buffers[], const 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,

View File

@ -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:

View File

@ -2,13 +2,13 @@
#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"
#include "frame.h" #include "frame.h"
#include "class_resolver.h" #include "class_resolver.h"
#include "printf.h" #include "printf.h"
#include "string.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,
@ -388,3 +388,58 @@ void vm_execute(struct vm * vm)
} }
} }
} }
void vm_start(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
const uint8_t * main_class,
int main_class_length)
{
struct class_entry * class_entry = class_resolver_lookup_class(class_hash_table_length,
class_hash_table,
main_class,
main_class_length);
assert(class_entry != nullptr);
const char * method_name = "main";
int method_name_length = string_length(method_name);
const char * method_descriptor = "()V";
int method_descriptor_length = string_length(method_descriptor);
int methods_hash_table_length = class_entry->methods.length;
struct hash_table_entry * methods_hash_table = class_entry->methods.entry;
struct method_info * method_info = class_resolver_lookup_method(methods_hash_table_length,
methods_hash_table,
(const uint8_t *)method_name,
method_name_length,
(const uint8_t *)method_descriptor,
method_descriptor_length);
assert(method_info != nullptr);
struct vm vm;
vm.class_hash_table.entry = class_hash_table;
vm.class_hash_table.length = class_hash_table_length;
vm.frame_stack.ix = 0;
vm.frame_stack.capacity = 1024;
struct frame frames[vm.frame_stack.capacity];
vm.frame_stack.frame = frames;
vm.data_stack.ix = 0;
vm.data_stack.capacity = 0x100000;
uint32_t data[vm.data_stack.capacity];
vm.data_stack.data = data;
struct frame * entry_frame = stack_push_frame(&vm.frame_stack, 1);
struct Code_attribute code;
code.max_locals = 0;
code.max_stack = 0;
entry_frame->code = &code;
entry_frame->local_variable = 0;
entry_frame->operand_stack = 0;
entry_frame->operand_stack_ix = 0;
vm_static_method_call(&vm, class_entry, method_info);
vm_execute(&vm);
}

View File

@ -153,3 +153,7 @@ void vm_special_method_call(struct vm * vm, struct class_entry * class_entry, st
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);
void vm_method_return(struct vm * vm); void vm_method_return(struct vm * vm);
void vm_execute(struct vm * vm); void vm_execute(struct vm * vm);
void vm_start(int class_hash_table_length,
struct hash_table_entry * class_hash_table,
const uint8_t * main_class,
int main_class_length);

105
c/main.c
View File

@ -1,105 +0,0 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "frame.h"
#include "class_resolver.h"
#include "string.h"
#include "file.h"
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];
size_t file_size[length];
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]);
buffers[i] = file_read(filenames[i], &file_size[i]);
}
struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(class_names,
class_names_length,
buffers,
length,
hash_table_length);
for (int i = 0; i < length; i++) {
memset(buffers[i], 0, file_size[i]);
free(buffers[i]);
}
return class_hash_table;
}
int main(int argc, const char * argv[])
{
assert(argc >= 3);
const char * main_class = argv[1];
const char ** class_filenames = &argv[2];
int num_class_filenames = argc - 2;
int class_hash_table_length;
struct hash_table_entry * class_hash_table = load_from_filenames(class_filenames, num_class_filenames, &class_hash_table_length);
struct class_entry * class_entry = class_resolver_lookup_class(class_hash_table_length,
class_hash_table,
(const uint8_t *)main_class,
string_length(main_class));
assert(class_entry != nullptr);
const char * method_name = "main";
int method_name_length = string_length(method_name);
const char * method_descriptor = "()V";
int method_descriptor_length = string_length(method_descriptor);
int methods_hash_table_length = class_entry->methods.length;
struct hash_table_entry * methods_hash_table = class_entry->methods.entry;
struct method_info * method_info = class_resolver_lookup_method(methods_hash_table_length,
methods_hash_table,
(const uint8_t *)method_name,
method_name_length,
(const uint8_t *)method_descriptor,
method_descriptor_length);
assert(method_info != nullptr);
struct vm vm;
vm.class_hash_table.entry = class_hash_table;
vm.class_hash_table.length = class_hash_table_length;
vm.frame_stack.ix = 0;
vm.frame_stack.capacity = 1024;
struct frame frames[vm.frame_stack.capacity];
vm.frame_stack.frame = frames;
vm.data_stack.ix = 0;
vm.data_stack.capacity = 0x100000;
uint32_t data[vm.data_stack.capacity];
vm.data_stack.data = data;
struct frame * entry_frame = stack_push_frame(&vm.frame_stack, 1);
struct Code_attribute code;
code.max_locals = 0;
code.max_stack = 0;
entry_frame->code = &code;
entry_frame->local_variable = 0;
entry_frame->operand_stack = 0;
entry_frame->operand_stack_ix = 0;
vm_static_method_call(&vm, class_entry, method_info);
vm_execute(&vm);
}

43
c/main_dreamcast.c Normal file
View File

@ -0,0 +1,43 @@
#include <stdint.h>
#include "string.h"
#include "class_resolver.h"
#include "frame.h"
#include "printf.h"
#include "sh7091_scif.h"
#include "p/Multiply.class.h"
void main()
{
scif_init(0);
const uint8_t * class_names[1];
int class_names_length[1];
class_names[0] = (const uint8_t *)"p/Multiply";
class_names_length[0] = string_length((const char *)class_names[0]);
const uint8_t * buffers[1];
buffers[0] = (const uint8_t *)&_binary_p_Multiply_class_start;
const uint8_t * main_class = class_names[0];
int main_class_length = class_names_length[0];
int length = (sizeof (class_names)) / (sizeof (class_names[0]));
int class_hash_table_length;
struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(class_names,
class_names_length,
buffers,
length,
&class_hash_table_length);
vm_start(class_hash_table_length,
class_hash_table,
main_class,
main_class_length);
while (1);
}

63
c/main_hosted.c Normal file
View File

@ -0,0 +1,63 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "frame.h"
#include "class_resolver.h"
#include "string.h"
#include "file.h"
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];
size_t file_size[length];
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]);
buffers[i] = file_read(filenames[i], &file_size[i]);
}
struct hash_table_entry * class_hash_table = class_resolver_load_from_buffers(class_names,
class_names_length,
buffers,
length,
hash_table_length);
for (int i = 0; i < length; i++) {
memset(buffers[i], 0, file_size[i]);
free(buffers[i]);
}
return class_hash_table;
}
int main(int argc, const char * argv[])
{
assert(argc >= 3);
const uint8_t * main_class = (const uint8_t *)argv[1];
int main_class_length = string_length((const char *)main_class);
const char ** class_filenames = &argv[2];
int num_class_filenames = argc - 2;
int class_hash_table_length;
struct hash_table_entry * class_hash_table = load_from_filenames(class_filenames, num_class_filenames, &class_hash_table_length);
vm_start(class_hash_table_length,
class_hash_table,
main_class,
main_class_length);
}

View File

@ -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;

View File

@ -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

1
dreamcast Symbolic link
View File

@ -0,0 +1 @@
../dreamcast

31
java.mk Normal file
View File

@ -0,0 +1,31 @@
%.class: %.java
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/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_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

BIN
main.elf Executable file

Binary file not shown.

15
p/Multiply.class.h Normal file
View 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
View 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);
}
}