New build script
Remove Amalgamator, CompileTool, and old insert.bat. Also fix some path issues with ScriptTool.
This commit is contained in:
parent
fec378462d
commit
61f12d6151
|
@ -1,3 +1,2 @@
|
|||
dotnet build tools/ScriptTool -o bin/ScriptTool
|
||||
dotnet build tools/SymbolTableBuilder -o bin/SymbolTableBuilder
|
||||
dotnet build tools/CompileTool -o bin/CompileTool
|
|
@ -0,0 +1,441 @@
|
|||
#Region Variables
|
||||
$input_rom_file = "bin/m12fresh.gba"
|
||||
$output_rom_file = "bin/m12.gba"
|
||||
$eb_rom_file = "bin/eb.smc"
|
||||
$working_dir = "working"
|
||||
$src_dir = "src"
|
||||
|
||||
$input_c_files =
|
||||
"src/c/ext.c",
|
||||
"src/c/vwf.c"
|
||||
|
||||
$base_c_address = 0x8100000;
|
||||
|
||||
$output_rom_sym_file = [IO.Path]::ChangeExtension($output_rom_file, "sym")
|
||||
|
||||
$scripttool_cmd = "bin/ScriptTool/ScriptTool.dll"
|
||||
$scripttool_args =
|
||||
"-compile",
|
||||
"-main",
|
||||
"-misc",
|
||||
$working_dir,
|
||||
$eb_rom_file,
|
||||
$input_rom_file
|
||||
|
||||
If ($IsWindows) { $asm_cmd = "bin/armips.exe" }
|
||||
ElseIf ($IsLinux) { $asm_cmd = "bin/armips" }
|
||||
Else
|
||||
{
|
||||
Write-Host "TODO: what's the Mac version of this?"
|
||||
Exit -1
|
||||
}
|
||||
|
||||
$symbuilder_cmd = "bin/SymbolTableBuilder/SymbolTableBuilder.dll"
|
||||
|
||||
# armips will be rooted in working_dir for these, so the includes files have an implicit "working/" in front
|
||||
$includes_asm_file = "m12-includes.asm"
|
||||
$includes_sym_file = [IO.Path]::ChangeExtension($includes_asm_file, "sym")
|
||||
|
||||
$gcc_cmd = "arm-none-eabi-gcc"
|
||||
$gcc_args =
|
||||
"-c",
|
||||
"-O3",
|
||||
"-fno-ipa-cp",
|
||||
"-fno-inline",
|
||||
"-march=armv4t",
|
||||
"-mtune=arm7tdmi",
|
||||
"-mthumb",
|
||||
"-ffixed-r12",
|
||||
"-mno-long-calls"
|
||||
|
||||
$ld_cmd = "arm-none-eabi-ld"
|
||||
$combined_obj_file = "src/c/combined.o"
|
||||
$linked_obj_file = "src/c/linked.o"
|
||||
$combine_script = "src/c/combine.ld"
|
||||
$link_script = "src/c/link.ld"
|
||||
$undefine_obj_file = "src/c/ext.o"
|
||||
|
||||
$combine_script_contents =
|
||||
"SECTIONS { .text 0x$($base_c_address.ToString('X')) : { *(.text .rodata) } }"
|
||||
|
||||
$link_script_contents =
|
||||
"SECTIONS { .text 0x$($base_c_address.ToString('X')) : { *(.text .data .rodata) } }"
|
||||
|
||||
$objdump_cmd = "arm-none-eabi-objdump"
|
||||
$compiled_asm_file = "src/m2-compiled.asm"
|
||||
|
||||
# armips will be rooted in src_dir for these, so the includes files have an implicit "working/" in front
|
||||
$hack_asm_file = "m2-hack.asm"
|
||||
$hack_sym_file = [IO.Path]::ChangeExtension($hack_asm_file, "sym")
|
||||
|
||||
$readelf_cmd = "arm-none-eabi-readelf"
|
||||
|
||||
#EndRegion Variables
|
||||
|
||||
#Region Functions
|
||||
class Symbol
|
||||
{
|
||||
[string]$Name
|
||||
[int]$Value
|
||||
[int]$Size
|
||||
[bool]$IsLocal
|
||||
[bool]$IsGlobal
|
||||
[bool]$IsWeak
|
||||
[bool]$IsConstructor
|
||||
[bool]$IsWarning
|
||||
[bool]$IsIndirect
|
||||
[bool]$IsDebugging
|
||||
[bool]$IsDynamic
|
||||
[bool]$IsFunction
|
||||
[bool]$IsFile
|
||||
[bool]$IsObject
|
||||
[string]$Section
|
||||
[bool]$IsAbsolute
|
||||
[bool]$IsUndefined
|
||||
}
|
||||
|
||||
class SectionInfo
|
||||
{
|
||||
[string]$Name
|
||||
[int]$Address
|
||||
[int]$Offset
|
||||
[int]$Size
|
||||
}
|
||||
|
||||
Function Get-Symbols ([string]$obj_file)
|
||||
{
|
||||
return & $objdump_cmd -t $obj_file | ForEach-Object { New-Symbol $_ } | Where-Object { $_ -ne $null }
|
||||
}
|
||||
|
||||
# Converts a symbol from objdump's string representation to a rich object representation
|
||||
$symbol_regex = "(?'value'[0-9a-fA-F]{8})\s(?'flags'.{7})\s(?'section'\S+)\s+(?'size'[0-9a-fA-F]{8})\s(?'name'\S+)"
|
||||
Function New-Symbol([string]$symbol_string)
|
||||
{
|
||||
if ($symbol_string -match $symbol_regex)
|
||||
{
|
||||
$symbol = [Symbol]::new()
|
||||
$symbol.Name = $Matches.name
|
||||
$symbol.Value = [int]::Parse($Matches.value, [System.Globalization.NumberStyles]::HexNumber)
|
||||
$symbol.Size = [int]::Parse($Matches.size, [System.Globalization.NumberStyles]::HexNumber)
|
||||
$symbol.Section = $Matches.section
|
||||
$symbol.IsAbsolute = $symbol.Section -eq "*ABS*"
|
||||
$symbol.IsUndefined = $symbol.Section -eq "*UND*"
|
||||
|
||||
$flags = $Matches.flags
|
||||
$symbol.IsLocal = $flags.Contains("l") -or $flags.Contains("!")
|
||||
$symbol.IsGlobal = $flags.Contains("g") -or $flags.Contains("!")
|
||||
$symbol.IsWeak = $flags.Contains("w")
|
||||
$symbol.IsConstructor = $flags.Contains("C")
|
||||
$symbol.IsWarning = $flags.Contains("W")
|
||||
$symbol.IsIndirect = $flags.Contains("I")
|
||||
$symbol.IsDebugging = $flags.Contains("d")
|
||||
$symbol.IsDynamic = $flags.Contains("D")
|
||||
$symbol.IsFunction = $flags.Contains("F")
|
||||
$symbol.IsFile = $flags.Contains("f")
|
||||
$symbol.IsObject = $flags.Contains("O")
|
||||
|
||||
return $symbol
|
||||
}
|
||||
else
|
||||
{
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
Function Get-SymfileSymbols([string]$symbol_file)
|
||||
{
|
||||
return Get-Content $symbol_file | ForEach-Object { New-SymfileSymbol $_ } | Where-Object { $_ -ne $null }
|
||||
}
|
||||
|
||||
$symfile_symbol_regex = "(?'value'[0-9a-fA-F]{8})\s+(?'name'(?>\.|@@|[a-zA-Z0-9_])[a-zA-Z0-9_]+):{0,1}(?'size'[0-9a-fA-F]+){0,1}"
|
||||
Function New-SymfileSymbol([string]$symbol_string)
|
||||
{
|
||||
if ($symbol_string -match $symfile_symbol_regex)
|
||||
{
|
||||
$symbol = [Symbol]::new()
|
||||
$symbol.Name = $Matches.name
|
||||
$symbol.Value = [int]::Parse($Matches.value, [System.Globalization.NumberStyles]::HexNumber)
|
||||
|
||||
if ($null -ne $Matches.size)
|
||||
{
|
||||
$symbol.Size = [int]::Parse($Matches.size, [System.Globalization.NumberStyles]::HexNumber)
|
||||
}
|
||||
else
|
||||
{
|
||||
$symbol.Size = 0
|
||||
}
|
||||
|
||||
$symbol.IsLocal = $symbol.Name.StartsWith("@@")
|
||||
$symbol.IsGlobal = -not $symbol.Name.StartsWith(".") -and -not $symbol.IsLocal
|
||||
|
||||
return $symbol
|
||||
}
|
||||
else
|
||||
{
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function Get-SectionInfo([string]$object_file)
|
||||
{
|
||||
$hash = @{}
|
||||
& $readelf_cmd -S $object_file | ForEach-Object {
|
||||
$section = New-Section $_
|
||||
if ($null -ne $section)
|
||||
{
|
||||
$hash[$section.Name] = $section
|
||||
}
|
||||
}
|
||||
return $hash
|
||||
}
|
||||
|
||||
$section_regex = "\s?\[\s?\d+]\s(?'name'\S+)\s+\S+\s+(?'address'[0-9a-fA-F]+)\s(?'offset'[0-9a-fA-F]+)\s(?'size'[0-9a-fA-F]+)"
|
||||
function New-Section([string]$section_string)
|
||||
{
|
||||
if ($section_string -match $section_regex)
|
||||
{
|
||||
$section = [SectionInfo]::new()
|
||||
$section.Name = $Matches.name
|
||||
$section.Address = [int]::Parse($Matches.address, [System.Globalization.NumberStyles]::HexNumber)
|
||||
$section.Offset = [int]::Parse($Matches.offset, [System.Globalization.NumberStyles]::HexNumber)
|
||||
$section.Size = [int]::Parse($Matches.size, [System.Globalization.NumberStyles]::HexNumber)
|
||||
|
||||
return $section
|
||||
}
|
||||
else
|
||||
{
|
||||
return $null
|
||||
}
|
||||
}
|
||||
#EndRegion Functions
|
||||
|
||||
<#
|
||||
This is a complicated build script that does complicated things, but it's
|
||||
that way for a reason.
|
||||
|
||||
- We want to use ASM and C code files simultaneously
|
||||
- The ASM code defines symbols that we want to reference from C
|
||||
- The C code defines symbols that we want to reference from ASM
|
||||
- The game text defines symbols that we want to reference from C
|
||||
|
||||
The ASM and C code therefore depend on each other. The way around this catch-22
|
||||
is to separate the compiling and linking stages of the C code.
|
||||
|
||||
1) Compile the game text
|
||||
|
||||
Inputs:
|
||||
- Text/script files
|
||||
|
||||
Outputs:
|
||||
- BIN files containing compiled text data
|
||||
- ASM files that relocate text pointers (m12-includes.asm)
|
||||
|
||||
2) Assemble output from step 1
|
||||
|
||||
Inputs:
|
||||
- Output from step 1
|
||||
- Fresh M12 ROM file
|
||||
|
||||
Outputs:
|
||||
- ROM file with text inserted and repointed
|
||||
- m12-includes.sym file containing generated symbols (e.g. individual strings from m12-other.json)
|
||||
|
||||
3) Compile C code
|
||||
|
||||
Inputs:
|
||||
- C files
|
||||
|
||||
Outputs:
|
||||
- O files (one for each C file)
|
||||
|
||||
Remarks:
|
||||
- All symbols not defined in the C code itself must be marked extern. We will link it
|
||||
in a later step. This includes the string symbols from step 2.
|
||||
- Due to an assembler limitation, extern symbols cannot contain capital letters.
|
||||
- There's a weird quirk with the linker that requires extra care when using external
|
||||
functions. You need to declare them as extern AND implement them using the ((naked))
|
||||
attribute, e.g.
|
||||
|
||||
(in a header file) extern int m2_drawwindow(WINDOW* window);
|
||||
(in a code file) int __attribute__((naked)) m2_drawwindow(WINDOW* window) {}
|
||||
|
||||
See: http://stackoverflow.com/a/43283331/1188632
|
||||
|
||||
This will cause a duplicate definition of the function symbol, since it's *really*
|
||||
defined in the ASM files somewhere, but we're redefining it again in C. So we also need
|
||||
to "undefine" these symbols later on when linking.
|
||||
|
||||
To make it a bit easier to do all that, place all such implementations in ext.c.
|
||||
|
||||
4) First link stage
|
||||
|
||||
Inputs:
|
||||
- O files from step 3
|
||||
- Base address
|
||||
|
||||
Outputs:
|
||||
- Single O file positioned to the base address
|
||||
- m2-compiled.asm, containing C symbol definitions
|
||||
|
||||
Remarks:
|
||||
- This is an incremental link; there will still be undefined symbols.
|
||||
- However, with this combined O file, the code layout will not change and we can now
|
||||
define symbols from the C code to be used in the ASM code.
|
||||
- The symbols will be passed to the assembler next, so export them as an ASM file
|
||||
with one ".definelabel" entry for each defined symbol. They need to be halfword-aligned.
|
||||
This file is called "m2-compiled.asm" by default and is referenced by m2-hack.asm.
|
||||
- Exclude the symbols defined in ext.c from m2-compiled.asm.
|
||||
|
||||
5) Assemble ASM code
|
||||
|
||||
Inputs:
|
||||
- m2-hack.asm
|
||||
- m2-compiled.asm
|
||||
- All other ASM and data files from src/ (but not the generated ones from working/)
|
||||
- M12 ROM file from step 2
|
||||
|
||||
Outputs:
|
||||
- M12 ROM file with all ASM code and data included
|
||||
- m2-hack.sym with all symbols defined thusfar
|
||||
|
||||
6) Generate final linker script
|
||||
|
||||
Inputs:
|
||||
- Base address (same as step 4)
|
||||
- m2-hack.sym (from step 5)
|
||||
- m12-includes.sym (from step 2)
|
||||
|
||||
Outputs:
|
||||
- Linker script file
|
||||
|
||||
Remarks:
|
||||
- The linker script must define each symbol that's still undefined; if everything is
|
||||
happy at this point, then they should all be contained within the two input SYM files.
|
||||
|
||||
7) Final link stage
|
||||
|
||||
Inputs:
|
||||
- O file from step 4
|
||||
- Linker script from step 6
|
||||
|
||||
Outputs:
|
||||
- Single O file with all symbols defined
|
||||
|
||||
8) Copy code to ROM
|
||||
|
||||
Inputs:
|
||||
- O file from step 7
|
||||
- M12 ROM file from step 5
|
||||
|
||||
Outputs:
|
||||
- M12 ROM file with all code and data included
|
||||
|
||||
9) Build final symbol file
|
||||
|
||||
Inputs:
|
||||
- m2-hack.sym
|
||||
- m12-includes.sym
|
||||
|
||||
Outputs:
|
||||
- m12.sym
|
||||
|
||||
Remarks:
|
||||
- This is a merged symbol file for debugging convenience.
|
||||
- The assembler generates a dummy .byt symbol at the base address; remove it.
|
||||
- Use SymbolTableBuilder to do the merge, plus remove the undesirable namespaces that
|
||||
the assembler inserts.
|
||||
#>
|
||||
|
||||
# ------------------------- COMPILE GAME TEXT -----------------------
|
||||
|
||||
"Copying $input_rom_file to $output_rom_file..."
|
||||
Copy-Item -Path $input_rom_file -Destination $output_rom_file
|
||||
|
||||
"Compiling game text..."
|
||||
& dotnet $scripttool_cmd $scripttool_args
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
|
||||
# ------------------------ ASSEMBLE GAME TEXT -----------------------
|
||||
|
||||
"Assembling game text..."
|
||||
& $asm_cmd -root $working_dir -sym $includes_sym_file $includes_asm_file
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
|
||||
# ----------------------------- COMPILE C ---------------------------
|
||||
|
||||
$obj_files = @()
|
||||
|
||||
# Invoke gcc on each file individually so that we can specify the output file
|
||||
foreach ($input_c_file in $input_c_files)
|
||||
{
|
||||
$obj_file = [IO.Path]::ChangeExtension($input_c_file, "o")
|
||||
$obj_files += $obj_file
|
||||
|
||||
"Compiling $input_c_file..."
|
||||
& $gcc_cmd $gcc_args -o $obj_file $input_c_file
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
}
|
||||
|
||||
# ----------------------------- 1ST LINK ----------------------------
|
||||
|
||||
"Writing $combine_script..."
|
||||
$combine_script_contents | Out-File -FilePath $combine_script
|
||||
|
||||
"Linking $obj_files..."
|
||||
& $ld_cmd -i -T $combine_script -o $combined_obj_file $obj_files
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
|
||||
# Export all C symbols to m2-compiled.asm, except for those in ext.c
|
||||
"Reading symbols from $combined_obj_file..."
|
||||
$combined_symbols = Get-Symbols $combined_obj_file
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
|
||||
"Reading symbols from $undefine_obj_file..."
|
||||
$ext_symbols = Get-Symbols $undefine_obj_file
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
|
||||
"Exporting C symbols to $compiled_asm_file..."
|
||||
$ext_symbols_names = $ext_symbols | Where-Object { $_.IsFunction -and $_.IsGlobal -and (-not $_.IsUndefined) } | ForEach-Object { $_.Name }
|
||||
$exported_symbols = $combined_symbols | Where-Object { $_.IsFunction -and $_.IsGlobal -and (-not $_.IsUndefined) -and ($ext_symbols_names -notcontains $_.Name) }
|
||||
$exported_symbols | Sort-Object -Property Name | ForEach-Object { ".definelabel $($_.Name),0x$($_.Value.ToString("X"))" } | Set-Content -Path $compiled_asm_file
|
||||
|
||||
# ------------------------ ASSEMBLE HACK CODE -----------------------
|
||||
|
||||
"Assembling $hack_asm_file..."
|
||||
& $asm_cmd -root $src_dir -sym $hack_sym_file $hack_asm_file
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
|
||||
# ------------------- GENERATE FINAL LINKER SCRIPT ------------------
|
||||
|
||||
"Writing $link_script..."
|
||||
$hack_symbols = Get-SymfileSymbols "$([IO.Path]::Combine($src_dir, $hack_sym_file))"
|
||||
$includes_symbols = Get-SymfileSymbols "$([IO.Path]::Combine($working_dir, $includes_sym_file))"
|
||||
$asm_symbols = ($hack_symbols + $includes_symbols) | Where-Object { $_.IsGlobal }
|
||||
Set-Content -Path $link_script -Value $link_script_contents
|
||||
$asm_symbols | ForEach-Object { Add-Content -Path $link_script -Value "$($_.Name) = 0x$($_.Value.ToString("X"));" }
|
||||
|
||||
# ---------------------------- FINAL LINK ---------------------------
|
||||
|
||||
"Linking to $linked_obj_file..."
|
||||
& $ld_cmd -T $link_script -o $linked_obj_file $combined_obj_file
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
|
||||
# -------------------- COPY COMPILED C CODE TO ROM ------------------
|
||||
|
||||
"Copying compiled code to $output_rom_file..."
|
||||
$sections = Get-SectionInfo $linked_obj_file
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
$text_section = $sections[".text"]
|
||||
$linked_bytes = [IO.File]::ReadAllBytes($linked_obj_file)
|
||||
$rom_bytes = [IO.File]::ReadAllBytes($output_rom_file)
|
||||
[System.Array]::Copy($linked_bytes, $text_section.Offset, $rom_bytes, $text_section.Address - 0x8000000, $text_section.Size)
|
||||
[IO.File]::WriteAllBytes($output_rom_file, $rom_bytes)
|
||||
|
||||
# -------------------------- GENERATE SYMBOLS -----------------------
|
||||
|
||||
"Generating $output_rom_sym_file..."
|
||||
& dotnet $symbuilder_cmd $output_rom_sym_file "$([IO.Path]::Combine($src_dir, $hack_sym_file))" "$([IO.Path]::Combine($working_dir, $includes_sym_file))"
|
||||
if ($LASTEXITCODE -ne 0) { exit -1 }
|
||||
|
||||
"Finished"
|
||||
exit 0
|
|
@ -1,22 +0,0 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.26403.0
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Amalgamator", "Amalgamator\Amalgamator.csproj", "{24518872-E9D3-4C09-BE31-A2B52A6634F2}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{24518872-E9D3-4C09-BE31-A2B52A6634F2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{24518872-E9D3-4C09-BE31-A2B52A6634F2}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{24518872-E9D3-4C09-BE31-A2B52A6634F2}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{24518872-E9D3-4C09-BE31-A2B52A6634F2}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -1,66 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||
<PropertyGroup>
|
||||
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||
<ProjectGuid>{24518872-E9D3-4C09-BE31-A2B52A6634F2}</ProjectGuid>
|
||||
<OutputType>Exe</OutputType>
|
||||
<RootNamespace>Amalgamator</RootNamespace>
|
||||
<AssemblyName>Amalgamator</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>bin\Debug\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>bin\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="ELFSharp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=22f480d29a3ced83, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\ELFSharp.1.0.4\lib\net40\ELFSharp.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="FluentCommandLineParser, Version=1.4.3.0, Culture=neutral, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\FluentCommandLineParser.1.4.3\lib\net35\FluentCommandLineParser.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="MiscUtil, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d3c42c4bfacf7596, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\JonSkeet.MiscUtil.0.1\lib\net35-Client\MiscUtil.dll</HintPath>
|
||||
</Reference>
|
||||
<Reference Include="System" />
|
||||
<Reference Include="System.Core" />
|
||||
<Reference Include="System.Xml.Linq" />
|
||||
<Reference Include="System.Data.DataSetExtensions" />
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
<Reference Include="System.Data" />
|
||||
<Reference Include="System.Net.Http" />
|
||||
<Reference Include="System.Xml" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Program.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="App.config" />
|
||||
<None Include="packages.config" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||
<PropertyGroup>
|
||||
<PostBuildEvent>
|
||||
</PostBuildEvent>
|
||||
</PropertyGroup>
|
||||
</Project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8" ?>
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.1" />
|
||||
</startup>
|
||||
</configuration>
|
|
@ -1,331 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using System.IO;
|
||||
using System.Diagnostics;
|
||||
using Fclp;
|
||||
using ELFSharp.ELF;
|
||||
using ELFSharp.ELF.Sections;
|
||||
|
||||
namespace Amalgamator
|
||||
{
|
||||
class Program
|
||||
{
|
||||
const string GccExec = "arm-none-eabi-gcc";
|
||||
const string LdExec = "arm-none-eabi-ld";
|
||||
const string CompiledAsmFile = "m2-compiled.asm";
|
||||
const string ArmipsExec = "armips.exe";
|
||||
const string HackFile = "m2-hack.asm";
|
||||
const string ArmipsSymFile = "armips-symbols.sym";
|
||||
const string IncludesSymFile = "working\\includes-symbols.sym";
|
||||
const string LinkerScript = "linker.ld";
|
||||
const string LinkedObjectFile = "linked.o";
|
||||
|
||||
const string ArmipsSymbolRegex = @"([0-9a-fA-F]{8}) ([^\.@]\S+)";
|
||||
|
||||
static int Main(string[] args)
|
||||
{
|
||||
int exitCode = MainInternal(args);
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
// I'm having Main wrap everything so that it's easier to break on error before the program returns
|
||||
static int MainInternal(string[] args)
|
||||
{
|
||||
var options = GetOptions(args);
|
||||
if (options == null)
|
||||
return 1;
|
||||
|
||||
var functionSymbols = new Dictionary<string, uint>();
|
||||
var undefinedSymbols = new HashSet<string>();
|
||||
var linkerScript = new StringBuilder();
|
||||
|
||||
foreach (string codeFile in options.CodeFiles)
|
||||
{
|
||||
bool success = CompileCodeFile(codeFile);
|
||||
if (!success)
|
||||
{
|
||||
Console.Error.WriteLine($"Error compiling {codeFile}");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// Skip the dummy function stubs from ext.o
|
||||
if (codeFile == "ext.c")
|
||||
continue;
|
||||
|
||||
var elf = ELFReader.Load(GetObjectFileName(codeFile));
|
||||
var symbols = elf.GetSection(".symtab") as SymbolTable<uint>;
|
||||
|
||||
foreach (var symbol in symbols.Entries.Where(
|
||||
s => s.Type == SymbolType.Function && s.Binding.HasFlag(SymbolBinding.Global)))
|
||||
{
|
||||
functionSymbols.Add(symbol.Name, symbol.Value);
|
||||
}
|
||||
|
||||
foreach (var symbol in symbols.Entries.Where(
|
||||
s => s.Type == SymbolType.NotSpecified && s.Binding.HasFlag(SymbolBinding.Global) && s.PointedSectionIndex == 0))
|
||||
{
|
||||
undefinedSymbols.Add(symbol.Name);
|
||||
}
|
||||
}
|
||||
|
||||
GenerateCompiledLabelsFile(options.GetRootFile(CompiledAsmFile),
|
||||
functionSymbols, options.CompiledAddress);
|
||||
|
||||
if (!RunAssembler(options.RootDirectory))
|
||||
return 3;
|
||||
|
||||
linkerScript.AppendLine($"SECTIONS {{ .text 0x{options.CompiledAddress:X} : {{ *(.text .data .rodata) }} }}");
|
||||
|
||||
foreach (var sym in EnumerateArmipsSymbols(options.GetRootFile(ArmipsSymFile))
|
||||
.Concat(EnumerateArmipsSymbols(options.GetRootFile(IncludesSymFile)))
|
||||
.Where(s => undefinedSymbols.Contains(s.Key)))
|
||||
{
|
||||
linkerScript.AppendLine($"{sym.Key} = 0x{sym.Value:X};");
|
||||
}
|
||||
|
||||
File.WriteAllText(LinkerScript, linkerScript.ToString());
|
||||
|
||||
if (!RunLinker(options.RootDirectory, options.CodeFiles.Select(c => GetObjectFileName(c))))
|
||||
return 4;
|
||||
|
||||
byte[] code = GenerateCompiledBinfile();
|
||||
if (code == null)
|
||||
return 5;
|
||||
|
||||
RemoveUnwantedCodeDataSymbol(options.GetRootFile(ArmipsSymFile), options.CompiledAddress);
|
||||
IncludeBinfile(options.GetRootFile(options.RomName), code, options.CompiledAddress);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static Options GetOptions(string[] args)
|
||||
{
|
||||
var options = new Options();
|
||||
var parser = new FluentCommandLineParser();
|
||||
|
||||
parser.Setup<string>('c', "compiled-address")
|
||||
.Callback(i => options.CompiledAddress = (int)new System.ComponentModel.Int32Converter().ConvertFromString(i))
|
||||
.Required();
|
||||
|
||||
parser.Setup<string>('d', "root-directory")
|
||||
.Callback(s => options.RootDirectory = s);
|
||||
|
||||
parser.Setup<string>('r', "rom-file")
|
||||
.Callback(s => options.RomName = s)
|
||||
.Required();
|
||||
|
||||
parser.Setup<List<string>>('i', "input-files")
|
||||
.Callback(s => options.CodeFiles = s)
|
||||
.Required();
|
||||
|
||||
var result = parser.Parse(args);
|
||||
|
||||
if (result.HasErrors)
|
||||
Console.WriteLine(result.ErrorText);
|
||||
|
||||
return result.HasErrors ? null : options;
|
||||
}
|
||||
|
||||
static int ParsePossiblyHexNumber(string str)
|
||||
{
|
||||
return (int)new System.ComponentModel.Int32Converter().ConvertFromString(str);
|
||||
}
|
||||
|
||||
static int RunLocalProcess(string fileName, params string[] args)
|
||||
=> RunProcess(fileName, null, args);
|
||||
|
||||
static int RunProcess(string fileName, string workingDirectory, params string[] args)
|
||||
=> RunProcess(fileName, Process_OutputDataReceived, Process_ErrorDataReceived, workingDirectory, args);
|
||||
|
||||
static int RunProcess(string fileName,
|
||||
DataReceivedEventHandler outputCallback,
|
||||
DataReceivedEventHandler errorCallback,
|
||||
string workingDirectory,
|
||||
params string[] args)
|
||||
{
|
||||
var process = new Process();
|
||||
process.StartInfo.FileName = Path.Combine((workingDirectory ?? ""), fileName);
|
||||
process.StartInfo.Arguments = String.Join(" ", args);
|
||||
if (workingDirectory != null)
|
||||
{
|
||||
process.StartInfo.WorkingDirectory = Path.GetFullPath(workingDirectory);
|
||||
}
|
||||
|
||||
Console.WriteLine($"Executing: {process.StartInfo.FileName} {process.StartInfo.Arguments}");
|
||||
|
||||
process.StartInfo.CreateNoWindow = true;
|
||||
process.StartInfo.UseShellExecute = false;
|
||||
|
||||
process.StartInfo.RedirectStandardError = true;
|
||||
process.StartInfo.RedirectStandardOutput = true;
|
||||
|
||||
if (errorCallback != null)
|
||||
process.ErrorDataReceived += errorCallback;
|
||||
|
||||
if (outputCallback != null)
|
||||
process.OutputDataReceived += outputCallback;
|
||||
|
||||
process.Start();
|
||||
process.BeginErrorReadLine();
|
||||
process.BeginOutputReadLine();
|
||||
process.WaitForExit();
|
||||
|
||||
return process.ExitCode;
|
||||
}
|
||||
|
||||
static int RunProcess(string fileName, out string standardOutput, params string[] args)
|
||||
{
|
||||
var outputBuilder = new StringBuilder();
|
||||
DataReceivedEventHandler outputCallback = (o, e) => outputBuilder.AppendLine(e.Data);
|
||||
|
||||
int exitCode = RunProcess(fileName, outputCallback, null, null, args);
|
||||
standardOutput = outputBuilder.ToString();
|
||||
|
||||
return exitCode;
|
||||
}
|
||||
|
||||
static string GetObjectFileName(string codeFileName)
|
||||
{
|
||||
return Path.GetFileNameWithoutExtension(codeFileName) + ".o";
|
||||
}
|
||||
|
||||
static void Process_OutputDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
Console.Out.WriteLine(e.Data);
|
||||
}
|
||||
|
||||
static void Process_ErrorDataReceived(object sender, DataReceivedEventArgs e)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(e.Data))
|
||||
Console.Error.WriteLine(e.Data);
|
||||
}
|
||||
|
||||
static bool CompileCodeFile(string fileName)
|
||||
{
|
||||
string objectName = GetObjectFileName(fileName);
|
||||
|
||||
return RunLocalProcess(GccExec,
|
||||
"-o", objectName,
|
||||
"-c",
|
||||
"-O3",
|
||||
"-fno-ipa-cp",
|
||||
"-fno-inline",
|
||||
fileName,
|
||||
"-march=armv4t",
|
||||
"-mtune=arm7tdmi",
|
||||
"-mthumb",
|
||||
"-ffixed-r12",
|
||||
"-mno-long-calls") == 0;
|
||||
}
|
||||
|
||||
static IEnumerable<KeyValuePair<string, int>> ParseAddressSymbolMatches(IEnumerable<Match> matches)
|
||||
{
|
||||
var symbols = new Dictionary<string, int>();
|
||||
|
||||
foreach (var match in matches)
|
||||
{
|
||||
// There should be exactly three groups (one for the full match + 2 captured groups)
|
||||
if (match.Groups.Count != 3)
|
||||
continue;
|
||||
|
||||
string addressString = match.Groups[1].Value;
|
||||
string symbolName = match.Groups[2].Value;
|
||||
int address = int.Parse(addressString, System.Globalization.NumberStyles.HexNumber);
|
||||
|
||||
symbols.Add(symbolName, address);
|
||||
}
|
||||
|
||||
return symbols;
|
||||
}
|
||||
|
||||
static IEnumerable<KeyValuePair<string, int>> EnumerateArmipsSymbols(string armipsSymbolsFile)
|
||||
{
|
||||
string armipsSymbols = File.ReadAllText(armipsSymbolsFile);
|
||||
|
||||
var regex = new Regex(ArmipsSymbolRegex);
|
||||
var matches = regex.Matches(armipsSymbols).Cast<Match>();
|
||||
return ParseAddressSymbolMatches(matches);
|
||||
}
|
||||
|
||||
static void GenerateCompiledLabelsFile(string fileName,
|
||||
IEnumerable<KeyValuePair<string, uint>> functionSymbols, int compiledAddress)
|
||||
{
|
||||
using (var writer = File.CreateText(fileName))
|
||||
{
|
||||
// Need to clear the 1 bit because armips requires aligned label addresses
|
||||
foreach (var kv in functionSymbols)
|
||||
writer.WriteLine($".definelabel {kv.Key},0x{(kv.Value & ~1) + compiledAddress:X}");
|
||||
}
|
||||
}
|
||||
|
||||
static bool RunAssembler(string rootDirectory)
|
||||
{
|
||||
return RunProcess(ArmipsExec, rootDirectory, HackFile, "-sym", ArmipsSymFile) == 0;
|
||||
}
|
||||
|
||||
static bool RunLinker(string rootDirectory, IEnumerable<string> objectFiles)
|
||||
{
|
||||
return RunLocalProcess(LdExec,
|
||||
"-o", LinkedObjectFile,
|
||||
String.Join(" ", objectFiles),
|
||||
"-T", LinkerScript) == 0;
|
||||
}
|
||||
|
||||
static byte[] GenerateCompiledBinfile()
|
||||
{
|
||||
var code = ExtractObjectSection(LinkedObjectFile, ".text");
|
||||
return code;
|
||||
}
|
||||
|
||||
static byte[] ExtractObjectSection(string objectFile, string sectionName)
|
||||
{
|
||||
var elf = ELFReader.Load(objectFile);
|
||||
var section = elf.GetSection(sectionName);
|
||||
return section.GetContents();
|
||||
}
|
||||
|
||||
static void RemoveUnwantedCodeDataSymbol(string symbolFile, int compiledAddress)
|
||||
{
|
||||
var symbols = File.ReadAllLines(symbolFile).ToList();
|
||||
|
||||
int unwantedIndex = symbols.FindIndex(l =>
|
||||
l.StartsWith(compiledAddress.ToString("X8")) &&
|
||||
l.Substring(9, 5) == ".byt:");
|
||||
|
||||
if (unwantedIndex >= 0)
|
||||
symbols.RemoveAt(unwantedIndex);
|
||||
|
||||
File.WriteAllLines(symbolFile, symbols.ToArray());
|
||||
}
|
||||
|
||||
static void IncludeBinfile(string outputFile, byte[] data, int compiledAddress)
|
||||
{
|
||||
byte[] output = File.ReadAllBytes(outputFile);
|
||||
Array.Copy(data, 0, output, compiledAddress & 0x1FFFFFF, data.Length);
|
||||
File.WriteAllBytes(outputFile, output);
|
||||
}
|
||||
}
|
||||
|
||||
class Options
|
||||
{
|
||||
public int CompiledAddress { get; set; }
|
||||
public string RootDirectory { get; set; }
|
||||
public string RomName { get; set; }
|
||||
public List<string> CodeFiles { get; set; }
|
||||
|
||||
public string GetRootFile(string fileName)
|
||||
{
|
||||
return Path.Combine(Path.GetFullPath(RootDirectory), fileName);
|
||||
}
|
||||
|
||||
public string GetQuotedRootFile(string fileName)
|
||||
{
|
||||
return "\"" + GetRootFile(fileName) + "\"";
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Amalgamator")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Amalgamator")]
|
||||
[assembly: AssemblyCopyright("Copyright © 2017")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("24518872-e9d3-4c09-be31-a2b52a6634f2")]
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<packages>
|
||||
<package id="ELFSharp" version="1.0.4" targetFramework="net461" />
|
||||
<package id="FluentCommandLineParser" version="1.4.3" targetFramework="net461" />
|
||||
<package id="JonSkeet.MiscUtil" version="0.1" targetFramework="net461" />
|
||||
</packages>
|
27
insert.bat
27
insert.bat
|
@ -1,27 +0,0 @@
|
|||
@echo off
|
||||
|
||||
echo Copying fresh ROM...
|
||||
copy /Y m12fresh.gba m12.gba
|
||||
|
||||
:: Compile text files
|
||||
echo Compiling text files...
|
||||
pushd ScriptTool\ScriptTool\bin\Debug
|
||||
ScriptTool.exe -compile -main -misc "..\..\..\..\working" "..\..\..\..\eb.smc" "..\..\..\..\m12fresh.gba"
|
||||
popd
|
||||
|
||||
:: Assemble includes
|
||||
echo Assembling includes...
|
||||
pushd working
|
||||
..\armips.exe m12-includes.asm -sym includes-symbols.sym
|
||||
popd
|
||||
|
||||
:: Compile all C and ASM code
|
||||
echo Compiling and assembling...
|
||||
pushd compiled
|
||||
Amalgamator\Amalgamator\bin\Debug\Amalgamator.exe -r m12.gba -c 0x8100000 -d "../" -i vwf.c ext.c
|
||||
popd
|
||||
if errorlevel 1 (pause && goto :eof)
|
||||
|
||||
SymbolTableBuilder\SymbolTableBuilder\bin\Debug\symbols.exe m12.sym armips-symbols.sym working/includes-symbols.sym
|
||||
|
||||
echo Success!
|
|
@ -1,5 +1,5 @@
|
|||
.gba
|
||||
.open "m12.gba",0x8000000
|
||||
.open "../bin/m12.gba",0x8000000
|
||||
|
||||
//==============================================================================
|
||||
// Relocation hacks
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>netcoreapp3.0</TargetFramework>
|
||||
</PropertyGroup>
|
||||
|
||||
</Project>
|
|
@ -1,12 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace CompileTool
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello World!");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,10 +1,8 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 15
|
||||
VisualStudioVersion = 15.0.28307.168
|
||||
# Visual Studio Version 16
|
||||
VisualStudioVersion = 16.0.28407.52
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CompileTool", "CompileTool\CompileTool.csproj", "{44399E43-DE61-41ED-85AE-5F3A9DA15970}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ScriptTool", "ScriptTool\ScriptTool.csproj", "{29AB41A8-6405-4C4B-A374-BF1BD7AF1A27}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "SymbolTableBuilder", "SymbolTableBuilder\SymbolTableBuilder.csproj", "{2E0E2F98-4EB7-48C7-968D-1BEDCADA37F2}"
|
||||
|
@ -17,10 +15,6 @@ Global
|
|||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{44399E43-DE61-41ED-85AE-5F3A9DA15970}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{44399E43-DE61-41ED-85AE-5F3A9DA15970}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{44399E43-DE61-41ED-85AE-5F3A9DA15970}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{44399E43-DE61-41ED-85AE-5F3A9DA15970}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{29AB41A8-6405-4C4B-A374-BF1BD7AF1A27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{29AB41A8-6405-4C4B-A374-BF1BD7AF1A27}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{29AB41A8-6405-4C4B-A374-BF1BD7AF1A27}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
|
||||
namespace ScriptTool
|
||||
{
|
||||
internal static class Asset
|
||||
{
|
||||
public static readonly string AssetPath;
|
||||
|
||||
static Asset()
|
||||
{
|
||||
AssetPath = AppDomain.CurrentDomain.BaseDirectory;
|
||||
}
|
||||
|
||||
private static string GetFullPath(string path)
|
||||
=> Path.Combine(AssetPath, path);
|
||||
|
||||
public static string ReadAllText(string path)
|
||||
=> File.ReadAllText(GetFullPath(path));
|
||||
|
||||
public static byte[] ReadAllBytes(string path)
|
||||
=> File.ReadAllBytes(GetFullPath(path));
|
||||
}
|
||||
}
|
|
@ -20,8 +20,8 @@ namespace ScriptTool
|
|||
|
||||
static Compiler()
|
||||
{
|
||||
byte[] widths = File.ReadAllBytes("m2-widths-main.bin");
|
||||
byte[] saturnWidths = File.ReadAllBytes("m2-widths-saturn.bin");
|
||||
byte[] widths = Asset.ReadAllBytes("m2-widths-main.bin");
|
||||
byte[] saturnWidths = Asset.ReadAllBytes("m2-widths-saturn.bin");
|
||||
virtualWidths = new int[widths.Length / 2];
|
||||
renderWidths = new int[widths.Length / 2];
|
||||
virtualWidthsSaturn = new int[saturnWidths.Length / 2];
|
||||
|
|
|
@ -36,7 +36,7 @@ namespace ScriptTool
|
|||
|
||||
// Load codes
|
||||
Codes = JsonConvert.DeserializeObject<List<EbControlCode>>(
|
||||
File.ReadAllText("eb-codelist.json"));
|
||||
Asset.ReadAllText("eb-codelist.json"));
|
||||
}
|
||||
|
||||
public bool IsMatch(byte[] rom, int address)
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace ScriptTool
|
|||
static M12ControlCode()
|
||||
{
|
||||
Codes = JsonConvert.DeserializeObject<List<M12ControlCode>>(
|
||||
File.ReadAllText("m12-codelist.json"));
|
||||
Asset.ReadAllText("m12-codelist.json"));
|
||||
}
|
||||
|
||||
public bool IsMatch(byte[] rom, int address)
|
||||
|
|
|
@ -39,8 +39,8 @@ namespace ScriptTool
|
|||
return -1;
|
||||
}
|
||||
|
||||
m12CharLookup = JsonConvert.DeserializeObject<Dictionary<byte, string>>(File.ReadAllText("m12-char-lookup.json"));
|
||||
ebCharLookup = JsonConvert.DeserializeObject<Dictionary<byte, string>>(File.ReadAllText("eb-char-lookup.json"));
|
||||
m12CharLookup = JsonConvert.DeserializeObject<Dictionary<byte, string>>(Asset.ReadAllText("m12-char-lookup.json"));
|
||||
ebCharLookup = JsonConvert.DeserializeObject<Dictionary<byte, string>>(Asset.ReadAllText("eb-char-lookup.json"));
|
||||
|
||||
if (options.Command == CommandType.Decompile)
|
||||
{
|
||||
|
@ -74,7 +74,7 @@ namespace ScriptTool
|
|||
using (IncludeFile = File.CreateText(Path.Combine(options.WorkingDirectory, "m12-includes.asm")))
|
||||
{
|
||||
IncludeFile.WriteLine(".gba");
|
||||
IncludeFile.WriteLine(".open \"../m12.gba\",0x8000000");
|
||||
IncludeFile.WriteLine(".open \"../bin/m12.gba\",0x8000000");
|
||||
|
||||
// Compile main string tables
|
||||
if (options.DoMainText)
|
||||
|
|
Loading…
Reference in New Issue