lua metaprogram adjustments

This commit is contained in:
ed
2026-07-06 19:13:53 -04:00
parent b29fc7dc02
commit c293e35cb4
4 changed files with 518 additions and 674 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
// Auto-generated by gen_atom_offsets.lua — DO NOT EDIT // Auto-generated by tape_atom_offset_gen.meta.lua — DO NOT EDIT
// Source: C:\projects\Pikuma\ps1\code\duffle\lottes_tape.h // Source: C:\projects\Pikuma\ps1\code\duffle\lottes_tape.h
#pragma once #pragma once
+1 -1
View File
@@ -1,4 +1,4 @@
// Auto-generated by gen_atom_offsets.lua — DO NOT EDIT // Auto-generated by tape_atom_offset_gen.meta.lua — DO NOT EDIT
// Source: C:\projects\Pikuma\ps1\code\gte_hello\hello_gte_tape.c // Source: C:\projects\Pikuma\ps1\code\gte_hello\hello_gte_tape.c
#pragma once #pragma once
+107 -107
View File
@@ -7,123 +7,123 @@ Converts a raw binary file to PlayStation 1 (PS-X) executable format.
]] ]]
function file_size(filename) function file_size(filename)
local file = io.open(filename, "rb") local file = io.open(filename, "rb")
if not file then return nil end if not file then return nil end
local size = file:seek("end") local size = file:seek("end")
file:close() file:close()
return size return size
end end
function main(args) function main(args)
if #args ~= 2 then if #args ~= 2 then
io.stderr:write(usage) io.stderr:write(usage)
os.exit(1) os.exit(1)
end end
-- print(string.format("Input file: %s", args[1])) -- print(string.format("Input file: %s", args[1]))
-- print(string.format("Output file: %s", args[2])) -- print(string.format("Output file: %s", args[2]))
-- PS1 executables have a maximum size limit of 2MB -- PS1 executables have a maximum size limit of 2MB
local max_size = 0x200000 local max_size = 0x200000
-- print(string.format("\nChecking input file size (max: %d bytes)...", max_size)) -- print(string.format("\nChecking input file size (max: %d bytes)...", max_size))
local infile_size = file_size(args[1]) local infile_size = file_size(args[1])
if not infile_size then if not infile_size then
io.stderr:write("Error: Cannot open input file " .. args[1] .. "\n") io.stderr:write("Error: Cannot open input file " .. args[1] .. "\n")
os.exit(1) os.exit(1)
end end
-- print(string.format("Input file size: %d bytes", infile_size)) -- print(string.format("Input file size: %d bytes", infile_size))
if infile_size > max_size then if infile_size > max_size then
io.stderr:write(string.format("Error: Input file %s longer than %d bytes\n", args[1], max_size)) io.stderr:write(string.format("Error: Input file %s longer than %d bytes\n", args[1], max_size))
os.exit(1) os.exit(1)
end end
-- print("\nOpening files...") -- print("\nOpening files...")
local ofile = io.open(args[2], "wb") local ofile = io.open(args[2], "wb")
if not ofile then if not ofile then
io.stderr:write("Error: Cannot open output file " .. args[2] .. "\n") io.stderr:write("Error: Cannot open output file " .. args[2] .. "\n")
os.exit(1) os.exit(1)
end end
local ifile = io.open(args[1], "rb") local ifile = io.open(args[1], "rb")
if not ifile then if not ifile then
io.stderr:write("Error: Cannot open input file " .. args[1] .. "\n") io.stderr:write("Error: Cannot open input file " .. args[1] .. "\n")
os.exit(1) os.exit(1)
end end
-- PS1 executables start with "PS-X EXE" magic string -- PS1 executables start with "PS-X EXE" magic string
-- print("Writing PS-X executable header...") -- print("Writing PS-X executable header...")
ofile:write("PS-X EXE") ofile:write("PS-X EXE")
-- Write entry point address (where the PS1 will jump to start execution) -- Write entry point address (where the PS1 will jump to start execution)
-- 0x80010000 is a standard entry point in PS1 RAM -- 0x80010000 is a standard entry point in PS1 RAM
ofile:seek("set", 0x10) ofile:seek("set", 0x10)
ofile:write(string.pack("<I4", 0x80010000)) ofile:write(string.pack("<I4", 0x80010000))
-- print(" Entry point: 0x80010000") -- print(" Entry point: 0x80010000")
-- Initial GP/R28 register value (Global Pointer for data addressing) -- Initial GP/R28 register value (Global Pointer for data addressing)
-- 0xFFFFFFFF means it will be set by crt0.S startup code -- 0xFFFFFFFF means it will be set by crt0.S startup code
ofile:write(string.pack("<I4", 0xFFFFFFFF)) ofile:write(string.pack("<I4", 0xFFFFFFFF))
-- Destination address in RAM where the executable will be loaded -- Destination address in RAM where the executable will be loaded
ofile:write(string.pack("<I4", 0x80010000)) ofile:write(string.pack("<I4", 0x80010000))
-- print(" Load address: 0x80010000") -- print(" Load address: 0x80010000")
-- Initial stack pointer (SP/R29) and frame pointer (FP/R30) -- Initial stack pointer (SP/R29) and frame pointer (FP/R30)
-- 0x801FFF00 points near the top of the 2MB main RAM -- 0x801FFF00 points near the top of the 2MB main RAM
ofile:seek("set", 0x30) ofile:seek("set", 0x30)
ofile:write(string.pack("<I4", 0x801FFF00)) ofile:write(string.pack("<I4", 0x801FFF00))
-- print(" Stack pointer: 0x801FFF00") -- print(" Stack pointer: 0x801FFF00")
-- PS1 executables have an 0x800 (2048) byte header -- PS1 executables have an 0x800 (2048) byte header
-- Zero fill the rest of the header -- Zero fill the rest of the header
ofile:seek("set", 0x800) ofile:seek("set", 0x800)
-- print(" Header padding complete (2048 bytes)") -- print(" Header padding complete (2048 bytes)")
-- Copy the actual program binary data after the header -- Copy the actual program binary data after the header
-- print("\nCopying program data...") -- print("\nCopying program data...")
local buffer_size = 0x2000 -- 8KB chunks for efficient copying local buffer_size = 0x2000 -- 8KB chunks for efficient copying
local bytes_copied = 0 local bytes_copied = 0
for i = 0, math.ceil(infile_size / buffer_size) - 1 do for i = 0, math.ceil(infile_size / buffer_size) - 1 do
local buffer = ifile:read(buffer_size) local buffer = ifile:read(buffer_size)
if buffer then if buffer then
ofile:write(buffer) ofile:write(buffer)
bytes_copied = bytes_copied + #buffer bytes_copied = bytes_copied + #buffer
-- Show progress every 64KB -- Show progress every 64KB
if bytes_copied % 0x10000 == 0 or bytes_copied == infile_size then if bytes_copied % 0x10000 == 0 or bytes_copied == infile_size then
print(string.format(" Copied %d/%d bytes (%.1f%%)", print(string.format(" Copied %d/%d bytes (%.1f%%)",
bytes_copied, infile_size, (bytes_copied / infile_size) * 100)) bytes_copied, infile_size, (bytes_copied / infile_size) * 100))
end end
end end
end end
-- PS1 executables must be padded to 0x800 (2048) byte boundaries -- PS1 executables must be padded to 0x800 (2048) byte boundaries
print("\nAligning to 2048-byte boundary...") print("\nAligning to 2048-byte boundary...")
local exe_size = ofile:seek() local exe_size = ofile:seek()
if exe_size % 0x800 ~= 0 then if exe_size % 0x800 ~= 0 then
local padding = 0x800 - (exe_size % 0x800) local padding = 0x800 - (exe_size % 0x800)
exe_size = exe_size + padding exe_size = exe_size + padding
ofile:seek("set", exe_size - 1) ofile:seek("set", exe_size - 1)
ofile:write(string.pack("B", 0)) ofile:write(string.pack("B", 0))
print(string.format(" Added %d bytes of padding", padding)) print(string.format(" Added %d bytes of padding", padding))
else else
print(" No padding needed") print(" No padding needed")
end end
-- Write the size of the executable (excluding the 0x800 byte header) -- Write the size of the executable (excluding the 0x800 byte header)
-- This goes at offset 0x1C in the header -- This goes at offset 0x1C in the header
ofile:seek("set", 0x1C) ofile:seek("set", 0x1C)
ofile:write(string.pack("<I4", exe_size - 0x800)) ofile:write(string.pack("<I4", exe_size - 0x800))
-- print(string.format("\nProgram size field set to: %d bytes", exe_size - 0x800)) -- print(string.format("\nProgram size field set to: %d bytes", exe_size - 0x800))
ifile:close() ifile:close()
ofile:close() ofile:close()
-- print(string.format("\nSuccess! PS1 executable created: %s", args[2])) -- print(string.format("\nSuccess! PS1 executable created: %s", args[2]))
print(string.format("Total file size: %d bytes\n", exe_size)) print(string.format("Total file size: %d bytes\n", exe_size))
end end
-- Run main with command line arguments -- Run main with command line arguments
File diff suppressed because it is too large Load Diff