mirror of
https://github.com/litruv/picoGraph.git
synced 2026-07-24 10:46:06 +10:00
Initial commit
moved from private version control
This commit is contained in:
67
scripts/nodes/library/memory/cstore.js
Normal file
67
scripts/nodes/library/memory/cstore.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Copies data from base RAM to cartridge ROM using cstore.
|
||||
*/
|
||||
export const memoryCstoreNode = createNodeModule(
|
||||
{
|
||||
id: "memory_cstore",
|
||||
title: "Store To Cart",
|
||||
category: "Memory",
|
||||
description:
|
||||
"Copy base RAM into cart ROM, optionally targeting another cartridge.",
|
||||
searchTags: ["cstore", "memory", "cart", "save"],
|
||||
inputs: [
|
||||
{ id: "exec_in", name: "Exec", direction: "input", kind: "exec" },
|
||||
{
|
||||
id: "dest",
|
||||
name: "Dest",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "source",
|
||||
name: "Source",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "length",
|
||||
name: "Length",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "filename",
|
||||
name: "Filename",
|
||||
direction: "input",
|
||||
kind: "string",
|
||||
description: "Optional cartridge filename",
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "exec_out", name: "Exec", direction: "output", kind: "exec" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
emitExec: ({ indent, indentLevel, resolveValueInput, emitNextExec }) => {
|
||||
const OMIT = "__pg_omit__";
|
||||
const dest = resolveValueInput("dest", "0");
|
||||
const source = resolveValueInput("source", "0");
|
||||
const length = resolveValueInput("length", "0");
|
||||
const filename = resolveValueInput("filename", OMIT);
|
||||
|
||||
const args = [dest, source, length];
|
||||
if (filename !== OMIT) {
|
||||
args.push(filename);
|
||||
}
|
||||
|
||||
const line = `${indent(indentLevel)}cstore(${args.join(", ")})`;
|
||||
return [line, ...emitNextExec("exec_out")];
|
||||
},
|
||||
}
|
||||
);
|
||||
43
scripts/nodes/library/memory/index.js
Normal file
43
scripts/nodes/library/memory/index.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { memoryPeekNode } from "./peek.js";
|
||||
import { memoryPeek2Node } from "./peek2.js";
|
||||
import { memoryPeek4Node } from "./peek4.js";
|
||||
import { memoryPokeNode } from "./poke.js";
|
||||
import { memoryPoke2Node } from "./poke2.js";
|
||||
import { memoryPoke4Node } from "./poke4.js";
|
||||
import { memoryMemcpyNode } from "./memcpy.js";
|
||||
import { memoryMemsetNode } from "./memset.js";
|
||||
import { memoryReloadNode } from "./reload.js";
|
||||
import { memoryCstoreNode } from "./cstore.js";
|
||||
|
||||
/**
|
||||
* All memory-related node modules backed by PICO-8 helpers.
|
||||
*/
|
||||
export const memoryNodes = [
|
||||
memoryPeekNode,
|
||||
memoryPeek2Node,
|
||||
memoryPeek4Node,
|
||||
memoryPokeNode,
|
||||
memoryPoke2Node,
|
||||
memoryPoke4Node,
|
||||
memoryMemcpyNode,
|
||||
memoryMemsetNode,
|
||||
memoryReloadNode,
|
||||
memoryCstoreNode,
|
||||
];
|
||||
|
||||
/**
|
||||
* Checklist tracking coverage of documented memory helpers.
|
||||
* @type {Array<{ function: string, nodeId: string, implemented: boolean }>}
|
||||
*/
|
||||
export const memoryFunctionChecklist = [
|
||||
{ function: "PEEK", nodeId: "memory_peek", implemented: true },
|
||||
{ function: "PEEK2", nodeId: "memory_peek2", implemented: true },
|
||||
{ function: "PEEK4", nodeId: "memory_peek4", implemented: true },
|
||||
{ function: "POKE", nodeId: "memory_poke", implemented: true },
|
||||
{ function: "POKE2", nodeId: "memory_poke2", implemented: true },
|
||||
{ function: "POKE4", nodeId: "memory_poke4", implemented: true },
|
||||
{ function: "MEMCPY", nodeId: "memory_memcpy", implemented: true },
|
||||
{ function: "MEMSET", nodeId: "memory_memset", implemented: true },
|
||||
{ function: "RELOAD", nodeId: "memory_reload", implemented: true },
|
||||
{ function: "CSTORE", nodeId: "memory_cstore", implemented: true },
|
||||
];
|
||||
51
scripts/nodes/library/memory/memcpy.js
Normal file
51
scripts/nodes/library/memory/memcpy.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Copies memory regions using memcpy.
|
||||
*/
|
||||
export const memoryMemcpyNode = createNodeModule(
|
||||
{
|
||||
id: "memory_memcpy",
|
||||
title: "Copy Memory",
|
||||
category: "Memory",
|
||||
description: "Copy a block of memory within base RAM.",
|
||||
searchTags: ["memcpy", "memory", "copy", "block"],
|
||||
inputs: [
|
||||
{ id: "exec_in", name: "Exec", direction: "input", kind: "exec" },
|
||||
{
|
||||
id: "dest",
|
||||
name: "Dest",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "source",
|
||||
name: "Source",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "length",
|
||||
name: "Length",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "exec_out", name: "Exec", direction: "output", kind: "exec" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
emitExec: ({ indent, indentLevel, resolveValueInput, emitNextExec }) => {
|
||||
const dest = resolveValueInput("dest", "0");
|
||||
const source = resolveValueInput("source", "0");
|
||||
const length = resolveValueInput("length", "0");
|
||||
const line = `${indent(indentLevel)}memcpy(${dest}, ${source}, ${length})`;
|
||||
return [line, ...emitNextExec("exec_out")];
|
||||
},
|
||||
}
|
||||
);
|
||||
51
scripts/nodes/library/memory/memset.js
Normal file
51
scripts/nodes/library/memory/memset.js
Normal file
@@ -0,0 +1,51 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Fills memory with a value using memset.
|
||||
*/
|
||||
export const memoryMemsetNode = createNodeModule(
|
||||
{
|
||||
id: "memory_memset",
|
||||
title: "Fill Memory",
|
||||
category: "Memory",
|
||||
description: "Fill a region of base RAM with a repeated value.",
|
||||
searchTags: ["memset", "memory", "fill"],
|
||||
inputs: [
|
||||
{ id: "exec_in", name: "Exec", direction: "input", kind: "exec" },
|
||||
{
|
||||
id: "dest",
|
||||
name: "Dest",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "value",
|
||||
name: "Value",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "length",
|
||||
name: "Length",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "exec_out", name: "Exec", direction: "output", kind: "exec" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
emitExec: ({ indent, indentLevel, resolveValueInput, emitNextExec }) => {
|
||||
const dest = resolveValueInput("dest", "0");
|
||||
const value = resolveValueInput("value", "0");
|
||||
const length = resolveValueInput("length", "0");
|
||||
const line = `${indent(indentLevel)}memset(${dest}, ${value}, ${length})`;
|
||||
return [line, ...emitNextExec("exec_out")];
|
||||
},
|
||||
}
|
||||
);
|
||||
45
scripts/nodes/library/memory/peek.js
Normal file
45
scripts/nodes/library/memory/peek.js
Normal file
@@ -0,0 +1,45 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Reads bytes from base RAM using PICO-8's peek helper.
|
||||
*/
|
||||
export const memoryPeekNode = createNodeModule(
|
||||
{
|
||||
id: "memory_peek",
|
||||
title: "Peek Memory",
|
||||
category: "Memory",
|
||||
description: "Read a byte or sequence of bytes from base RAM.",
|
||||
searchTags: ["peek", "memory", "read"],
|
||||
inputs: [
|
||||
{
|
||||
id: "address",
|
||||
name: "Address",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "count",
|
||||
name: "Count",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
description: "Optional number of bytes to read",
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "value", name: "Value", direction: "output", kind: "number" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
evaluateValue: ({ resolveValueInput }) => {
|
||||
const OMIT = "__pg_omit__";
|
||||
const address = resolveValueInput("address", "0");
|
||||
const count = resolveValueInput("count", OMIT);
|
||||
if (count === OMIT) {
|
||||
return `peek(${address})`;
|
||||
}
|
||||
return `peek(${address}, ${count})`;
|
||||
},
|
||||
}
|
||||
);
|
||||
33
scripts/nodes/library/memory/peek2.js
Normal file
33
scripts/nodes/library/memory/peek2.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Reads a 16-bit little-endian value using peek2.
|
||||
*/
|
||||
export const memoryPeek2Node = createNodeModule(
|
||||
{
|
||||
id: "memory_peek2",
|
||||
title: "Peek16 Memory",
|
||||
category: "Memory",
|
||||
description: "Read a 16-bit little-endian value from base RAM.",
|
||||
searchTags: ["peek2", "memory", "read", "16-bit"],
|
||||
inputs: [
|
||||
{
|
||||
id: "address",
|
||||
name: "Address",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "value", name: "Value", direction: "output", kind: "number" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
evaluateValue: ({ resolveValueInput }) => {
|
||||
const address = resolveValueInput("address", "0");
|
||||
return `peek2(${address})`;
|
||||
},
|
||||
}
|
||||
);
|
||||
33
scripts/nodes/library/memory/peek4.js
Normal file
33
scripts/nodes/library/memory/peek4.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Reads a 32-bit little-endian value using peek4.
|
||||
*/
|
||||
export const memoryPeek4Node = createNodeModule(
|
||||
{
|
||||
id: "memory_peek4",
|
||||
title: "Peek32 Memory",
|
||||
category: "Memory",
|
||||
description: "Read a 32-bit little-endian value from base RAM.",
|
||||
searchTags: ["peek4", "memory", "read", "32-bit"],
|
||||
inputs: [
|
||||
{
|
||||
id: "address",
|
||||
name: "Address",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "value", name: "Value", direction: "output", kind: "number" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
evaluateValue: ({ resolveValueInput }) => {
|
||||
const address = resolveValueInput("address", "0");
|
||||
return `peek4(${address})`;
|
||||
},
|
||||
}
|
||||
);
|
||||
67
scripts/nodes/library/memory/poke.js
Normal file
67
scripts/nodes/library/memory/poke.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Writes one or more bytes to base RAM using poke.
|
||||
*/
|
||||
export const memoryPokeNode = createNodeModule(
|
||||
{
|
||||
id: "memory_poke",
|
||||
title: "Poke Memory",
|
||||
category: "Memory",
|
||||
description: "Write sequential bytes to base RAM.",
|
||||
searchTags: ["poke", "memory", "write"],
|
||||
inputs: [
|
||||
{ id: "exec_in", name: "Exec", direction: "input", kind: "exec" },
|
||||
{
|
||||
id: "address",
|
||||
name: "Address",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "value",
|
||||
name: "Value",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "exec_out", name: "Exec", direction: "output", kind: "exec" },
|
||||
],
|
||||
properties: [
|
||||
{
|
||||
key: "extraValues",
|
||||
label: "Additional Values",
|
||||
type: "string",
|
||||
placeholder: "e.g. 0x10, 0x11",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
emitExec: ({
|
||||
node,
|
||||
indent,
|
||||
indentLevel,
|
||||
resolveValueInput,
|
||||
emitNextExec,
|
||||
}) => {
|
||||
const address = resolveValueInput("address", "0");
|
||||
const value = resolveValueInput("value", "0");
|
||||
const args = [address, value];
|
||||
|
||||
const extras = String(node.properties.extraValues ?? "").trim();
|
||||
if (extras.length) {
|
||||
extras
|
||||
.split(",")
|
||||
.map((entry) => entry.trim())
|
||||
.filter((entry) => entry.length > 0)
|
||||
.forEach((entry) => args.push(entry));
|
||||
}
|
||||
|
||||
const line = `${indent(indentLevel)}poke(${args.join(", ")})`;
|
||||
return [line, ...emitNextExec("exec_out")];
|
||||
},
|
||||
}
|
||||
);
|
||||
43
scripts/nodes/library/memory/poke2.js
Normal file
43
scripts/nodes/library/memory/poke2.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Writes a 16-bit little-endian value using poke2.
|
||||
*/
|
||||
export const memoryPoke2Node = createNodeModule(
|
||||
{
|
||||
id: "memory_poke2",
|
||||
title: "Poke16 Memory",
|
||||
category: "Memory",
|
||||
description: "Write a 16-bit little-endian value to base RAM.",
|
||||
searchTags: ["poke2", "memory", "write", "16-bit"],
|
||||
inputs: [
|
||||
{ id: "exec_in", name: "Exec", direction: "input", kind: "exec" },
|
||||
{
|
||||
id: "address",
|
||||
name: "Address",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "value",
|
||||
name: "Value",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "exec_out", name: "Exec", direction: "output", kind: "exec" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
emitExec: ({ indent, indentLevel, resolveValueInput, emitNextExec }) => {
|
||||
const address = resolveValueInput("address", "0");
|
||||
const value = resolveValueInput("value", "0");
|
||||
const line = `${indent(indentLevel)}poke2(${address}, ${value})`;
|
||||
return [line, ...emitNextExec("exec_out")];
|
||||
},
|
||||
}
|
||||
);
|
||||
43
scripts/nodes/library/memory/poke4.js
Normal file
43
scripts/nodes/library/memory/poke4.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Writes a 32-bit little-endian value using poke4.
|
||||
*/
|
||||
export const memoryPoke4Node = createNodeModule(
|
||||
{
|
||||
id: "memory_poke4",
|
||||
title: "Poke32 Memory",
|
||||
category: "Memory",
|
||||
description: "Write a 32-bit little-endian value to base RAM.",
|
||||
searchTags: ["poke4", "memory", "write", "32-bit"],
|
||||
inputs: [
|
||||
{ id: "exec_in", name: "Exec", direction: "input", kind: "exec" },
|
||||
{
|
||||
id: "address",
|
||||
name: "Address",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "value",
|
||||
name: "Value",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "exec_out", name: "Exec", direction: "output", kind: "exec" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
emitExec: ({ indent, indentLevel, resolveValueInput, emitNextExec }) => {
|
||||
const address = resolveValueInput("address", "0");
|
||||
const value = resolveValueInput("value", "0");
|
||||
const line = `${indent(indentLevel)}poke4(${address}, ${value})`;
|
||||
return [line, ...emitNextExec("exec_out")];
|
||||
},
|
||||
}
|
||||
);
|
||||
67
scripts/nodes/library/memory/reload.js
Normal file
67
scripts/nodes/library/memory/reload.js
Normal file
@@ -0,0 +1,67 @@
|
||||
import { createNodeModule } from "../../nodeTypes.js";
|
||||
|
||||
/**
|
||||
* Copies data from cartridge ROM into base RAM using reload.
|
||||
*/
|
||||
export const memoryReloadNode = createNodeModule(
|
||||
{
|
||||
id: "memory_reload",
|
||||
title: "Reload Memory",
|
||||
category: "Memory",
|
||||
description:
|
||||
"Copy data from cart ROM into base RAM, optionally from another cart.",
|
||||
searchTags: ["reload", "memory", "copy", "rom"],
|
||||
inputs: [
|
||||
{ id: "exec_in", name: "Exec", direction: "input", kind: "exec" },
|
||||
{
|
||||
id: "dest",
|
||||
name: "Dest",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "source",
|
||||
name: "Source",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "length",
|
||||
name: "Length",
|
||||
direction: "input",
|
||||
kind: "number",
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
id: "filename",
|
||||
name: "Filename",
|
||||
direction: "input",
|
||||
kind: "string",
|
||||
description: "Optional cartridge filename",
|
||||
},
|
||||
],
|
||||
outputs: [
|
||||
{ id: "exec_out", name: "Exec", direction: "output", kind: "exec" },
|
||||
],
|
||||
properties: [],
|
||||
},
|
||||
{
|
||||
emitExec: ({ indent, indentLevel, resolveValueInput, emitNextExec }) => {
|
||||
const OMIT = "__pg_omit__";
|
||||
const dest = resolveValueInput("dest", "0");
|
||||
const source = resolveValueInput("source", "0");
|
||||
const length = resolveValueInput("length", "0");
|
||||
const filename = resolveValueInput("filename", OMIT);
|
||||
|
||||
const args = [dest, source, length];
|
||||
if (filename !== OMIT) {
|
||||
args.push(filename);
|
||||
}
|
||||
|
||||
const line = `${indent(indentLevel)}reload(${args.join(", ")})`;
|
||||
return [line, ...emitNextExec("exec_out")];
|
||||
},
|
||||
}
|
||||
);
|
||||
Reference in New Issue
Block a user