0hmX/am3352-ddr-track-a-local-dfm-wip-20261007
Experimental RJ45-corrected board with isolated PG indication. 1005/1005 source joins pass; 15 expanded-guard physical errors, sourcing and qualification gates remain. Not fabrication-ready.
- Version
- 0.0.14
- License
- unset
- Stars
- 0
simulations-next/ibis.circuit.tsx
import { analog } from "@tscircuit/core"
import { ImportedBoard } from "./saved-board"
import { resolveDdrChannel } from "./channels"
import { createDdrIbisModels, modelCornerSupplyV } from "./ibis-models"
/** Fixed PRBS7 sequence, repeated; this is a finite SI test, not a BER claim. */
function prbs7() {
let state = 0x7f
let bits = ""
for (let i = 0; i < 127; i++) {
bits += state & 1
state = (state >> 1) | (((state ^ (state >> 1)) & 1) << 6)
}
return bits
}
/** Native vendor-IBIS investigation declarations on the supplied routed PCB.
* The current routed-copper extractor retains selected GND only. This is not
* the full-copper Maxwell model and cannot establish actual-board DDR margin.
*/
export default function DdrIbisBoard({
circuitJson,
byte = 0,
dataSignal = `DDR_D${byte * 8}`,
direction = "write",
corner = "typical",
drive = "slow9mA",
ramOdt = "ODT_60",
uiNs = 1.5625,
}) {
const data = resolveDdrChannel(circuitJson, dataSignal)
const dqs = resolveDdrChannel(circuitJson, `DDR_DQS${byte}`)
const dqsn = resolveDdrChannel(circuitJson, `DDR_DQSn${byte}`)
const models = createDdrIbisModels({ byte, direction, corner, drive, ramOdt, ramDataPin: data.loadBall, cpuDataPin: data.sourceBall })
const channels = [data, dqs, dqsn]
const names = ["DQ", "DQS", "DQSn"]
const output = (channel) => direction === "write" ? channel.source : channel.load
const input = (channel) => direction === "write" ? channel.load : channel.source
const driverGround = direction === "write" ? ".U1 > .A1" : ".U3 > .B1"
const receiverGround = direction === "write" ? ".U3 > .B1" : ".U1 > .A1"
const bitDuration = `${uiNs}ns`
// Writes are center-aligned. Reads are edge-aligned and require PHY sampling shift.
const strobeStart = `${direction === "write" ? uiNs / 2 : 0}ns`
const channel = {
reduction: "routed-copper" as const,
sections: 12,
lanes: channels.map((route, i) => ({ name: names[i], from: output(route), to: input(route) })),
referencePinRef: driverGround,
extraction: {
minimumFrequency: "1Hz", maximumFrequency: "1GHz", modelFrequency: "100MHz",
filaments: 3, refinementFilaments: 5, convergenceTolerance: 0.05,
capacitanceTolerance: 0.02, reciprocityTolerance: 0.025,
dcResistanceTolerance: 0.002, maxPanelLength: "2mm", groundMeshSize: "3mm",
},
relativePermittivity: 4.1,
via: { platingThickness: "0.025mm", equivalentWidth: "0.1mm", omitThroughViaStubs: true },
}
const states = Object.fromEntries(channels.flatMap(route => [
[output(route), { isOutput: true, isOutputEnabled: true }],
[input(route), { isOutput: false }],
]))
return (
<ImportedBoard circuitJson={circuitJson} fabricatorPreset="jlcpcb_standard">
<ibismodel componentRef="chip.U1" {...models.cpu} />
<ibismodel componentRef="chip.U3" {...models.ram} />
<voltagesource name="DDR_VDDQ" voltage={`${modelCornerSupplyV[corner]}V`} connections={{ pin1: ".U1 > .E5", pin2: ".U1 > .A1" }} />
<voltageprobe name="DQ_RX" connectsTo={input(data)} referenceTo={receiverGround} />
<voltageprobe name="DQ_TX" connectsTo={output(data)} referenceTo={driverGround} />
<voltageprobe name="DQS_RX" connectsTo={input(dqs)} referenceTo={input(dqsn)} />
{(["QUIET", "SWITCHING"] as const).map(activity => {
const name = `BYTE${byte}_${direction.toUpperCase()}_${activity}`
const simulationRef = `.${name}`
return [
<analog.transientsimulation key={name} name={name} spiceEngine="pcb_spice"
duration="512ns" timePerStep="10ps" pcbSpiceChannel={channel} ibisPinStates={states} />,
<analog.digitalstimulus key={`${name}_DQ`} name={`${name}_DQ`} simulationRef={simulationRef}
sourcePinRef={output(data)} bitDuration={bitDuration} startTime="0ns" initialState={0}
transmittedData={{ transmissionType: "bits", bits: prbs7(), repeat: true }} />,
<analog.digitalstimulus key={`${name}_DQS`} name={`${name}_DQS`} simulationRef={simulationRef}
sourcePinRef={output(dqs)} bitDuration={bitDuration} startTime={strobeStart} initialState={0}
transmittedData={{ transmissionType: "bits", bits: activity === "QUIET" ? "0" : "01", repeat: true }} />,
<analog.digitalstimulus key={`${name}_DQSn`} name={`${name}_DQSn`} simulationRef={simulationRef}
sourcePinRef={output(dqsn)} bitDuration={bitDuration} startTime={strobeStart} initialState={0} inverted
transmittedData={{ transmissionType: "bits", bits: activity === "QUIET" ? "0" : "01", repeat: true }} />,
<analog.eyediagram key={`${name}_DQ_eye`} name={`${name}_DQ_eye`} simulationRef={simulationRef}
probeRef=".DQ_RX" unitInterval={bitDuration} timeOrigin="0ns" startTime="40ns" />,
<analog.eyediagram key={`${name}_DQS_eye`} name={`${name}_DQS_eye`} simulationRef={simulationRef}
probeRef=".DQS_RX" unitInterval={bitDuration} timeOrigin={strobeStart} startTime="40ns" />,
]
})}
</ImportedBoard>
)
}