diff --git a/src/docs/verilog-waveform.md b/src/docs/verilog-waveform.md
new file mode 100644
index 00000000..7311fa8f
--- /dev/null
+++ b/src/docs/verilog-waveform.md
@@ -0,0 +1,29 @@
+# Waveform Viewer
+
+The Verilog platform shows a waveform trace below the emulator screen,
+with one row per exposed signal. **Click** to give the waveform viewer
+keyboard focus.
+
+If the CRT is active, the waveform viewer is hidden by default, below the CRT frame.
+You can **click and drag** its frame border up from the bottom of the screen.
+
+## Which signals appear
+
+The trace shows every scalar/vector `logic` signal from the flattened
+design: top-level ports and internal registers and wires from every
+submodule, not just the top level. These are omitted:
+
+- Non-logic types (arrays, memories)
+- Internal simulator temporaries (names starting with `__V`)
+- If the design drives video output (it has `vsync`, `hsync`, and `rgb`
+ signals), `clk` and `reset`
+
+Multi-bit signals will display their hex or decimal values on top of the waveforms when zoomed in.
+
+## Mouse actions
+
+- **Click** on the trace to move the selection cursor to that clock.
+- **Click and drag** to scrub through the trace.
+- **Scroll horizontally** to pan left/right.
+- For input signals (other than `clk` or `reset`) **click** its row to change its
+ value at the current clock.
diff --git a/src/ide/ui.ts b/src/ide/ui.ts
index 895533b8..2eb9ee49 100644
--- a/src/ide/ui.ts
+++ b/src/ide/ui.ts
@@ -30,7 +30,7 @@ import { AssetEditorView } from "./views/asseteditor";
import { isMobileDevice } from "./views/baseviews";
import { AddressHeatMapView, BinaryFileView, BreakpointsView, MemoryMapView, MemoryView, ProbeLogView, ProbeSymbolView, RasterStackMapView, ScanlineIOView, VRAMMemoryView } from "./views/debugviews";
import { DisassemblerView, HeaderView, ListingView, PC_LINE_LOOKAHEAD, SourceEditor, setUppercaseOnly } from "./views/editors";
-import { HELP_TOPICS, HelpView, helpTopicForView } from "./views/helpview";
+import { HELP_TOPICS, HelpView, elementHelpTopicForFocus, helpTopicForView } from "./views/helpview";
import { CallStackView, DebugBrowserView } from "./views/treeviews";
import { ProjectWindows } from "./windows";
import { setupSplits, showTab } from "./layout";
@@ -1861,8 +1861,11 @@ function setupDebugControls() {
// Going through the hash means Back returns to the previous view.
function showContextHelp() {
if (!projectWindows) return;
+ // widgets embedded outside ProjectWindows (e.g. the Verilog waveform
+ // viewer) register their own topic; prefer that when it has focus
+ var elId = elementHelpTopicForFocus();
var isEditor = projectWindows.getActive() instanceof SourceEditor;
- var id = helpTopicForView(projectWindows.getActiveID(), isEditor);
+ var id = elId || helpTopicForView(projectWindows.getActiveID(), isEditor);
var hash = '#help/' + id;
if (window.location.hash === hash) {
projectWindows.createOrShow(hash);
diff --git a/src/ide/views/debugviews.ts b/src/ide/views/debugviews.ts
index a68dbb50..91a6f61b 100644
--- a/src/ide/views/debugviews.ts
+++ b/src/ide/views/debugviews.ts
@@ -985,7 +985,7 @@ export class BreakpointsView implements ProjectView {
.attr('placeholder', 'address or symbol (e.g. $8000, mainloop)')
.val(editing && editing.bp.type == 'address' ? editing.bp.target : '');
const condInput = $('')
- .attr('placeholder', 'condition (e.g. A == $20, #scanline > 222)')
+ .attr('placeholder', 'condition (e.g. A>=$20, #scanline==222)')
.val(editing ? editing.bp.condition || '' : '');
const submit = $('').text(editing ? 'Save' : 'Add');
const cancel = $('').text('Cancel');
diff --git a/src/ide/views/helpview.ts b/src/ide/views/helpview.ts
index ce187207..da40b3c9 100644
--- a/src/ide/views/helpview.ts
+++ b/src/ide/views/helpview.ts
@@ -25,6 +25,7 @@ import buildDirectivesMd from "../../docs/build-directives.md";
import toolchainsMd from "../../docs/toolchains.md";
import assetHeadersMD from "../../docs/asset-headers.md";
import embeddingIdeMd from "../../docs/embedding-ide.md";
+import verilogWaveformMd from "../../docs/verilog-waveform.md";
// Help is a normal ProjectView so it reuses ProjectWindows (tabs, hash
// routing, the window list). The registry and renderHelpBody() below are
@@ -59,6 +60,7 @@ export const HELP_TOPICS: HelpTopic[] = [
{ id: "toolchains", title: "Toolchains & Platforms", html: toolchainsMd },
{ id: "asset-headers", title: "Asset Headers", html: assetHeadersMD },
{ id: "embedding-ide", title: "Embedding the IDE", html: embeddingIdeMd },
+ { id: "verilog-waveform", title: "Waveform Viewer", html: verilogWaveformMd },
];
const HELP_BY_ID: { [id: string]: HelpTopic } = {};
@@ -106,6 +108,29 @@ export function helpTopicForView(viewId: string, isEditor: boolean): string {
return (viewId && VIEW_HELP[viewId]) || "index";
}
+// Widgets embedded directly in a platform's UI (not a ProjectWindows tab,
+// e.g. the Verilog waveform viewer alongside the emulator screen) register
+// their container + topic id here so F1 can find them while focused.
+let elementHelpTopics: { div: HTMLElement; id: string }[] = [];
+
+export function registerElementHelpTopic(div: HTMLElement, id: string) {
+ elementHelpTopics.push({ div, id });
+}
+
+export function unregisterElementHelpTopic(div: HTMLElement) {
+ elementHelpTopics = elementHelpTopics.filter((eh) => eh.div !== div);
+}
+
+// topic id for the currently focused element-scoped widget, if any
+export function elementHelpTopicForFocus(): string | null {
+ const ae = document.activeElement;
+ if (!ae) return null;
+ for (const eh of elementHelpTopics) {
+ if (eh.div.contains(ae)) return eh.id;
+ }
+ return null;
+}
+
// Turn relative Markdown links ("foo.md") into internal help routes
// ("#help/foo") so clicks stay in the IDE. Absolute links open in a new tab.
function rewriteHelpLinks(root: HTMLElement) {
diff --git a/src/ide/waveform.ts b/src/ide/waveform.ts
index 9e5127a6..9acf9a3a 100644
--- a/src/ide/waveform.ts
+++ b/src/ide/waveform.ts
@@ -1,6 +1,7 @@
import { Toolbar } from "./toolbar";
import { registerElementShortcuts, Shortcut } from "./shortcutbar";
+import { registerElementHelpTopic } from "./views/helpview";
import { VirtualList } from "../common/vlist";
import DOMPurify from "dompurify";
@@ -54,6 +55,7 @@ export class WaveformView {
// bar's focus tracking (see shortcutbar.ts)
this.parent.addEventListener('mousedown', (e) => { e.preventDefault(); this.parent.focus(); });
registerElementShortcuts(this.parent, () => this.getShortcuts());
+ registerElementHelpTopic(this.parent, 'verilog-waveform');
this.recreate();
}