6502.org Forum  Projects  Code  Documents  Tools  Forum
It is currently Tue May 07, 2024 8:55 am

All times are UTC




Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next
Author Message
 Post subject: breakpoints...
PostPosted: Sun Apr 15, 2018 10:57 pm 
Offline

Joined: Mon Nov 11, 2002 6:53 pm
Posts: 79
Location: Seattle
Hi All,

So I've been beavering away on a 6502 clone in verilog and cobbled together a simple assembler. Ideally, I'd like to write an IDE that allows you to put breakpoints in the source a la Visual Studio. While I get that the disassembler 'lies' to you, I wonder what the best way is to execute the instruction that follows the break as you're (effectively) overwriting said instruction.
For instance, if I put a breakpoint at the following instruction (in a compiled binary) that is:

8000: 4c 00 00 jmp $0000

The break instruction would replace the '4c' instruction and would need to store the jump opcode *somewhere* and then execute it. Since I'm writing my own core, single-stepping isn't that much of an issues. Just wondering how people tackle this as you need to preserve the original breakpoint AND the instruction.. I could copy the instruction to a buffer and execute THAT but that seems cumbersome...

-Yvo


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Mon Apr 16, 2018 2:37 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1928
Location: Sacramento, CA, USA
yzoer wrote:
... you need to preserve the original breakpoint AND the instruction.. I could copy the instruction to a buffer and execute THAT but that seems cumbersome...

If you didn't need to preserve the breakpoint, things would be a lot less complicated because your BRK routine could copy the op-code back to its proper place, adjust the return address on the stack and RTI. I think you might be stuck with the cumbersome solution otherwise, unless you have some hardware assistance.

Mike B.


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Mon Apr 16, 2018 6:56 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10799
Location: England
I must be missing something - what does it mean to preserve the original breakpoint?

I think the technique of copying the instruction to a buffer and executing there is a very old and respected one. Whatever you do, for single stepping in software I think you need to distinguish between normal sequential opcodes and those which modify program flow: you need to know where they are going to land. If you just execute them, you'll now be running somewhere else, no longer single stepping.

But it may be that there are two or three different ideas in play here and I haven't managed to distinguish them


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Mon Apr 16, 2018 9:28 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
Quote:
Since I'm writing my own core, single-stepping

Since you're writing your own core you could also add a set of breakpoint registers in hardware that generates an IRQ on an address match.
Since you have access to the program counter all it needs is a line like: if (pc==brkaddress) irq = true; and a way to set the brkaddress. Memory mapped registers is one way to implement it. That way the running code doesn't have to be modified (you can even breakpoint code in ROM), but a set of breakpoint registers is required somewhere.

What can also be helpful for debugging is a history log of the program counter. This can be continuously recorded in a circular buffer until a breakpoint IRQ occurs.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Tue Apr 17, 2018 10:40 pm 
Offline

Joined: Sat Dec 13, 2003 3:37 pm
Posts: 1004
The core doesn't do this, the debug software does this.

When you create the breakpoint, you copy out the original instruction, and store it with the "break point meta data" that you must maintain anyway. You need to meta data to know which break point was hit when you get the BRK interrupt.

After the breakpoint is hit, when you hit "continue", it's up to the debugger to mimic the actual instruction to execute.

So, say for example, you had this:
Code:
0200 LBL:  LDA #0
0202       BEQ LBL1
0204       ...
...
0220 LBL1: ...


To put in the break point, you replace the A9 with BRK (00). When its hit, the handler figures out where it came from, located the meta data, presents the code to debugger, etc.

But, when you "continue" from the debugger, you relocate the instruction to a local work area and add a JMP:
Code:
XXXX LDA #00
XXX2 JMP 0202


That will mimic the instruction being executed, and then continue on, while leaving your break point in place.

The trick here is couple of things. First, you need to know what instruction you're mimicking, so that you can pull out the necessary data for the operand. (i.e. you need to know that the LDA # here has a single byte argument, the 00, so you can copy it in to your mimic instruction buffer), also, if you happen to be stomping on a JSR or branch, you'll need to simulate those instructions. In the JSR case, you need to stuff the stack correctly, and then do the jump. With a branch, you'll need to test the proper bits for the instruction, calculate the proper destination, and then JMP there.

The branch simulation is easy. Consider the above code, with the breakpoint on the BEQ.
Code:
XXXX PLP ; Pull the processor status off the stack, after you made sure it's the proper one captured from the BRK
XXX1 BEQ XXX6
XXX3 JMP 0204
XXX6 JMP 0220 ; calculated from the branch instruction


You need to jump through these hoops. You can't simply replace the BRK with the instruction and continue, as you then lose the breakpoint and have no way of setting it back again.

For single stepping, you just create a "new" temporary break point on the next instruction, and handle it like any other break point. For branches, you'll need to predict where it will go so you can set the BRK properly (not like you don't know...).

So, there's a bit of advanced disassembly and simulation involved in a software debugger.

But this is all done in the debugger software.


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Tue Apr 17, 2018 11:14 pm 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8432
Location: Southern California
Assembly is so fast these days I think it works much better to just insert an added JSR DEBUG (or call it what you like) at the desired location, and re-assemble. I have not used BRK at all since that first 6502 class in 1982.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Wed Apr 18, 2018 2:42 am 
Offline
User avatar

Joined: Sun Jun 30, 2013 10:26 pm
Posts: 1928
Location: Sacramento, CA, USA
I used breakpoints when I was debugging my VTL02 port a few years ago. The code was tangled up pretty tightly, but I probably could have inserted a few JSR DEBUGs into the source and re-assembled without too much risk of breaking any branch instructions. I decided instead to use an Apple ][ emulator on my PC and insert my own breakpoints manually from the ML monitor, armed with a .lst file of the heavily commented source in a neighboring window on my display. It wasn't very "vintage", but it was highly effective.

For true vintage flavor, I suppose I could have dusted off my real Apple //e and made a dot-matrix hard-copy of the listing on fan-fold tractor-feed paper ... I know where the computer and the box of paper are in my attic, but I lost track of my Epson MX-80 many years ago, probably around the same time that I lost my ][+ motherboard with 65c802 :-(

Mike B.


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Wed Apr 18, 2018 5:46 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 672
One problem is if you're trying to replace code at $xxFF right before an I/O page, say an RTS, into JSR DEBUG. That would spill over into unwanted effects. The idea would only safely work for 3-byte instructions.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Wed Apr 18, 2018 7:23 am 
Offline
User avatar

Joined: Fri Aug 30, 2002 1:09 am
Posts: 8432
Location: Southern California
That would indeed be a special situation if you ran code right to the end of a page immediately preceding an I/O page, ending it either with an RTS, JMP, or BRA! It would either be from a lot of attention and work, or an oversight someone got away with by a lot of luck. :o OTOH, if you're referring to putting lots of break points in via JSRs, so many that it could fill the last available page that had dozens of bytes left over, that might be just slightly more realistic.

_________________
http://WilsonMinesCo.com/ lots of 6502 resources
The "second front page" is http://wilsonminesco.com/links.html .
What's an additional VIA among friends, anyhow?


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Wed Apr 18, 2018 3:19 pm 
Offline
User avatar

Joined: Sun Dec 29, 2002 8:56 pm
Posts: 449
Location: Canada
I still think that for in-circuit breakpoints hardware break-pointing is the best. With a little bit of logic both instructions and data could be break-pointed.

For software breakpoints, a software emulation of the system could be used. The 6502's memory system is small enough that a side-buffer containing break-point info for each byte of memory could be set-up.

This kind of thing could be done with hardware too, provided there are enough ram resources available. Simply check a breakpoint bit in the side memory when an address is reached and set an interrupt FF if the bit is set. 9 bit wide memories are common in FPGA's the extra bit could be used as a breakpoint flag. It requires a little bit of additional hardware similar to bank switching to set/clear the breakpoint bits.

_________________
http://www.finitron.ca


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Wed Apr 18, 2018 9:32 pm 
Offline
User avatar

Joined: Thu Jun 23, 2011 2:12 am
Posts: 229
Location: Rancho Cucamonga, California
I don't really see why any kind of emulation is needed for single-stepping in software.

A debugger would have a table of breakpoints, and it keeps track of a "current location" (i.e. the next location to execute). While the debugger runs (i.e. the program that's being debugged is not executing) and allows the user to evaluate memory locations etc., all breakpoints have their original values stored. When the user tells the debugger to execute the program, it first replaces all breakpoints with $00, after it makes a backup of the byte at each breakpoint location. Then it executes RTS or JMP to execute the program. When execution hits a breakpoint, all bytes are restored from the breakpoint table again.

When single-stepping through a program, the debugger just needs to calculate where the NEXT instruction AFTER the current location is, and regard that location as a breakpoint. Then before RTS-ing or JMP-ing to the current location, it does the usual replace-by-00. The single instruction at the "current location" gets executed in the place where it was stored all along, so there's no need for simulation (which would be especially hairy with things like branches). And after the instruction is done, the 6502 executes the BRK instruction that was stored in the following location because it's a breakpoint.

If the instruction at the "current location" is a JSR, a sophisticated debugger can inspect the instruction to make it possible to "jump into" a subroutine vs. "jump over" it. When the instruction is a JMP, it can inspect the target address and set the next breakpoint there. When it's a branch, it can inspect the flags on the stack to determine where execution is going to go. This is not difficult to write. What IS difficult is dealing with self-modifying code or some assembler tricks. Also, an instruction that jumps or branches to itself would be a problem because then the debugger ends up putting the breakpoint at the current location and the instruction doesn't get executed when single-stepping. And of course you can't debug code in ROM that way.

===Jac


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Thu Apr 19, 2018 7:28 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10799
Location: England
> just needs to calculate where the NEXT instruction AFTER the current location is, and regard that location as a breakpoint

In the case of a branch, that's two possibilities. In the case of an RTS, it means looking at the stack, I think?


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Thu Apr 19, 2018 10:50 am 
Offline

Joined: Tue Jul 24, 2012 2:27 am
Posts: 672
If it's paused at the branch instruction, you can check the flags to see which branch will be taken, so only 1 path need be patched.

_________________
WFDis Interactive 6502 Disassembler
AcheronVM: A Reconfigurable 16-bit Virtual CPU for the 6502 Microprocessor


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Thu Apr 19, 2018 11:07 am 
Offline
User avatar

Joined: Thu Dec 11, 2008 1:28 pm
Posts: 10799
Location: England
Oh, of course, it's software, so you can inspect the machine. My head was still in the databus-only monitor technique, which does have to reconstruct and model the machine state.


Top
 Profile  
Reply with quote  
 Post subject: Re: breakpoints...
PostPosted: Fri Apr 20, 2018 4:32 pm 
Offline

Joined: Mon Nov 11, 2002 6:53 pm
Posts: 79
Location: Seattle
Apologies for the late reply. Just read over all the replies (thanks for that!) and I'll clarify some of it. Single-stepping is considered easy as it's a single bit that triggers an IRQ after every instruction. In order to avoid single stepping your single-step routine, I could only allow that to happen when it's outside of an interrupt (i.e. the 'I' bit is zero). Of course, that would rule out stepping through an IRQ routine but I digress :-) The 68k has a single-step feature that explains this stuff nicely.

Now for breakpoints, a hardware breakpoint is easy enough, as Rob pointed out. The problem with that is that you this takes space (registers to hold breakpoint addresses) and additional logic (comparing all those registers against the PC). One way around this would be to dedicate a single bit in your opcode. Alas, I don't have that space, so that's a no. Copying the instruction over to a buffer would require quite some code to make sure you copy over the correct #of bytes. This could be somewhat tricky with branches and instructions that mess with the PC though..

Of course, when your code is in ROM, the whole opcode patching kinda goes out of the window... I'll give it another ponder as I'm sure there's some way to figure this out in a nice, elegant way :-)

Yvo


Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 16 posts ]  Go to page 1, 2  Next

All times are UTC


Who is online

Users browsing this forum: No registered users and 9 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Jump to: