diff --git a/alt.lds b/alt.lds index ccd8937..7253641 100644 --- a/alt.lds +++ b/alt.lds @@ -1,8 +1,11 @@ OUTPUT_FORMAT("elf32-shl", "elf32-shl", "elf32-shl") MEMORY { - p1ram : ORIGIN = 0x8c020000, LENGTH = 0xfe0000 - p2ram : ORIGIN = 0xac020000, LENGTH = 0xfe0000 + p1ram : ORIGIN = 0xac080000, LENGTH = 0xfe0000 + p2ram : ORIGIN = 0xac080000, LENGTH = 0xfe0000 } __stack_reservation = 0x1000; + INCLUDE "common.lds" + +__stack_end = ORIGIN(p1ram) + LENGTH(p1ram) - 0x4000; diff --git a/example/example.mk b/example/example.mk index 23928a9..0f2d86e 100644 --- a/example/example.mk +++ b/example/example.mk @@ -437,6 +437,14 @@ GDROM_ISO9660_OBJ = \ example/gdrom_iso9660.elf: LDSCRIPT = $(LIB)/main.lds example/gdrom_iso9660.elf: $(START_OBJ) $(GDROM_ISO9660_OBJ) +GDROM_JVM_BOOT_OBJ = \ + example/gdrom_jvm_boot.o \ + sh7091/serial.o + +example/gdrom_jvm_boot.elf: LDSCRIPT = $(LIB)/alt.lds +example/gdrom_jvm_boot.elf: $(START_OBJ) $(GDROM_JVM_BOOT_OBJ) + + AICA_OBJ = \ example/aica.o \ sh7091/serial.o \ diff --git a/example/gdrom_jvm_boot.cpp b/example/gdrom_jvm_boot.cpp new file mode 100644 index 0000000..ac335b6 --- /dev/null +++ b/example/gdrom_jvm_boot.cpp @@ -0,0 +1,201 @@ +#include + +#include "memorymap.hpp" +#include "systembus.hpp" +#include "sh7091/serial.hpp" +#include "gdrom/gdrom.hpp" +#include "gdrom/gdrom_bits.hpp" +#include "gdrom/command_packet_format.hpp" +#include "gdrom/toc.hpp" + +#include "iso9660/primary_volume_descriptor.hpp" +#include "iso9660/directory_record.hpp" + +void pio_data(const uint8_t * data) +{ + while ((gdrom::status::bsy(gdrom_if.status) | gdrom::status::drq(gdrom_if.status)) != 0); + + gdrom_if.features = gdrom::features::dma::disable; + gdrom_if.drive_select = gdrom::drive_select::drive_select + | gdrom::drive_select::lun(0); + + gdrom_if.command = gdrom::command::code::packet_command; + while (gdrom::status::drq(gdrom_if.status) == 0); + + const uint16_t * buf = reinterpret_cast(&data[0]); + for (int i = 0; i < 6; i++) { + gdrom_if.data = buf[i]; + } + + while (gdrom::status::bsy(gdrom_if.status) != 0); +} + +void read_data(uint16_t * buf, const uint32_t length) +{ + serial::string("read_data drq interrupt_reason: "); + serial::integer(gdrom::status::drq(gdrom_if.status), ' '); + serial::integer(gdrom_if.interrupt_reason); + for (uint32_t i = 0; i < (length / 2); i++) { + buf[i] = gdrom_if.data; + } +} + +uint32_t toc__get_data_track_fad() +{ + auto packet = gdrom_command_packet_format::get_toc(0, // single-density + 0x0198 // maximum toc length + ); + serial::string("get_toc\n"); + pio_data(packet._data()); + + serial::string("byte_count: "); + serial::integer(gdrom_if.byte_count()); + uint16_t buf[gdrom_if.byte_count() / 2]; + read_data(buf, gdrom_if.byte_count()); + + serial::string("status: "); + serial::integer(gdrom_if.status); + + auto toc = reinterpret_cast(buf); + for (int i = 0; i < 99; i++) { + if (toc->track[i].fad() == 0xffffff) + break; + serial::string("track "); + serial::integer(i); + serial::integer(toc->track[i].fad()); + } + + // assume track 1 is the correct track + return toc->track[1].fad(); +} + +uint32_t cd_read(uint16_t * buf, + const uint32_t starting_address, + const uint32_t transfer_length) +{ + const uint8_t data_select = 0b0010; // data + const uint8_t expected_data_type = 0b100; // XA mode 2 form 1 + const uint8_t parameter_type = 0b0; // FAD specified + const uint8_t data = (data_select << 4) | (expected_data_type << 1) | (parameter_type << 0); + + auto packet = gdrom_command_packet_format::cd_read(data, + starting_address, + transfer_length); + serial::string("cd_read\n"); + serial::string("starting_address: "); + serial::integer(starting_address); + pio_data(packet._data()); + + uint32_t length = 0; + while ((gdrom::status::drq(gdrom_if.status)) != 0) { + const uint32_t byte_count = gdrom_if.byte_count(); + length += byte_count; + read_data(buf, byte_count); + } + serial::string("status: "); + serial::integer(gdrom_if.status); + + serial::string("read length: "); + serial::integer(length); + return length; +} + +bool dr_is_self_or_parent(const iso9660::directory_record * dr) +{ + if (dr->length_of_file_identifier != 1) + return false; + uint8_t c = dr->file_identifier[0]; + return c == 0 || c == 1; +} + +#define FILE_FLAGS__DIRECTORY 2 + +void walk_directory_record(const iso9660::directory_record * dr) +{ + if (dr_is_self_or_parent(dr)) + return; + + if ((dr->file_flags & FILE_FLAGS__DIRECTORY) == 0) { + serial::string(" [regular file] "); + } else { + serial::string(" [directory] "); + } + + serial::string(" file_identifier: "); + serial::string(dr->file_identifier, dr->length_of_file_identifier); + serial::character('\n'); +} + +void walk_directory(uint16_t * buf, int extent, int num_extents) +{ + auto buf8 = reinterpret_cast(buf); + + while (num_extents > 0) { + cd_read(buf, + extent + 150, // 150? + 1 // one sector + ); + + int offset = 0; + + while (true) { + auto dr = reinterpret_cast(&buf8[offset]); + if (dr->length_of_directory_record == 0) + break; + + walk_directory_record(dr); + + offset += dr->length_of_directory_record; + } + num_extents -= 1; + extent += 1; + } +} + +void main() +{ + //serial::init(0); + + // gdrom unlock undocumented register + g1_if.GDUNLOCK = 0x1fffff; + + // Without this read from system_boot_rom, the read value of + // gdrom_if.status is always 0xff + for(uint32_t i = 0; i < 0x200000 / 4; i++) { + (void)system_boot_rom[i]; + } + + const uint32_t fad = toc__get_data_track_fad(); + serial::character('\n'); + + const uint32_t primary_volume_descriptor = fad + 16; + uint16_t buf[2048 / 2]; + cd_read(buf, + primary_volume_descriptor, + 1 // one sector + ); + serial::character('\n'); + + auto pvd = reinterpret_cast(&buf[0]); + auto root_dr = reinterpret_cast(&pvd->directory_record_for_root_directory[0]); + + serial::string("primary volume descriptor:\n"); + serial::string(" standard_identifier: "); + serial::string(pvd->standard_identifier, 5); + serial::character('\n'); + serial::string(" root directory record:\n"); + serial::string(" location of extent: "); + serial::integer(root_dr->location_of_extent.get()); + serial::string(" data length: "); + serial::integer(root_dr->data_length.get()); + + serial::character('\n'); + + const int extent = root_dr->location_of_extent.get(); + const int data_length = root_dr->data_length.get(); + const int num_extents = data_length >> 11; // division by 2048 + + walk_directory(buf, extent, num_extents); + + while (1); +} diff --git a/ip.mk b/ip.mk index 1b4e3b2..c8559a0 100644 --- a/ip.mk +++ b/ip.mk @@ -10,20 +10,27 @@ IP_OBJ = \ sg_are02.o \ sg_are03.o \ sg_are04.o \ - $(START_OBJ) \ + $(START_OBJ) + +SERIAL_LOAD_OBJ = \ example/serial_transfer.o \ sh7091/serial.o \ serial_load.o \ maple/maple.o \ font/portfolio_6x8/portfolio_6x8.data.o \ crc32.o -#sg_ini.o \ -#aip.o + +GDROM_JVM_BOOT_OBJ = \ + example/gdrom_jvm_boot.o \ + sh7091/serial.o %.o: %.obj $(OBJCOPY) -g \ --rename-section IP=.text.$* \ $< $@ -ip.elf: $(IP_OBJ) +serial_load_ip.elf: $(IP_OBJ) $(SERIAL_LOAD_OBJ) + $(LD) --orphan-handling=error --print-memory-usage -T $(LIB)/ip.lds $^ -o $@ + +gdrom_jvm_boot_ip.elf: $(IP_OBJ) $(GDROM_JVM_BOOT_OBJ) $(LD) --orphan-handling=error --print-memory-usage -T $(LIB)/ip.lds $^ -o $@ diff --git a/tools/ftdi_transfer_alt.sh b/tools/ftdi_transfer_alt.sh new file mode 100644 index 0000000..acf4ba3 --- /dev/null +++ b/tools/ftdi_transfer_alt.sh @@ -0,0 +1,17 @@ +#!/bin/sh + +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +filename="$1" + +if [ -z "$filename" ]; then + echo "usage: ./$0 [filename]" + exit 1 +fi + +set -ex + +${SCRIPT_DIR}/ftdi_transfer \ + write 0xac080000 "$filename" \ + jump 0xac080000 \ + console