@@ -3,12 +3,15 @@ package m6502
33import (
44 "fmt"
55
6+ "github.com/retroenv/retrodisasm/internal/options"
67 "github.com/retroenv/retrodisasm/internal/program"
78 "github.com/retroenv/retrogolib/arch/cpu/m6502"
89 "github.com/retroenv/retrogolib/arch/system/nes"
910 "github.com/retroenv/retrogolib/log"
1011)
1112
13+ const resetLabel = "Reset"
14+
1215func (ar * Arch6502 ) Initialize () error {
1316 if err := ar .initializeIrqHandlers (); err != nil {
1417 return fmt .Errorf ("initializing IRQ handlers: %w" , err )
@@ -18,80 +21,148 @@ func (ar *Arch6502) Initialize() error {
1821
1922// initializeIrqHandlers reads the 3 IRQ handler addresses and adds them to the addresses to be
2023// followed for execution flow. Multiple handler can point to the same address.
21- // nolint:funlen
2224func (ar * Arch6502 ) initializeIrqHandlers () error {
2325 opts := ar .dis .Options ()
2426 handlers := program.Handlers {
2527 NMI : "0" ,
26- Reset : "Reset" ,
28+ Reset : resetLabel ,
2729 IRQ : "0" ,
2830 }
2931
32+ // In binary mode, skip reading NMI/IRQ vectors from ROM
33+ // as they don't exist in raw binary files
34+ if opts .Binary {
35+ return ar .initializeBinaryMode (opts , handlers )
36+ }
37+
38+ nmi , err := ar .initializeNMIHandler (& handlers )
39+ if err != nil {
40+ return err
41+ }
42+
43+ reset , err := ar .initializeResetHandler (& handlers )
44+ if err != nil {
45+ return err
46+ }
47+
48+ irq , err := ar .initializeIRQHandler (& handlers )
49+ if err != nil {
50+ return err
51+ }
52+
53+ ar .resolveSharedHandlers (& handlers , nmi , reset , irq )
54+ ar .calculateCodeBaseAddress (reset )
55+ ar .queueHandlersToParse (nmi , reset , irq )
56+
57+ ar .dis .SetHandlers (handlers )
58+ return nil
59+ }
60+
61+ func (ar * Arch6502 ) initializeNMIHandler (handlers * program.Handlers ) (uint16 , error ) {
3062 nmi , err := ar .dis .ReadMemoryWord (m6502 .NMIAddress )
3163 if err != nil {
32- return fmt .Errorf ("reading NMI address: %w" , err )
64+ return 0 , fmt .Errorf ("reading NMI address: %w" , err )
3365 }
34- if nmi != 0 {
35- ar .logger .Debug ("NMI handler" , log .Hex ("address" , nmi ))
36- offsetInfo := ar .mapper .OffsetInfo (nmi )
37- if offsetInfo != nil {
38- offsetInfo .Label = "NMI"
39- offsetInfo .SetType (program .CallDestination )
40- }
41- handlers .NMI = "NMI"
66+ if nmi == 0 {
67+ return 0 , nil
4268 }
4369
44- var reset uint16
45- if opts .Binary {
46- reset = uint16 (nes .CodeBaseAddress )
47- } else {
48- reset , err = ar .dis .ReadMemoryWord (m6502 .ResetAddress )
49- if err != nil {
50- return fmt .Errorf ("reading reset address: %w" , err )
51- }
70+ ar .logger .Debug ("NMI handler" , log .Hex ("address" , nmi ))
71+ offsetInfo := ar .mapper .OffsetInfo (nmi )
72+ if offsetInfo != nil {
73+ offsetInfo .Label = "NMI"
74+ offsetInfo .SetType (program .CallDestination )
75+ }
76+ handlers .NMI = "NMI"
77+ return nmi , nil
78+ }
79+
80+ func (ar * Arch6502 ) initializeResetHandler (handlers * program.Handlers ) (uint16 , error ) {
81+ reset , err := ar .dis .ReadMemoryWord (m6502 .ResetAddress )
82+ if err != nil {
83+ return 0 , fmt .Errorf ("reading reset address: %w" , err )
5284 }
5385
5486 ar .logger .Debug ("Reset handler" , log .Hex ("address" , reset ))
5587 offsetInfo := ar .mapper .OffsetInfo (reset )
5688 if offsetInfo != nil {
5789 if offsetInfo .Label != "" {
58- handlers .NMI = "Reset"
90+ handlers .NMI = resetLabel
5991 }
60- offsetInfo .Label = "Reset"
92+ offsetInfo .Label = resetLabel
6193 offsetInfo .SetType (program .CallDestination )
6294 }
95+ return reset , nil
96+ }
6397
98+ func (ar * Arch6502 ) initializeIRQHandler (handlers * program.Handlers ) (uint16 , error ) {
6499 irq , err := ar .dis .ReadMemoryWord (m6502 .IrqAddress )
65100 if err != nil {
66- return fmt .Errorf ("reading IRQ address: %w" , err )
101+ return 0 , fmt .Errorf ("reading IRQ address: %w" , err )
67102 }
68- if irq != 0 {
69- ar .logger .Debug ("IRQ handler" , log .Hex ("address" , irq ))
70- offsetInfo = ar .mapper .OffsetInfo (irq )
71- if offsetInfo != nil {
72- if offsetInfo .Label == "" {
73- offsetInfo .Label = "IRQ"
74- handlers .IRQ = "IRQ"
75- } else {
76- handlers .IRQ = offsetInfo .Label
77- }
78- offsetInfo .SetType (program .CallDestination )
103+ if irq == 0 {
104+ return 0 , nil
105+ }
106+
107+ ar .logger .Debug ("IRQ handler" , log .Hex ("address" , irq ))
108+ offsetInfo := ar .mapper .OffsetInfo (irq )
109+ if offsetInfo != nil {
110+ if offsetInfo .Label == "" {
111+ offsetInfo .Label = "IRQ"
112+ handlers .IRQ = "IRQ"
113+ } else {
114+ handlers .IRQ = offsetInfo .Label
79115 }
116+ offsetInfo .SetType (program .CallDestination )
80117 }
118+ return irq , nil
119+ }
81120
121+ func (ar * Arch6502 ) resolveSharedHandlers (handlers * program.Handlers , nmi , reset , irq uint16 ) {
82122 if nmi == reset {
83123 handlers .NMI = handlers .Reset
84124 }
85125 if irq == reset {
86126 handlers .IRQ = handlers .Reset
87127 }
128+ }
129+
130+ func (ar * Arch6502 ) queueHandlersToParse (nmi , reset , irq uint16 ) {
131+ if nmi != 0 {
132+ ar .dis .AddAddressToParse (nmi , nmi , 0 , nil , false )
133+ }
134+ if reset != 0 {
135+ ar .dis .AddAddressToParse (reset , reset , 0 , nil , false )
136+ }
137+ if irq != 0 {
138+ ar .dis .AddAddressToParse (irq , irq , 0 , nil , false )
139+ }
140+ }
88141
89- ar .calculateCodeBaseAddress (reset )
142+ // initializeBinaryMode sets up handlers for binary mode disassembly.
143+ func (ar * Arch6502 ) initializeBinaryMode (opts options.Disassembler , handlers program.Handlers ) error {
144+ // Use custom base address if specified, otherwise use default NES code base
145+ var reset uint16
146+ if opts .BaseAddress != 0 {
147+ reset = opts .BaseAddress
148+ } else {
149+ reset = uint16 (nes .CodeBaseAddress )
150+ }
151+
152+ ar .logger .Debug ("Binary mode reset handler" , log .Hex ("address" , reset ))
153+
154+ // Set code base address before accessing offsets
155+ ar .dis .SetCodeBaseAddress (reset )
156+ ar .dis .SetVectorsStartAddress (m6502 .InterruptVectorStartAddress )
157+
158+ offsetInfo := ar .mapper .OffsetInfo (reset )
159+ if offsetInfo != nil {
160+ offsetInfo .Label = resetLabel
161+ offsetInfo .SetType (program .CallDestination )
162+ }
90163
91- // add IRQ handlers to be parsed after the code base address has been calculated
92- ar .dis .AddAddressToParse (nmi , nmi , 0 , nil , false )
164+ // Add reset address to parse
93165 ar .dis .AddAddressToParse (reset , reset , 0 , nil , false )
94- ar .dis .AddAddressToParse (irq , irq , 0 , nil , false )
95166
96167 ar .dis .SetHandlers (handlers )
97168 return nil
@@ -103,7 +174,23 @@ func (ar *Arch6502) initializeIrqHandlers() error {
103174// address is calculated. This ensures that jsr instructions will result in the same opcode, as it
104175// is based on the code base address.
105176func (ar * Arch6502 ) calculateCodeBaseAddress (resetHandler uint16 ) {
177+ // Check if user specified a custom base address
178+ opts := ar .dis .Options ()
179+ if opts .BaseAddress != 0 {
180+ // Use custom base address from options
181+ ar .dis .SetCodeBaseAddress (opts .BaseAddress )
182+ ar .dis .SetVectorsStartAddress (m6502 .InterruptVectorStartAddress )
183+ return
184+ }
185+
106186 cart := ar .dis .Cart ()
187+ if cart == nil || len (cart .PRG ) == 0 {
188+ // No cart data (binary mode), use default
189+ ar .dis .SetCodeBaseAddress (0x8000 )
190+ ar .dis .SetVectorsStartAddress (m6502 .InterruptVectorStartAddress )
191+ return
192+ }
193+
107194 halfPrg := len (cart .PRG ) % 0x8000
108195 codeBaseAddress := uint16 (0x8000 + halfPrg )
109196 vectorsStartAddress := uint16 (m6502 .InterruptVectorStartAddress )
0 commit comments