I've not done anything this past week as I've been fixing a friends machine (and been knackered to boot!), so I've made no progress from what I reported last time.
However I was thinking.... I got a question a while ago about my tools being runable on Mac/Linux and I said probably not, but that might not be true. You see the thing about C# and .NET is that you can just use it as a C/C++ compiler as C# will happily do whats called unsafe code; thats basically where you use pointers again. Now what this means is I can port SNASM and possibly Minus4 into a C#/.NET environment and get it compiling, and it would then magically work on other platforms!
You see the thing about .NET is that its a virtual state machine, so you compile your code for a mythical CPU. This is then JIT (Just In Time) compiled when the program runs - much like Java is. This means my plain ol' C++ program would run quite happily under Mono on Mac or Linux. If I get a chance, I'll give this a go and see how I get on. Once its in a C# project I can then slowly port it properly to C# without all the pain.
(And yes...I know theres a managed C++ for .NET, but C/C++ sucks and I'd rather use C# these days...)
Saturday, August 30, 2008
Sunday, August 24, 2008
Toys - old and new
I've spent most of today playing with some old zx spectrum stuff. I looked out my old 48k spectrum (I actually have 4 or 5 now!) and some interfaces I have for them. I hooked up my Interface 1 and microdrive, tried my DivIDE (which I couldnt get to work on a 48k for some reason - need to find the manual...), and a Disciple interface. I had to find a floppy controller but had an old Amiga drive so used that. New PC drives dont work because they are hardwired to the wrong device. Still, the disciple interface works pretty well (its a clone though, not an original). It loads really (REALLY) quickly, and theres loads of storage. However theres no through connector (on this one) and I can use the interface one's RS232.
I also tried using the interface 1 with other things plugged in, and it didn't work either - although plugging an interface 2 did work. I have an interface 2 card that takes an eprom so thats a possibility as well. We could (for development) use an interface 1 and interface 2 to try out ROMs.
The other thing we could do is supply new ROM's for the spectrum itself, but thats not what we really want to do....
The first downloading code has to be written on the speccy, but after that It should be easy enough to develop for. However, most of this is Russells problem, and I've just been having fun for the day.
I also tried using the interface 1 with other things plugged in, and it didn't work either - although plugging an interface 2 did work. I have an interface 2 card that takes an eprom so thats a possibility as well. We could (for development) use an interface 1 and interface 2 to try out ROMs.
The other thing we could do is supply new ROM's for the spectrum itself, but thats not what we really want to do....
The first downloading code has to be written on the speccy, but after that It should be easy enough to develop for. However, most of this is Russells problem, and I've just been having fun for the day.
Saturday, August 23, 2008
More progress...
As you can see from the screen shot I've now gotten the watch window up and running properly. I now need to implement breakpoints properly and come up with a better way to redraw the main dissassembly window, rather than use the rich text box.
Oh, I also need to implement the register window properly as its currently processed by the monitor app rather than the CPU module. Since each processor has different register requirements theres no way to have this done generically, so it must be handled by the CPU module. This is a pain, but necessary. Technically speaking, I could implement a simple generic one IF the CPU module doesn't, and this would mean you could get up and running quicker, but I'm not sure yet.....
Lastly, I suddenly realised that we could use RS232 on a 48K spectrum using an interface one as it has a serial port built in. This would be slow (2.4k a second) but would be quick enough for a remote debugger. I expect most work to be done in an emulator, but this would provide a cheap way to get access on a real machine. This will of course be up to Russell whenever he gets around to doing that.
Oh, I also need to implement the register window properly as its currently processed by the monitor app rather than the CPU module. Since each processor has different register requirements theres no way to have this done generically, so it must be handled by the CPU module. This is a pain, but necessary. Technically speaking, I could implement a simple generic one IF the CPU module doesn't, and this would mean you could get up and running quicker, but I'm not sure yet.....
Lastly, I suddenly realised that we could use RS232 on a 48K spectrum using an interface one as it has a serial port built in. This would be slow (2.4k a second) but would be quick enough for a remote debugger. I expect most work to be done in an emulator, but this would provide a cheap way to get access on a real machine. This will of course be up to Russell whenever he gets around to doing that.
Friday, August 22, 2008
Watch Window.
I've gotten most of the watch window running now, and although its not finished it IS doing the client memory lookup as part of the expression. This involves giving the expression system access to the ICOMMS interface. This is fine as the monitor window owns both the expression and the comms classes.
The theory is you can have multiple monitor windows each with their own ICPU,IComms and IEvaluation objects. This means watches are attached to the CPU window and so can fetch memory from the client using a different comms interface (or the same). This should provide the most flexibility for the future as you should be able to debug multiple CPU machines like the SNES or megadrive which has a main CPU and a seprate sound CPU.
So, for now the expression evaluation will do proper evaluations, and allow you to access memory on the client via the attached comms module like so: [TEMP+4,w] This looks up the label TEMP, adds 4 then looks up the client memory and downloads a word (the ,w bit). This could then be used as a further value into a more progressive expression like this....
[SpriteData+[CurrentSprite,b]*2,w]. Obviously the more remote memory accesses you have the slower it'll go; BUT it will do it.
So, its looking good. I've decided to drop the memory count at the end for now as this means you can ALTER watch values via this window as well - which I wasn't planning. So all in all, its going well.
I plan to release full sources the the following modules-
The ISymbolFile module to load the SNASM symbol tables
The ICPU 6502 CPU module
The ICOMMS parallel port COMMS module
The 6502 STUB for parallel port version of the comms (C64 and Plus4)
The TCP/IP ICOMMS module
The TCP/IP C++ STUB for emulators
I will not be releasing source to the main Monitor program. I do hope to be doing a UDP version for the RR-NET, but that might not be in the first release. There will probably also be a Z80 ICPU module for using with my spectrum emulator which Russell is currently rewriting in C#. He's also really keen to write a remote stub for a real machine somehow, although we'll need an interface for that first. I do have a download cable for an amstrad, so he should be able to write a stub for that in the future as well.
I'm not currently sure what the first version will look like, or what features will be in but I think it'll be the basic monitor with breakpoints etc. Watch and memory window. If theres anything you think it shouldn't be released without, let me know - but remember most key systems are pluggable, so if theres a CPU thats not supported, you can write it yourself! I might add some tool modules so that the ICOMMS can do things like fetch sprite data etc. This would mean you could add a tool that views maps, sprites and all the rest at a later date.
Future additions will include a 65816 module for the superCPU, and probably a 65c02 module as well as a Hu7 module sometime there after. I know these will take time to appear, but feel free to add it yourself! In the far distant future, 68000 will appear as I want to play with the Amiga+ST again and this would be an ideal way....
Be warned though, part of the license agreement to this will state that any new modules WILL be included in the main application package although I've yet to decide if it will require the source code to be relased as well. So even if you dont send me your modules to get included, if I find them, they WILL be. I suspect this won't be an issue for anyone, but be warned. This is only for new ICPU, ICOMMS (and any stub that goes with it) and ISYMBOLTABLE modules, not for any program that uses them. if you have a problem with this, let me know now why that is.
The theory is you can have multiple monitor windows each with their own ICPU,IComms and IEvaluation objects. This means watches are attached to the CPU window and so can fetch memory from the client using a different comms interface (or the same). This should provide the most flexibility for the future as you should be able to debug multiple CPU machines like the SNES or megadrive which has a main CPU and a seprate sound CPU.
So, for now the expression evaluation will do proper evaluations, and allow you to access memory on the client via the attached comms module like so: [TEMP+4,w] This looks up the label TEMP, adds 4 then looks up the client memory and downloads a word (the ,w bit). This could then be used as a further value into a more progressive expression like this....
[SpriteData+[CurrentSprite,b]*2,w]. Obviously the more remote memory accesses you have the slower it'll go; BUT it will do it.
So, its looking good. I've decided to drop the memory count at the end for now as this means you can ALTER watch values via this window as well - which I wasn't planning. So all in all, its going well.
I plan to release full sources the the following modules-
I will not be releasing source to the main Monitor program. I do hope to be doing a UDP version for the RR-NET, but that might not be in the first release. There will probably also be a Z80 ICPU module for using with my spectrum emulator which Russell is currently rewriting in C#. He's also really keen to write a remote stub for a real machine somehow, although we'll need an interface for that first. I do have a download cable for an amstrad, so he should be able to write a stub for that in the future as well.
I'm not currently sure what the first version will look like, or what features will be in but I think it'll be the basic monitor with breakpoints etc. Watch and memory window. If theres anything you think it shouldn't be released without, let me know - but remember most key systems are pluggable, so if theres a CPU thats not supported, you can write it yourself! I might add some tool modules so that the ICOMMS can do things like fetch sprite data etc. This would mean you could add a tool that views maps, sprites and all the rest at a later date.
Future additions will include a 65816 module for the superCPU, and probably a 65c02 module as well as a Hu7 module sometime there after. I know these will take time to appear, but feel free to add it yourself! In the far distant future, 68000 will appear as I want to play with the Amiga+ST again and this would be an ideal way....
Be warned though, part of the license agreement to this will state that any new modules WILL be included in the main application package although I've yet to decide if it will require the source code to be relased as well. So even if you dont send me your modules to get included, if I find them, they WILL be. I suspect this won't be an issue for anyone, but be warned. This is only for new ICPU, ICOMMS (and any stub that goes with it) and ISYMBOLTABLE modules, not for any program that uses them. if you have a problem with this, let me know now why that is.
Wednesday, August 20, 2008
Watch me now....
I've been fighting with .NET list views for the watch window and have finally managed to get a watch class being mapped and displayed via the .NET data mapper. The Data mapper is very cool, and lets you map a class directly into a control. It also lets you add new items and will allocate/edit/delete new entries without me lifting a finger! Very neat.
I'll start on the actual watch processing tomorrow, and with any luck that'll be all that I'll need to do to implement basic watches! After that I'll need to get breakpoints working and I suspect the first version will closely follow afterwards.
I'll start on the actual watch processing tomorrow, and with any luck that'll be all that I'll need to do to implement basic watches! After that I'll need to get breakpoints working and I suspect the first version will closely follow afterwards.
Monday, August 18, 2008
Coming together....
I've been making steady progress and have now got the dissassembly window scrolling around under user control (without tracing). So you can now use the cursor keys to scroll the window, and the page-up and page-down keys to move quicker. It's going pretty well but I'm not happy with the ricj text box control. It feels slow, and there are a few keys you can't seem to override. This means although it gets rewritten every tick, you can upset things by pressing enter at the wrong time. I think I'm going to have to draw it myself somehow - perhaps even on a bitmap or something....
However that aside, its making good progress, and once I have user breakpoints in I can start looking at memory and watch windows. But the drawing of the display remains a concern....
However that aside, its making good progress, and once I have user breakpoints in I can start looking at memory and watch windows. But the drawing of the display remains a concern....
Saturday, August 16, 2008
Single stepping.
After a long discussion with Russell on Friday about the best way to single step, I decided to try out the new method. It basically involves having the STUB execute a single command inside the STUB itself. Currently I simply place a breakpoint one instruction later, and then run the application; the program runs, hits a BRK then stops again. This new way is friendlier to machines like the ZX Spectrum that has issues (and bugs in the ROM), but its tricky.
Imagine you've stopped the execution of a program, saved all the registers, flags etc. and now want to single step. What you would have to do is copy the instruction you want to trace into a 3 byte slot (thats prefilled with NOP's), restore all registers and flags (also stack) and execute the command. You then resave everything and return back to the debug comms loop. It sounds fairly simple but its not as easy as it appears.
Now you'll also notice you have to do some jiggery-pokery with the flags so you dont reenable interrupts by accident (since we're actually still IN an interrupt), but aside from that theres a lot of stuff involved. The bit I really dont like is that emulators simply wouldn't do this. They would simply set a break point and run. I really don't want to have 2 ways to step through code, I'd like it if the CPU module simply didn't care if it was a real machine or an emulator. Now, the spectrum can still do it with breakpoints, but since the spectrum ROM has bugs in it, its limited in exactly what it CAN do.
We currently think you would need to do breakpoints with CALL's, as the RST instruction needs ROM support and its the part thats bugged. NOW calls take up a few bytes which means you have limits as to where you can place a breakpoint. For example, if you were to branch over an XOR A but wanted to put a breakpoint on the XOR, then the breakpoint would overrun onto the next instruction, and it might crash.
Now for single stepping, that shouldn't happen; particually if the coder is aware of the limits. On other Z80 machines, it should be possible to use the RST instruction to do the breakpoints so they would be fine. I've put breakpoint control on the STUB for a few reasons, but because of this it means each STUB can decide how it wants to do them.
So... after playing around a lot with it (and actually getting it to work), I've decided not to use it, but to go back to the breakpoint idea. I think it has the widest compatibility, and if your really stuck you could still implement you own single step if you modify a CPU module and package it together with a dedicated COMMS module.
I've also started to think about the TCP/IP module for using with emulators (and I'll do a UDP one for the RR-NET later), and I'm starting to get excited about the possibility of it being adopted by other emulator guys. If all goes well, then no one should ever have to write a built in debugger again!
Imagine you've stopped the execution of a program, saved all the registers, flags etc. and now want to single step. What you would have to do is copy the instruction you want to trace into a 3 byte slot (thats prefilled with NOP's), restore all registers and flags (also stack) and execute the command. You then resave everything and return back to the debug comms loop. It sounds fairly simple but its not as easy as it appears.
;******************************************************************************
;
; Name: SingleStep
; Function: Given an address and a byte count, execute a sequence of bytes
;
;******************************************************************************
ExecuteCommand:
jsr GetByte ; Get destination address
sta Dest
jsr GetByte
sta Dest+1
jsr GetByte ; get opcode size
tay
dey
; Clear out exec buffer
lda #$ea ; Clear the instruction space
sta ExecBuffer+1 ; in case the instruction isn't 3 bytes long!
sta ExecBuffer+2
; copy
!lp1 lda (Dest),y ; Copy the instruction to execute
sta ExecBuffer,y
dey
bpl !lp1
tsx ; Save current stack
stx StackStore
ldx RegSP ; Restore application stack
txs
lda RegF ; Get the flags ready
pha
and #$4 ; We must keep interrupts OFF!
sta RegF
pla
ora #4
pha
lda RegA ; restore registers
ldx RegX
ldy RegY
plp ; restore flags
ExecBuffer:
nop ; Command goes here.
nop
nop
php ; Save flags
sta RegA ; Save registers
stx RegX
sty RegY
pla ; get the flags and store
and #%11111011
ora RegF
sta RegF
tsx
stx RegSP ; Store the application stack
ldx StackStore ; get the debugger stack back
txs ; and restore it.
rts
StackStore db 0
Now you'll also notice you have to do some jiggery-pokery with the flags so you dont reenable interrupts by accident (since we're actually still IN an interrupt), but aside from that theres a lot of stuff involved. The bit I really dont like is that emulators simply wouldn't do this. They would simply set a break point and run. I really don't want to have 2 ways to step through code, I'd like it if the CPU module simply didn't care if it was a real machine or an emulator. Now, the spectrum can still do it with breakpoints, but since the spectrum ROM has bugs in it, its limited in exactly what it CAN do.
We currently think you would need to do breakpoints with CALL's, as the RST instruction needs ROM support and its the part thats bugged. NOW calls take up a few bytes which means you have limits as to where you can place a breakpoint. For example, if you were to branch over an XOR A but wanted to put a breakpoint on the XOR, then the breakpoint would overrun onto the next instruction, and it might crash.
Now for single stepping, that shouldn't happen; particually if the coder is aware of the limits. On other Z80 machines, it should be possible to use the RST instruction to do the breakpoints so they would be fine. I've put breakpoint control on the STUB for a few reasons, but because of this it means each STUB can decide how it wants to do them.
So... after playing around a lot with it (and actually getting it to work), I've decided not to use it, but to go back to the breakpoint idea. I think it has the widest compatibility, and if your really stuck you could still implement you own single step if you modify a CPU module and package it together with a dedicated COMMS module.
I've also started to think about the TCP/IP module for using with emulators (and I'll do a UDP one for the RR-NET later), and I'm starting to get excited about the possibility of it being adopted by other emulator guys. If all goes well, then no one should ever have to write a built in debugger again!
Thursday, August 14, 2008
Lookin' good!
I've finally done enough to make some visible progress. With the addition of the expression evaluation, symbol table lookup and command line processing means I can finally display symbols in the dissassembly view. It's now starting to look like a proper debugger. I need to get left side labels in next (where the addresses are displayed) so you can see where your branching to, then we'll be mostly done in that view.
I still have to add control of the view but thats next. The biggest unknown is the registers, I've no idea yet how to display a generic number of registers or how to lay them out. I'm tempted to let the CPU module display them as well as handle them, but I don't know yet.
Tuesday, August 12, 2008
Good progress!
I've gotten on pretty well tonight! I've managed to finish BOTH the lexical analysis class and the expression evaluation system. Not bad for a nights work. I can now evaluate things like...
This means watches can enter calculations to be evaluated, which you can then apply the [...] modifier to so that its a memory lookup on the target. I still have a way to go as theres currently no way to get the evaluation system to look at the targets memory OR registers. However that shouldn't be hard and then things will start to get very cool. Of course the inital reason for this is so theres an interface for the CPU module to lookup symbols for the dissassembly, but through the same interface you'll be able to execute actual calculations.
I also have the ability to add commands to this, like Lo() and Hi(). This means you could do calculations like...
This is pretty neat, but it also opens up for more complex functions like ...err... SQRT() or something, which is pretty cool too. The whole expression and lexical stuff is just 2 small C# files, so its pretty portable if I want to do anything else, so this could be handy!
((2<<(4*4)+8*4)&$ffff-MySymbol)*4
This means watches can enter calculations to be evaluated, which you can then apply the [...] modifier to so that its a memory lookup on the target. I still have a way to go as theres currently no way to get the evaluation system to look at the targets memory OR registers. However that shouldn't be hard and then things will start to get very cool. Of course the inital reason for this is so theres an interface for the CPU module to lookup symbols for the dissassembly, but through the same interface you'll be able to execute actual calculations.
I also have the ability to add commands to this, like Lo() and Hi(). This means you could do calculations like...
Lo( 2<<(4*4)+8*4 )<<2
This is pretty neat, but it also opens up for more complex functions like ...err... SQRT() or something, which is pretty cool too. The whole expression and lexical stuff is just 2 small C# files, so its pretty portable if I want to do anything else, so this could be handy!
Monday, August 11, 2008
Expressions and Lexical analysis
So I started to look around after yesterdays revamp of the plugins, and realised that to finish the intialisation system I need to pass in an expression evaluation interface. Oh well.... more code to port..... I started to port over SNasms expression stuff but it soon became apparent that I needed a lexical processor first. Now the one in SNasm it pretty fully featured, but a bit much for a command interface, then I suddenly realised that I dont need very much at all. I need to be able to pick out symbols (like *,."$&[]() etc.) and symbols. This means I only need a very simple one as at text I dont understand will be a label (or I can do a quick dictionary lookup to got basic commands).
So I've almost got this basic one going, and its really very simple but will do the job at hand. So I'll finish this tomorrow, and then port the expression stuff the night after and finally I'll be able to get the intialisation stuff done. It also means I can start to load symbol files and get a proper symbolic dissassembly!
Slow going, but we're headed in the right direction.
So I've almost got this basic one going, and its really very simple but will do the job at hand. So I'll finish this tomorrow, and then port the expression stuff the night after and finally I'll be able to get the intialisation stuff done. It also means I can start to load symbol files and get a proper symbolic dissassembly!
Slow going, but we're headed in the right direction.
Sunday, August 10, 2008
Slow going....
I've not been doing much on the debugger as I've been busy with real life, but I did get some time today to mess around. I've been updating the plugin system to make it more flexible and so that I can do some work on the command line arguments system. Currently I can specify which modules I want to use on the command line (along with symbol table loader and symbol file), and the next step is to spawn a monitor window using the selected modules.
I've rearranged all code so that multiple monitor windows are possible, in theory this will allow debugging of secondard CPU modules as long as the debugging stub or interface supports it - although thats a long way off yet.
I've rearranged all code so that multiple monitor windows are possible, in theory this will allow debugging of secondard CPU modules as long as the debugging stub or interface supports it - although thats a long way off yet.
Thursday, August 07, 2008
Future plans....
There was a question about using the RR-NET instead of the serial port, so I thought I'd answer in depth here.....
Currently I'm debugging via the user port on a Commodore Plus/4 and the parallel port on the PC, but the plan is to then do two C64 versions using both the userport AND the RR-NET (since the RR-NET is far easier to get a hold of). However the user port version would allow you to develop more hardware as you can't always use RR-NET if your trying to develop for a bit of hardware where theres no passthrough, or it's simply not available (The current cart disables the pass through when in use.)
That said, for normal apps and games, I hope the MMC64/RR-NET (and the MMC Replay) will be invaluable for getting things working on real hardware. Theres nothing quite like debugging on a real machine, particually if you are using the MMC64 file loader stuff I did in the framework, as thats currently impossible to develop with via an emulator. Of course someone could also implement a SilverSurfer stub as well - nothing to stop them!
In between these versions (probably at the same time as the RR-NET version), I'll write my first emulator plugin and get Minus4 working using it. This will then be given away for everyone to use. I then hope that new modules will start popping up as all the hard work should be done, and emulators should just be able to plug it in. Once we have some simple CPU types (Z80, 6502 etc.) then all an emulator should have to do is implement the STUB and it'll all magically work.
The idea is to give away the source to the 6502 module, the COMMS modules, all the STUBS that I end up doing, and the Symbol table module. This should allow you to write whatever system you want, without having to implement all the crap around it that makes up the debugger - in theory. It also means you can easily adapt modules for your own use; so the 6502 one could be changed to be a 65816 one, or a 65c02 etc. allowing for new machines like the SNES or PC Engine to be added easily.
Lastly.... if theres ever any real problems with getting a particular machine to work using the interface provided, then all you need to do is put both modules in the same DLL (comms and cpu) then you can add extra interfaces to expand or alter the behaviour. Lets say you couldn't implement single stepping in the way thats assumed you would, then you can add a new comms command that only YOUR cpu module knows about and call it instead.
Thats the theory......
Currently I'm debugging via the user port on a Commodore Plus/4 and the parallel port on the PC, but the plan is to then do two C64 versions using both the userport AND the RR-NET (since the RR-NET is far easier to get a hold of). However the user port version would allow you to develop more hardware as you can't always use RR-NET if your trying to develop for a bit of hardware where theres no passthrough, or it's simply not available (The current cart disables the pass through when in use.)
That said, for normal apps and games, I hope the MMC64/RR-NET (and the MMC Replay) will be invaluable for getting things working on real hardware. Theres nothing quite like debugging on a real machine, particually if you are using the MMC64 file loader stuff I did in the framework, as thats currently impossible to develop with via an emulator. Of course someone could also implement a SilverSurfer stub as well - nothing to stop them!
In between these versions (probably at the same time as the RR-NET version), I'll write my first emulator plugin and get Minus4 working using it. This will then be given away for everyone to use. I then hope that new modules will start popping up as all the hard work should be done, and emulators should just be able to plug it in. Once we have some simple CPU types (Z80, 6502 etc.) then all an emulator should have to do is implement the STUB and it'll all magically work.
The idea is to give away the source to the 6502 module, the COMMS modules, all the STUBS that I end up doing, and the Symbol table module. This should allow you to write whatever system you want, without having to implement all the crap around it that makes up the debugger - in theory. It also means you can easily adapt modules for your own use; so the 6502 one could be changed to be a 65816 one, or a 65c02 etc. allowing for new machines like the SNES or PC Engine to be added easily.
Lastly.... if theres ever any real problems with getting a particular machine to work using the interface provided, then all you need to do is put both modules in the same DLL (comms and cpu) then you can add extra interfaces to expand or alter the behaviour. Lets say you couldn't implement single stepping in the way thats assumed you would, then you can add a new comms command that only YOUR cpu module knows about and call it instead.
Thats the theory......
Wednesday, August 06, 2008
Bingo!!
I've now fixed the tracing system so I can trace without a problem. I managed to single step through quite a bit of XeO3 which is a good sign. It appears to be pretty solid, I can stop/start and trace without any issue now - which is great. That means I have the core functionality now needed to progress. The current CPU and COMMS interface does have an issue however.... Single stepping on the spectrum (a 48k one at anyrate) isn't easy, and in order to make it better you really need to get the target to execute the single step so it can do it best for itself. However, getting the stub to do that takes quite a bit of memory and I dont want that, so I need to think about it a little longer....
Almost there!
I've now got things almost working, single stepping is rock solid and I now have the RTS instruction being simulated fine. There appears to be a slight glitch where on a specific instruction in XeO3 it doesn't step properly but jumps off to $FFFF for some reason - no idea why as yet. While I'm trying to figure this out I'll start adding breakpoints to the interface and then get the symbol table loaded.
I suddenly realised that I shouldn't be passing the an interface top the symbol table to the CPU model, but an interface to an expression evaluation module. This means the CPU code could evaluate expressions if it needs to, and that leaves me to deal with symbol table lookups inside the expression evaluation without having to worry about it. You'll still be able to write your own symbol table so that you can load funny symbol file formats, and you'll still be able to query for symbols but this time it'll go through the evaluation system instead.
I'll pinch the expression stuff from SNasm and put an interface around it, this means it'll handle anything SNasm could (which was a lot!). It also means that watches (with their complex expressions) should be a breeze to process, all I need to do is add the new [..] context to get memory from the target. Should be fun when its all working! I'm still not sure how fast its all gonna run, as getting lots of memory over a parallel cable isn't quick, still emulators should be very fast and at least you'll be using a common interface then!
I also realised that each module (ICPU, ISymbolTable and IComms) needs to be able to change some options, so I'll add a new interface that means it can pop up an options box and allow you to change things. For example, the CPU module might allow you to enable undocumented opcodes which aren't on by default.
So there you go! Its going pretty well so far! Once I get it to a basic level, I'll need to see if I can get some other coders to try it out and give me some feedback. of course, having only SNasm labels might hinder things a little, but then again it would be a good opportunity to have someone else write a module and tell me how easy or hard it was!
I suddenly realised that I shouldn't be passing the an interface top the symbol table to the CPU model, but an interface to an expression evaluation module. This means the CPU code could evaluate expressions if it needs to, and that leaves me to deal with symbol table lookups inside the expression evaluation without having to worry about it. You'll still be able to write your own symbol table so that you can load funny symbol file formats, and you'll still be able to query for symbols but this time it'll go through the evaluation system instead.
I'll pinch the expression stuff from SNasm and put an interface around it, this means it'll handle anything SNasm could (which was a lot!). It also means that watches (with their complex expressions) should be a breeze to process, all I need to do is add the new [..] context to get memory from the target. Should be fun when its all working! I'm still not sure how fast its all gonna run, as getting lots of memory over a parallel cable isn't quick, still emulators should be very fast and at least you'll be using a common interface then!
I also realised that each module (ICPU, ISymbolTable and IComms) needs to be able to change some options, so I'll add a new interface that means it can pop up an options box and allow you to change things. For example, the CPU module might allow you to enable undocumented opcodes which aren't on by default.
So there you go! Its going pretty well so far! Once I get it to a basic level, I'll need to see if I can get some other coders to try it out and give me some feedback. of course, having only SNasm labels might hinder things a little, but then again it would be a good opportunity to have someone else write a module and tell me how easy or hard it was!
Monday, August 04, 2008
Step, Step, Pause, Step step, step step
I didn't get much done tonight, but single stepping is a lot more stable now. I've updated the window update so that it doesn't request the current view every time you single step. This obviously won't work for self-modifying code, but for now it makes it much quicker to single step. I'm trying to get the RTS instruction to work but the register update doesn't appear to be working yet. The idea is to simulate RTS and RTI (and possibly JSR, JMP and all the branches) but this involves updating the registers to their new values.
I'll need to clean the monitor code up once its all working, as its getting a little messy just now. Also I'm still having trouble debugging this code as devstudio doesn't appear to want to load the symbols for all the modules its loaded....very annoying!
I'll need to clean the monitor code up once its all working, as its getting a little messy just now. Also I'm still having trouble debugging this code as devstudio doesn't appear to want to load the symbols for all the modules its loaded....very annoying!
Sunday, August 03, 2008
Squeezing it all in.
Now that things are working better I've started to try and squeeze it all down a little. It's not finished by any means, but I think it's at a reasonable stage where I can start to think about the memory foot print. The inital goal was to have the stub take up around 1k, but I now have it down to under 0.5k which is great news. I'm sure there's going to be more added to it, but its pretty complete for now. As a default setup, I've put the debug variables on the unused bits of the stack ($100 to $138) which is usually free - although since I'll give away the source - you can put it where you like. I only use 5 bytes of zero page $FA-$FF so as along as you avoid these locations, all should be well.
I've made pretty good progress today, and while tracing still isn't finished (still jumps off into the wilds now and then), it's now progressing nicely. I'll fix up JSRs, RTSs, RTIs and branches tomorrow night if I get time, then I can move on to making the dissassembly window nicer along with a user controlable BAR for scrolling the view around, and then start on the symbol table and displaying a proper symbolic dissassembly.
I've made pretty good progress today, and while tracing still isn't finished (still jumps off into the wilds now and then), it's now progressing nicely. I'll fix up JSRs, RTSs, RTIs and branches tomorrow night if I get time, then I can move on to making the dissassembly window nicer along with a user controlable BAR for scrolling the view around, and then start on the symbol table and displaying a proper symbolic dissassembly.
AT LAST!!!!
I've finally figured out what I was doing wrong...what a twat! Okay, so in the old remote debugger I hadn't delt with the +2 of the BRK instruction and I have here, so that wasn't it this time around. I was begining to think the 7501 was slightly different from the 6502 and all the docs I had would be wrong for it, but no. The REAL reason was far simpler..... I had 2 interrupt routines.
Now I figered you only need to check for a debugger in one of them since its only checking comms and waiting a frame there doesn't matter, but the more I tested this BRK thing, the more confusing it became.
I was able to make a test where it was out right ignoring BRK instructions! I simply couldn't figure that out, that is until I realised you need to call the debug stub EVERY interrupt so it can ALSO check for BRK instructions. Otherwise it'll just exit the IRQ and carry on like nothing happened.
So, that really annoying bug fixed, and I can now single step/run/stop in a rock solid manner - at last! Now I need to emulate RTS and RTI instructions so that the debugger works properly, and I'll probably emulate branches as well since it means I only need one breakpoint. Although I'll allow RTI via the monitor, you wont't be able to debug interrupts, this is just for emulator support as it WILL be able to debug interrupts. Because a real machine uses BRK's for breakpoints, its stub is inside an interrupt, but emulators dont have to do that, they can single step anywhere and dont need to write BRK's, they can just have a breakpoint table and check to the current PC which makes them very powerful.
I have to say I'm relieved, it was starting to get to me. I usually don't spend long on bugs, but this one was pushing it.... Still, all fixed and now we can really push on with some monitor features! It'll be great to get real watches and multiple memory windows without having to do to much. The comm's speed will probably hurt the update of watch windows, but we can probably put in a bit of smarts and a FORCE UPDATE button or something to help. Watches are probably the most powerful thing I've missed as you can ask for a variable and tell it the type and number of entrys you want displayed. i.e.
The other great thing about watches is that you only get the memory you need, not a whole memory window just to watch a single byte! You'll also notice I hope to do expression evaluation like "[Temp,w]+Y". This would get the word contents of Temp and add on the Y - or something like this. this is of course way down the line, but features like this will come, and everyone that uses the STUB interface will benifit without having to do it themselves.
Now I figered you only need to check for a debugger in one of them since its only checking comms and waiting a frame there doesn't matter, but the more I tested this BRK thing, the more confusing it became.
I was able to make a test where it was out right ignoring BRK instructions! I simply couldn't figure that out, that is until I realised you need to call the debug stub EVERY interrupt so it can ALSO check for BRK instructions. Otherwise it'll just exit the IRQ and carry on like nothing happened.
So, that really annoying bug fixed, and I can now single step/run/stop in a rock solid manner - at last! Now I need to emulate RTS and RTI instructions so that the debugger works properly, and I'll probably emulate branches as well since it means I only need one breakpoint. Although I'll allow RTI via the monitor, you wont't be able to debug interrupts, this is just for emulator support as it WILL be able to debug interrupts. Because a real machine uses BRK's for breakpoints, its stub is inside an interrupt, but emulators dont have to do that, they can single step anywhere and dont need to write BRK's, they can just have a breakpoint table and check to the current PC which makes them very powerful.
I have to say I'm relieved, it was starting to get to me. I usually don't spend long on bugs, but this one was pushing it.... Still, all fixed and now we can really push on with some monitor features! It'll be great to get real watches and multiple memory windows without having to do to much. The comm's speed will probably hurt the update of watch windows, but we can probably put in a bit of smarts and a FORCE UPDATE button or something to help. Watches are probably the most powerful thing I've missed as you can ask for a variable and tell it the type and number of entrys you want displayed. i.e.
DestAdd,w: $2881
SrcTable,w,3: $8002, $8100, $8132
SpriteData,64: $00,$01,$02,$03,$04....(up to 64 bytes)
[Temp,w]+y,5: $10,$22,$44,$86,$00
The other great thing about watches is that you only get the memory you need, not a whole memory window just to watch a single byte! You'll also notice I hope to do expression evaluation like "[Temp,w]+Y". This would get the word contents of Temp and add on the Y - or something like this. this is of course way down the line, but features like this will come, and everyone that uses the STUB interface will benifit without having to do it themselves.
Progress? Who knows....
Here's another little test app and this one's pretty simple, but it does show up the flaw.
Now on entry to the debugger I adjust the stack to point to the BRK instruction so that we know exactly where its stopped. This works fine. But on exit I expect it to re-execute the BRK and not do anything, however this one does not. When I run it again the screen colour changes, and its not supposed to. I suspect this is the problem, BRK's are not being restarted properly, but at least now I have a test case, I should manage to fix it easily enough - I think.
58C9 CE 15 FF dec $FF15
58CC EA nop
58CD EA nop
58D0 00 brk
58D1 EA nop
58D4 EA nop
58D5 4C C9 58 jmp $58C9
Now on entry to the debugger I adjust the stack to point to the BRK instruction so that we know exactly where its stopped. This works fine. But on exit I expect it to re-execute the BRK and not do anything, however this one does not. When I run it again the screen colour changes, and its not supposed to. I suspect this is the problem, BRK's are not being restarted properly, but at least now I have a test case, I should manage to fix it easily enough - I think.
Saturday, August 02, 2008
Trouble ahead.
I really am struggling with getting this thing to single step properly, its a nightmare! The actual monitor code is pretty easy but I think I have something wrong on the stub end that means its just now working right. I have a single breakpoint that I place after the current instruction (lets ignore branchs and calls just now), and I then resume execution. The idea being that it runs a single instruction and hits the new breakpoint (however its been implemented) and jumps back into the debugger again.
The problem is, its just not working like that. Now RUN and STOP work great, so I know jumping in and out the debugger is fine, and I have tested BRK instructions as well and they are okay too. Whenever I hit a break I subtract 2 off the PC (as its moved on entry to the interrupt routine), and I can then resume again.
So far so good.... but if I drop in some more BRK's, they don't seem to be getting hit properly at all. I can't of course debug the stub either so I'm left with just looking at code. I suspect I'll need to start a new, simple project to try and figure out why its not working, as staring at code doesn't seem to help.
So heres the loop Im trying to debug, and its interesting coz aside from not doing much, it shows up several issues.
First, if I try and single step $58DA, the whole thing dies a horrible death. IF I try and step $58D6, then $FF15 is increased and Y is decreased to 1 (which is impossible).
Its all very odd, but there must be a logical solution - somewhere!
The problem is, its just not working like that. Now RUN and STOP work great, so I know jumping in and out the debugger is fine, and I have tested BRK instructions as well and they are okay too. Whenever I hit a break I subtract 2 off the PC (as its moved on entry to the interrupt routine), and I can then resume again.
So far so good.... but if I drop in some more BRK's, they don't seem to be getting hit properly at all. I can't of course debug the stub either so I'm left with just looking at code. I suspect I'll need to start a new, simple project to try and figure out why its not working, as staring at code doesn't seem to help.
So heres the loop Im trying to debug, and its interesting coz aside from not doing much, it shows up several issues.
58D1 CE 15 FF dec $FF15
58D4 A9 01 lda #$01
58D6 A2 02 ldx #$02
58D8 A0 03 ldy #$03
58DA EA nop
58DB CA dex
58DC D0 FC bne $58DA
58DE B9 00 10 lda $1000,y
58E1 88 dey
58E2 4C D1 58 jmp $58D1
First, if I try and single step $58DA, the whole thing dies a horrible death. IF I try and step $58D6, then $FF15 is increased and Y is decreased to 1 (which is impossible).
Its all very odd, but there must be a logical solution - somewhere!
Friday, August 01, 2008
New we're getting some where!
So with most of the ground work done I've now managed to get registers from the client and can dissassemble the current view (as shown). I'm using a rich text box (after some head scratching) and it appears to work fine. I have a stack of new interfaces and classes that people will use to write their own debugging aids, and Russell says he wants to do a Z80 one and plug it into my noddy spectrum emulator. (which I had forgotten all about). This means when I get the basic one going, he's going to write a TCP/IP (or UDP) version and that can be given away free for folk to include in their own code. These stubs will be in C++ so most emulators should be able to use them.
I did start to port my spectrum emulator over to C# but never got around to finishing it - perhaps something to do on my next holiday.....
So the current state of play is I can stop the target, run it again, and get its registers and a dissassembly view of it. Next I need to be able to STEP an instruction, and then things will get really interesting! While you're using a PC to debug the Plus/4, its easy to forget that it's a slow beasty and the more watches, memory windows and the like you have, the slower its going to go! downloading all that memory will take time! So if its too slow, closing a memory window will probably speed things up quite a bit!
The debugger is also designed so that one day I can add source level debugging as well. This means you can step through your actual source code and not just some abstract view. It also means you'll get all your comments while stepping and viewing code. This will be pretty cool indeed. Minus4Dos actually did this. It was the last feature I added before stopping its development, and it was pretty cool so I'm looking forward to getting that feature back. I'll need to expand SNasm's output support so that it does index files which will eventually enable me to do this, but that should be pretty easy....
Subscribe to:
Posts (Atom)