Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 59 additions & 55 deletions internal/assembler/asm6/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package asm6
import (
"fmt"
"io"
"strings"

"github.com/retroenv/retrodisasm/internal/assembler"
"github.com/retroenv/retrodisasm/internal/options"
Expand Down Expand Up @@ -30,9 +31,10 @@ type headerByteWrite struct {
}

type prgBankWrite struct {
address string
bank *program.PRGBank
lastBank bool
address string
bank *program.PRGBank
lastBank bool
firstBank bool
}

type customWrite func() error
Expand Down Expand Up @@ -90,9 +92,10 @@ func (f FileWriter) Write() error {
lastBank := i == len(f.app.PRG)-1
writes = append(writes,
prgBankWrite{
address: fmt.Sprintf("$%04x", f.app.CodeBaseAddress),
bank: bank,
lastBank: lastBank,
address: fmt.Sprintf("$%04x", bank.BaseAddress),
bank: bank,
lastBank: lastBank,
firstBank: i == 0,
},
)
}
Expand Down Expand Up @@ -129,59 +132,61 @@ func (f FileWriter) Write() error {
}

func (f FileWriter) writeBank(w prgBankWrite) error {
if err := f.writeSegment(w.address); err != nil {
return err
bankWriteCloser, err := f.newBankWriter(w.bank.Name)
if err != nil {
return fmt.Errorf("creating bank writer: %w", err)
}
defer func() { _ = bankWriteCloser.Close() }()

if f.options.SplitBanks {
if w.firstBank {
if _, err := fmt.Fprintln(f.mainWriter); err != nil {
return fmt.Errorf("writing newline: %w", err)
}
}
bankFile := bankFilename(f.options.OutputFilename, w.bank.Name)
if _, err := fmt.Fprintf(f.mainWriter, ".include \"%s\"\n", bankFile); err != nil {
return fmt.Errorf("writing include directive: %w", err)
}
}

bankW := writer.New(f.app, bankWriteCloser, writer.Options{
OffsetComments: f.options.OffsetComments,
})

if _, err := fmt.Fprintf(bankWriteCloser, "\n.base %s\n\n", w.address); err != nil {
return fmt.Errorf("writing segment: %w", err)
}
if err := f.writeConstants(w.bank); err != nil {
return err

if err := bankW.OutputAliasMap(w.bank.Constants); err != nil {
return fmt.Errorf("writing constants output alias map: %w", err)
}
if err := f.writeVariables(w.bank); err != nil {
return err
if err := bankW.OutputAliasMap(w.bank.Variables); err != nil {
return fmt.Errorf("writing variables output alias map: %w", err)
}
if err := f.writeCode(w.bank); err != nil {
return err

endIndex := w.bank.LastNonZeroByte(f.options)
if err := bankW.ProcessPRG(w.bank, endIndex); err != nil {
return fmt.Errorf("writing PRG: %w", err)
}

vectorsAddr := w.bank.BaseAddress + uint16(len(w.bank.Offsets)) - 6

if w.lastBank {
if err := f.writeVectors(f.app.Handlers.NMI, f.app.Handlers.Reset, f.app.Handlers.IRQ); err != nil {
if err := f.writeVectorsTo(bankWriteCloser, vectorsAddr, f.app.Handlers.NMI, f.app.Handlers.Reset, f.app.Handlers.IRQ); err != nil {
return err
}
} else {
nmi := fmt.Sprintf("$%04X", w.bank.Vectors[0])
reset := fmt.Sprintf("$%04X", w.bank.Vectors[1])
irq := fmt.Sprintf("$%04X", w.bank.Vectors[2])
if err := f.writeVectors(nmi, reset, irq); err != nil {
if err := f.writeVectorsTo(bankWriteCloser, vectorsAddr, nmi, reset, irq); err != nil {
return err
}
}
return nil
}

// writeSegment writes a segment header to the output.
func (f FileWriter) writeSegment(address string) error {
_, err := fmt.Fprintf(f.mainWriter, "\n.base %s\n\n", address)
if err != nil {
return fmt.Errorf("writing segment: %w", err)
}
return nil
}

// writeConstants writes constant aliases to the output.
func (f FileWriter) writeConstants(bank *program.PRGBank) error {
if err := f.writer.OutputAliasMap(bank.Constants); err != nil {
return fmt.Errorf("writing constants output alias map: %w", err)
}
return nil
}

// writeVariables writes variable aliases to the output.
func (f FileWriter) writeVariables(bank *program.PRGBank) error {
if err := f.writer.OutputAliasMap(bank.Variables); err != nil {
return fmt.Errorf("writing variables output alias map: %w", err)
}
return nil
}

// writeCHR writes the CHR content to the output.
func (f FileWriter) writeCHR() error {
if f.options.ZeroBytes {
Expand All @@ -206,33 +211,32 @@ func (f FileWriter) writeCHR() error {
return nil
}

// writeVectors writes the IRQ vectors.
func (f FileWriter) writeVectors(nmi, reset, irq string) error {
// writeVectorsTo writes the IRQ vectors to the specified writer.
func (f FileWriter) writeVectorsTo(w io.Writer, vectorsAddr uint16, nmi, reset, irq string) error {
if f.options.CodeOnly {
return nil
}

addr := fmt.Sprintf("$%04X", f.app.VectorsStartAddress)
addr := fmt.Sprintf("$%04X", vectorsAddr)

_, err := fmt.Fprintf(f.mainWriter, "\n.pad %s\n", addr)
_, err := fmt.Fprintf(w, "\n.pad %s\n", addr)
if err != nil {
return fmt.Errorf("writing padding: %w", err)
}

if err := f.writeSegment(addr); err != nil {
return err
if _, err := fmt.Fprintf(w, "\n.base %s\n\n", addr); err != nil {
return fmt.Errorf("writing segment: %w", err)
}
if _, err := fmt.Fprintf(f.mainWriter, vectors, nmi, reset, irq); err != nil {
if _, err := fmt.Fprintf(w, vectors, nmi, reset, irq); err != nil {
return fmt.Errorf("writing vectors: %w", err)
}
return nil
}

// writeCode writes the code to the output.
func (f FileWriter) writeCode(bank *program.PRGBank) error {
endIndex := bank.LastNonZeroByte(f.options)
if err := f.writer.ProcessPRG(bank, endIndex); err != nil {
return fmt.Errorf("writing PRG: %w", err)
}
return nil
// bankFilename derives the bank output filename from the main output filename
// and the bank name. Matches the logic in pipeline.generateBankFilename.
func bankFilename(outputFilename, bankName string) string {
base := strings.TrimSuffix(outputFilename, ".asm")
suffix := strings.TrimPrefix(strings.ToLower(bankName), "prg_")
return base + "_" + suffix + ".asm"
}
6 changes: 3 additions & 3 deletions internal/assembler/ca65/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func GenerateMapperConfig(conf Config) (string, error) {
buf.WriteString(memoryConfigPart1)

for _, bank := range conf.App.PRG {
if _, err := fmt.Fprintf(buf, memoryPrgBankTemplate, bank.Name+":", conf.App.CodeBaseAddress, len(bank.Offsets)); err != nil {
if _, err := fmt.Fprintf(buf, memoryPrgBankTemplate, bank.Name+":", bank.BaseAddress, len(bank.Offsets)); err != nil {
return "", fmt.Errorf("writing memory bank line: %w", err)
}
}
Expand All @@ -58,7 +58,7 @@ func GenerateMapperConfig(conf Config) (string, error) {
buf.WriteString(segmentsConfigPart1)

for _, bank := range conf.App.PRG {
if _, err := fmt.Fprintf(buf, segmentsPrgBankTemplate, bank.Name+":", bank.Name, conf.App.CodeBaseAddress); err != nil {
if _, err := fmt.Fprintf(buf, segmentsPrgBankTemplate, bank.Name+":", bank.Name, bank.BaseAddress); err != nil {
return "", fmt.Errorf("writing segment bank line: %w", err)
}
}
Expand All @@ -67,7 +67,7 @@ func GenerateMapperConfig(conf Config) (string, error) {
// For multi-bank ROMs, vectors are included in each bank segment
if len(conf.App.PRG) == 1 {
lastBank := conf.App.PRG[0]
vectorStart := conf.App.CodeBaseAddress + uint16(len(lastBank.Offsets)) - 6
vectorStart := lastBank.BaseAddress + uint16(len(lastBank.Offsets)) - 6
if _, err := fmt.Fprintf(buf, segmentsVectorsTemplate, lastBank.Name, vectorStart); err != nil {
return "", fmt.Errorf("writing vectors segment: %w", err)
}
Expand Down
Loading
Loading