diff --git a/src/com/maccasoft/tools/Application.java b/src/com/maccasoft/tools/Application.java index f61654c..d00629b 100644 --- a/src/com/maccasoft/tools/Application.java +++ b/src/com/maccasoft/tools/Application.java @@ -63,6 +63,8 @@ import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.events.MenuEvent; import org.eclipse.swt.events.MenuListener; +import org.eclipse.swt.events.MouseAdapter; +import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.TraverseEvent; @@ -237,7 +239,7 @@ public class Application { return; } - display.asyncExec(stepOverRunnable); + display.asyncExec(this); } }; @@ -255,7 +257,19 @@ public class Application { return; } - display.asyncExec(runToLineRunnable); + display.asyncExec(this); + } + }; + + final Runnable runCodeRunnable = new Runnable() { + + @Override + public void run() { + if (stepOverPC1 == -1) { + return; + } + proc.execute(); + display.asyncExec(this); } }; @@ -962,6 +976,37 @@ public class Application { menuItem.setMenu(menu); MenuItem item = new MenuItem(menu, SWT.PUSH); + item.setText("Run\tF5"); + item.setAccelerator(SWT.F5); + item.addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event e) { + try { + handleRun(); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + }); + + item = new MenuItem(menu, SWT.PUSH); + item.setText("Stop"); + item.addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event e) { + try { + handleStop(); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + }); + + new MenuItem(menu, SWT.SEPARATOR); + + item = new MenuItem(menu, SWT.PUSH); item.setText("Step into\tF8"); item.setAccelerator(SWT.F8); item.addListener(SWT.Selection, new Listener() { @@ -1008,13 +1053,28 @@ public class Application { new MenuItem(menu, SWT.SEPARATOR); item = new MenuItem(menu, SWT.PUSH); - item.setText("Stop"); + item.setText("Toggle breakpoint\tCtrl+Shift+B"); + item.setAccelerator(SWT.MOD1 + SWT.MOD2 + 'B'); item.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event e) { try { - handleStop(); + handleToggleBreakpoint(); + } catch (Exception e1) { + e1.printStackTrace(); + } + } + }); + + item = new MenuItem(menu, SWT.PUSH); + item.setText("Clear all breakpoints"); + item.addListener(SWT.Selection, new Listener() { + + @Override + public void handleEvent(Event e) { + try { + handleClearBreakpoints(); } catch (Exception e1) { e1.printStackTrace(); } @@ -1515,6 +1575,13 @@ public class Application { viewer = new SourceViewer(composite, new Z80TokenMarker()); viewer.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); + viewer.getStyledText().addMouseListener(new MouseAdapter() { + + @Override + public void mouseDoubleClick(MouseEvent e) { + handleToggleBreakpoint(); + } + }); registers = new Registers(composite); registers.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, false, false)); @@ -2356,36 +2423,43 @@ public class Application { public int breakpoint(int address, int opcode) { // Emulate CP/M Syscall at address 5 - switch (proc.getRegC()) { - case 0: // BDOS 0 System Reset - out.println("Z80 reset after " + memIoOps.getTstates() + " t-states"); - break; - case 2: // BDOS 2 console char output - if (debugTerminal != null) { - debugTerminal.write(proc.getRegE()); - } - else { - out.write(proc.getRegE()); - } - break; - case 9: {// BDOS 9 console string output (string terminated by "$") - int strAddr = proc.getRegDE(); - if (debugTerminal != null) { - while (memIoOps.peek8(strAddr) != '$') { - debugTerminal.write(memIoOps.peek8(strAddr++)); + if (address == 0x0005) { + switch (proc.getRegC()) { + case 0: // BDOS 0 System Reset + out.println("Z80 reset after " + memIoOps.getTstates() + " t-states"); + break; + case 2: // BDOS 2 console char output + if (debugTerminal != null) { + debugTerminal.write(proc.getRegE()); } - } - else { - while (memIoOps.peek8(strAddr) != '$') { - out.write(memIoOps.peek8(strAddr++)); + else { + out.write(proc.getRegE()); } + break; + case 9: { // BDOS 9 console string output (string terminated by "$") + int strAddr = proc.getRegDE(); + if (debugTerminal != null) { + while (memIoOps.peek8(strAddr) != '$') { + debugTerminal.write(memIoOps.peek8(strAddr++)); + } + } + else { + while (memIoOps.peek8(strAddr) != '$') { + out.write(memIoOps.peek8(strAddr++)); + } + } + break; } - break; + default: + out.println("BDOS Call " + proc.getRegC()); + break; } - default: - out.println("BDOS Call " + proc.getRegC()); - break; + + return opcode; } + + handleStop(); + return opcode; } @@ -2584,6 +2658,32 @@ public class Application { updateDebuggerState(); } + private void handleToggleBreakpoint() { + int caretOffset = viewer.getStyledText().getCaretOffset(); + int lineAtOffset = viewer.getStyledText().getLineAtOffset(caretOffset); + + Line line = viewer.getSource().getLines().get(lineAtOffset); + if (line != null) { + int address = line.getScope().getAddress(); + viewer.toggleBreakpoint(address); + proc.setBreakpoint(address, viewer.isBreakpoint(address)); + } + } + + private void handleClearBreakpoints() { + viewer.resetBreakpoints(); + proc.resetBreakpoints(); + } + + private void handleRun() { + stepOverPC1 = 0; + stepOverPC2 = -1; + memory.clearUpdates(); + viewer.getControl().setFocus(); + + display.asyncExec(runCodeRunnable); + } + void updateDebuggerState() { memory.update(); registers.updateRegisters(proc); diff --git a/src/com/maccasoft/tools/CodeRuler.java b/src/com/maccasoft/tools/CodeRuler.java index e8b671a..4aa01f6 100644 --- a/src/com/maccasoft/tools/CodeRuler.java +++ b/src/com/maccasoft/tools/CodeRuler.java @@ -9,6 +9,10 @@ package com.maccasoft.tools; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + import org.eclipse.swt.SWT; import org.eclipse.swt.custom.CaretEvent; import org.eclipse.swt.custom.CaretListener; @@ -37,6 +41,7 @@ public class CodeRuler { StyledText text; Source source; + boolean[] breakpoint; int leftMargin; int rightMargin; @@ -46,6 +51,9 @@ public class CodeRuler { private int currentLine; private Color currentLineBackground; + private Font font; + private Font fontBold; + final PaintListener paintListener = new PaintListener() { @Override @@ -101,6 +109,8 @@ public class CodeRuler { currentLine = 0; currentLineBackground = new Color(Display.getDefault(), 232, 242, 254); + + breakpoint = new boolean[65536]; } public void setText(StyledText text) { @@ -128,6 +138,7 @@ public class CodeRuler { if (source != null && lineNumber >= 0 && lineNumber < source.getLines().size()) { Line line = source.getLines().get(lineNumber); + int address = line.getScope().getAddress(); byte[] code = line.getBytes(); StringBuilder sb = new StringBuilder(); @@ -145,6 +156,7 @@ public class CodeRuler { else { gc.setBackground(canvas.getBackground()); } + gc.setFont((breakpoint[address] && code.length != 0) ? fontBold : font); gc.drawString(sb.toString(), leftMargin, y, true); } @@ -152,7 +164,10 @@ public class CodeRuler { } } - public void setFont(Font font) { + public void setFont(Font font, Font boldFont) { + this.font = font; + this.fontBold = boldFont; + canvas.setFont(font); GC gc = new GC(canvas); @@ -172,4 +187,32 @@ public class CodeRuler { public void redraw() { canvas.redraw(); } + + public int[] getBreakpoints() { + List l = new ArrayList(); + for (int i = 0; i < breakpoint.length; i++) { + if (breakpoint[i]) { + l.add(i); + } + } + + int[] result = new int[l.size()]; + for (int i = 0; i < l.size(); i++) { + result[i] = l.get(i); + } + return result; + } + + public void toggleBreakpoint(int address) { + breakpoint[address] = !breakpoint[address]; + } + + public boolean isBreakpoint(int address) { + return breakpoint[address]; + } + + public void resetBreakpoints() { + Arrays.fill(breakpoint, false); + } + } diff --git a/src/com/maccasoft/tools/SourceViewer.java b/src/com/maccasoft/tools/SourceViewer.java index 8ea6728..7cba6ef 100644 --- a/src/com/maccasoft/tools/SourceViewer.java +++ b/src/com/maccasoft/tools/SourceViewer.java @@ -119,7 +119,7 @@ public class SourceViewer { ruler.setFont(font); ruler.setText(text); - codeRuler.setFont(font); + codeRuler.setFont(font, fontBold); codeRuler.setText(text); currentLine = 0; @@ -374,7 +374,7 @@ public class SourceViewer { text.setCaretOffset(text.getCaretOffset()); ruler.setFont(font); - codeRuler.setFont(font); + codeRuler.setFont(font, fontBold); container.getDisplay().asyncExec(new Runnable() { @@ -418,4 +418,18 @@ public class SourceViewer { styleMap.put(TokenId.NumberLiteral, new TextStyle(font, new Color(Display.getDefault(), 0xFF, 0x00, 0xFF), null)); } + public void toggleBreakpoint(int address) { + codeRuler.toggleBreakpoint(address); + codeRuler.redraw(); + } + + public boolean isBreakpoint(int address) { + return codeRuler.isBreakpoint(address); + } + + public void resetBreakpoints() { + codeRuler.resetBreakpoints(); + codeRuler.redraw(); + } + } diff --git a/src/z80core/Z80.java b/src/z80core/Z80.java index e06e130..55278d3 100644 --- a/src/z80core/Z80.java +++ b/src/z80core/Z80.java @@ -1776,6 +1776,12 @@ public class Z80 { breakpointAt[address & 0xffff] = state; } + public final void setBreakpoints(int[] address, boolean state) { + for (int i = 0; i < address.length; i++) { + breakpointAt[address[i] & 0xffff] = state; + } + } + public void resetBreakpoints() { Arrays.fill(breakpointAt, false); }