diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml deleted file mode 100644 index cba9134..0000000 --- a/.github/workflows/CompatHelper.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: CompatHelper -on: - schedule: - - cron: 0 0 * * * - workflow_dispatch: -jobs: - CompatHelper: - runs-on: ubuntu-latest - steps: - - name: Pkg.add("CompatHelper") - run: julia -e 'using Pkg; Pkg.add("CompatHelper")' - - name: CompatHelper.main() - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} - run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml deleted file mode 100644 index 634f90d..0000000 --- a/.github/workflows/TagBot.yml +++ /dev/null @@ -1,16 +0,0 @@ -name: TagBot -on: - issue_comment: - types: - - created - workflow_dispatch: -jobs: - TagBot: - if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' - runs-on: ubuntu-latest - steps: - - uses: JuliaRegistries/TagBot@v1 - with: - token: ${{ secrets.GITHUB_TOKEN }} - ssh: ${{ secrets.DOCUMENTER_KEY }} - \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index a034182..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,40 +0,0 @@ -name: CI -on: - push: - branches: - - master - tags: '*' - pull_request: -jobs: - test: - name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - version: - - '1' - os: - - ubuntu-latest - - macOS-latest - - windows-latest - arch: - - x64 - steps: - - uses: actions/checkout@v2 - - uses: julia-actions/setup-julia@v1 - with: - version: ${{ matrix.version }} - arch: ${{ matrix.arch }} - - uses: actions/cache@v1 - env: - cache-name: cache-artifacts - with: - path: ~/.julia/artifacts - key: ${{ runner.os }}-test-${{ env.cache-name }}-${{ hashFiles('**/Project.toml') }} - restore-keys: | - ${{ runner.os }}-test-${{ env.cache-name }}- - ${{ runner.os }}-test- - ${{ runner.os }}- - - uses: julia-actions/julia-buildpkg@latest - - uses: julia-actions/julia-runtest@latest \ No newline at end of file diff --git a/Manifest.toml b/Manifest.toml index f6d406d..ec4da10 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -1,197 +1,67 @@ # This file is machine-generated - editing it directly is not advised -[[ArgTools]] -uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" +julia_version = "1.12.6" +manifest_format = "2.0" +project_hash = "f8556de8ceff5f13bdaf89939adbdadb5282f7ec" -[[Artifacts]] +[[deps.Artifacts]] uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" +version = "1.11.0" -[[Base64]] -uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" +[[deps.DataStructures]] +deps = ["OrderedCollections"] +git-tree-sha1 = "6fb53a69613a0b2b68a0d12671717d307ab8b24e" +uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" +version = "0.19.5" -[[CEnum]] -git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9" -uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82" -version = "0.4.1" - -[[ColorTypes]] -deps = ["FixedPointNumbers", "Random"] -git-tree-sha1 = "024fe24d83e4a5bf5fc80501a314ce0d1aa35597" -uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" -version = "0.11.0" - -[[Colors]] -deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] -git-tree-sha1 = "417b0ed7b8b838aa6ca0a87aadf1bb9eb111ce40" -uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" -version = "0.12.8" - -[[Dates]] +[[deps.Dates]] deps = ["Printf"] uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" +version = "1.11.0" -[[Downloads]] -deps = ["ArgTools", "LibCURL", "NetworkOptions"] -uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" - -[[FixedPointNumbers]] -deps = ["Statistics"] -git-tree-sha1 = "335bfdceacc84c5cdf16aadc768aa5ddfc5383cc" -uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" -version = "0.8.4" - -[[InteractiveUtils]] -deps = ["Markdown"] -uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" - -[[JLLWrappers]] -deps = ["Preferences"] -git-tree-sha1 = "642a199af8b68253517b80bd3bfd17eb4e84df6e" +[[deps.JLLWrappers]] +deps = ["Artifacts", "Preferences"] +git-tree-sha1 = "7204148362dafe5fe6a273f855b8ccbe4df8173e" uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" -version = "1.3.0" - -[[LibCURL]] -deps = ["LibCURL_jll", "MozillaCACerts_jll"] -uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" - -[[LibCURL_jll]] -deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] -uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" - -[[LibGit2]] -deps = ["Base64", "NetworkOptions", "Printf", "SHA"] -uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" +version = "1.8.0" -[[LibSSH2_jll]] -deps = ["Artifacts", "Libdl", "MbedTLS_jll"] -uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" - -[[Libdl]] +[[deps.Libdl]] uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" +version = "1.11.0" -[[LinearAlgebra]] -deps = ["Libdl"] -uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" - -[[Logging]] -uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" - -[[Markdown]] -deps = ["Base64"] -uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" - -[[MbedTLS_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" +[[deps.NgHerb]] +deps = ["DataStructures", "ngspice_jll"] +path = "." +uuid = "16d751f2-2168-46b0-9d00-9e1470832ba3" +version = "0.2.1" -[[MozillaCACerts_jll]] -uuid = "14a3606d-f60d-562e-9121-12d972cd8159" +[[deps.OrderedCollections]] +git-tree-sha1 = "94ba93778373a53bfd5a0caaf7d809c445292ff4" +uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" +version = "1.8.2" -[[NetworkOptions]] -uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" - -[[Pkg]] -deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] -uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" - -[[Preferences]] +[[deps.Preferences]] deps = ["TOML"] -git-tree-sha1 = "ea79e4c9077208cd3bc5d29631a26bc0cff78902" +git-tree-sha1 = "8b770b60760d4451834fe79dd483e318eee709c4" uuid = "21216c6a-2e73-6563-6e65-726566657250" -version = "1.2.1" +version = "1.5.2" -[[Printf]] +[[deps.Printf]] deps = ["Unicode"] uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" +version = "1.11.0" -[[REPL]] -deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] -uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" - -[[Random]] -deps = ["Serialization"] -uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" - -[[RecipesBase]] -git-tree-sha1 = "b3fb709f3c97bfc6e948be68beeecb55a0b340ae" -uuid = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" -version = "1.1.1" - -[[Reexport]] -git-tree-sha1 = "57d8440b0c7d98fc4f889e478e80f268d534c9d5" -uuid = "189a3867-3050-52da-a836-e630ba90ab69" -version = "1.0.0" - -[[ReplMaker]] -deps = ["REPL", "Unicode"] -git-tree-sha1 = "76098218397ec93b925b70ce355144d539b1a8b4" -uuid = "b873ce64-0db9-51f5-a568-4457d8e49576" -version = "0.2.5" - -[[Requires]] -deps = ["UUIDs"] -git-tree-sha1 = "4036a3bd08ac7e968e27c203d45f5fff15020621" -uuid = "ae029012-a4dd-5104-9daa-d747884805df" -version = "1.1.3" - -[[SHA]] -uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" - -[[SafeTestsets]] -deps = ["Test"] -git-tree-sha1 = "36ebc5622c82eb9324005cc75e7e2cc51181d181" -uuid = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -version = "0.0.1" - -[[Serialization]] -uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" - -[[Sockets]] -uuid = "6462fe0b-24de-5631-8697-dd941f90decc" - -[[SparseArrays]] -deps = ["LinearAlgebra", "Random"] -uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" - -[[Statistics]] -deps = ["LinearAlgebra", "SparseArrays"] -uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" - -[[TOML]] +[[deps.TOML]] deps = ["Dates"] uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" +version = "1.0.3" -[[Tar]] -deps = ["ArgTools", "SHA"] -uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" - -[[Test]] -deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] -uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" - -[[UUIDs]] -deps = ["Random", "SHA"] -uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" - -[[Unicode]] +[[deps.Unicode]] uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" +version = "1.11.0" -[[Zlib_jll]] -deps = ["Libdl"] -uuid = "83775a58-1f1d-513f-b197-d71354ab007a" - -[[nghttp2_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" - -[[ngspice_jll]] -deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] -git-tree-sha1 = "02d25c1bad237d00e23208770c48da1d46f68de1" -repo-rev = "main" -repo-url = "https://github.com/JuliaBinaryWrappers/ngspice_jll.jl" +[[deps.ngspice_jll]] +deps = ["Artifacts", "JLLWrappers", "Libdl"] +git-tree-sha1 = "58c3dc3bb44dd7e74086c6dfc9fcd69b732b5162" uuid = "57e080ce-e004-5ece-a144-c95753423b2a" -version = "34.0.0+1" - -[[p7zip_jll]] -deps = ["Artifacts", "Libdl"] -uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" +version = "41.0.0+2" diff --git a/Project.toml b/Project.toml index af4a47a..cc3b534 100644 --- a/Project.toml +++ b/Project.toml @@ -1,28 +1,13 @@ -name = "NgSpice" -uuid = "1a64e563-3ad9-44a2-8713-a1728bea8a90" -authors = ["Venkateshprasad Bhat"] -version = "0.1.4" +name = "NgHerb" +uuid = "16d751f2-2168-46b0-9d00-9e1470832ba3" +version = "0.2.0" +authors = ["Chris Winstead", "Venkateshprasad Bhat"] [deps] -CEnum = "fa961155-64e5-5f13-b03f-caf6b980ea82" -Colors = "5ae59095-9a9b-59fe-a467-6f913c188581" -Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb" -RecipesBase = "3cdcf5f2-1ef4-517c-9805-6587b60abb01" -ReplMaker = "b873ce64-0db9-51f5-a568-4457d8e49576" -Requires = "ae029012-a4dd-5104-9daa-d747884805df" +DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" ngspice_jll = "57e080ce-e004-5ece-a144-c95753423b2a" -[compat] -CEnum = "0.4, 0.5" -Colors = "0.12" -RecipesBase = "1.1" -ReplMaker = "0.2" -Requires = "1.1" -julia = "1.5" - -[extras] -SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" -[targets] -test = ["Test", "SafeTestsets"] +[compat] +DataStructures = "0.19.5" +ngspice_jll = "41.0.0" diff --git a/README.md b/README.md index bf4c8f5..4358959 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,101 @@ -# NgSpice +# NgHerb.jl -- A Revision of NgSpice.jl -[![Stable](https://img.shields.io/badge/docs-stable-blue.svg)](https://JuliaComputing.github.io/NgSpice.jl/stable) -[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaComputing.github.io/NgSpice.jl/dev) -[![Build Status](https://github.com/JuliaComputing/NgSpice.jl/workflows/CI/badge.svg)](https://github.com/JuliaComputing/NgSpice.jl/actions) -[![Coverage](https://codecov.io/gh/JuliaComputing/NgSpice.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaComputing/NgSpice.jl) +This repository provides a Julia wrapper for `ngspice` shared C library. It's based on the +[NgSpice.jl](https://github.com/JuliaComputing/NgSpice.jl) Julia module by Venkateshprasad Bhat. +NgHerb.jl implements these changes: + +* Thread safety for `ngspice` callbacks, to resolve segfaults in Julia 1.12.6+ +* Removed unused callbacks +* Removed some REPL and Plot features for easier maintenance + +NgHerb.jl has some additional streamlining compared to NgSpice.jl + +The main purpose of this fork is to provide a minimal `ngspice` library wrapper that works stably with more recent +Julia versions. As of Julia 1.12.6, the upstream NgSpice.jl module is broken unless +Julia is constrained to one thread, i.e. `julia -t 1`. NgHerb.jl tries to fix this by +introducing a CircularBuffer to manage asynchronous output from the `ngspice`. I made a fork rather than +mess with NgSpice.jl directly, mainly because I'm not super confident about my solution. -This repository provides a Julia wrapper for NgSpice library. ## Usage: In a Julia REPL, ``` -] add https://github.com/JuliaComputing/NgSpice.jl -using NgSpice +] add https://github.com/cjwinstead/NgHerb.jl +using NgHerb ``` --- -To start an an interactive mode, +Upon initialization, you shold see a startup message from the `ngspice` library, something +like this: + ``` -using Plots -NgSpice.interactive() +****** +** ngspice-46 shared library +** Creation Date: Tue May 12 23:05:42 UTC 2026 +****** ``` -- Hit `~` for initializing the NgSpice +### Basic Functions -Run the Ngspice simulations commands!
-For example: -``` -source /filepath/netlist # without quotes -display # prints all vectors and constants -plot vector1 vector2 # plots the real part of vector by default -``` +To load a netlist and run analyses in `ngspice`, use: +* `NgHerb.load_netlist(String)` -- loads a netlist from a multi-line Julia String +* `NgHerb.cmd(String)` -- run an `ngspice` command. -*Note*: It is not necessary for `.cir` to be placed in `bin` folder as long as full path is specified. +To retrieve data from `ngspice`, use: -Additional to usual plot parameters, different modes of retrieval can be set with:
- `plot -x space seperated vectorlist`
- where `x` takes following modes: +* `NgHerb.getrealvec(String)` -- get the named vector +* `NgHerb.getmagnitudevec(String)` -- get the magnitude of a complex vector +* `NgHerb.getphasevec(String)` -- get the phase of a complex vector (radians) -| Modes | Description | -|---------|-------| -| -r, --real | Real part of vector| -| -i, --imaginary | Imaginary part of vector | -| -m, --magnitude | Magnitude of vector | -| -p, --phase | Phase of vector | ---- -For a non-interactive and more Julia-like experience checkout this [tutorial](tutorials\mosfet.jl). +```julia-repl +julia> netlist=""" +* Demo circuit + +V1 1 0 DC 1 +R1 1 2 1k +R2 2 0 2k + +.end +"""; + +julia> NgHerb.load_netlist(netlist) +Circuit: * Demo circuit + +julia> NgHerb.cmd("op") + +Doing analysis at TEMP = 27.000000 and TNOM = 27.000000 +Using SPARSE 1.3 as Direct Linear Solver +No. of Data Rows : 1 + +julia> NgHerb.cmd("print all"); + +v(1) = 1.000000e+00 +v(2) = 6.666667e-01 +v1#branch = -3.33333e-04 + +julia> NgHerb.getrealvec("2") +1-element Vector{Float64}: + 0.6666666666666666 -Additionally, to simulate a `complex_circuit.sp` file with multiple plotting statements, run -``` -using NgSpice -using Plots -source_sp("path/to/the/complex_circuit.sp") ``` + +## String Macros + +Some special strings are defined to conveniently interface with `ngspice`: + +* `ng"..."` -- shorthand for NgHerb.cmd() +* `vec"..."` -- returns the indicated vector (with name and type) + +These string types all return `Vector{Float64}`: + +* `real"..."` -- real part of the indicated `ngspice` vector +* `imag"..."` -- imaginary part of the indicated `ngspice` vector +* `magnitude"..."` -- complex magnitude of the indicated vector +* `phase"..."` -- complex phase (in degrees) +* `dB"..."` -- magnitude in dB20 +* `i"..."` -- real-valued branch current in the indicated voltage source + diff --git a/inputs/RC2.net b/inputs/RC2.net deleted file mode 100644 index e08dc85..0000000 --- a/inputs/RC2.net +++ /dev/null @@ -1,15 +0,0 @@ -* Spice netlister for gnetlist -R5 n4 n5 1k -V1 n0 0 dc 1 ac 2 pulse 0 1 10n 10n 100n 1u 2u -R4 n3 n4 1k -R3 n2 n3 5k -C5 n5 0 1n -R2 n1 n2 1K -C4 n4 0 1n -R1 n0 n1 1k -C3 n3 0 1n -C2 n2 0 1n -C1 n1 0 1n -I1 n5 0 DC 0.01mA -R6 0 n5 10k -.END \ No newline at end of file diff --git a/inputs/ac_ascii.cir b/inputs/ac_ascii.cir deleted file mode 100644 index f7f14a5..0000000 --- a/inputs/ac_ascii.cir +++ /dev/null @@ -1,8 +0,0 @@ -* simulation of RC2 -.control -set filetype=ascii -ac dec 100 10k 1000k - -write ac_ascii.raw -.endc -.include RC2.net \ No newline at end of file diff --git a/inputs/mosfet.cir b/inputs/mosfet.cir deleted file mode 100644 index 1d25d40..0000000 --- a/inputs/mosfet.cir +++ /dev/null @@ -1,23 +0,0 @@ -A Berkeley SPICE3 compatible circuit -* -* This circuit contains only Berkeley SPICE3 components. -* -* The circuit is an AC coupled transistor amplifier with -* a sinewave input at node "1", a gain of approximately -3.9, -* and output on node "coll". -* -.tran 1e-5 2e-3 -* -vcc vcc 0 12.0 -vin 1 0 0.0 ac 1.0 sin(0 1 1k) -ccouple 1 base 10uF -rbias1 vcc base 100k -rbias2 base 0 24k -q1 coll base emit generic -rcollector vcc coll 3.9k -remitter emit 0 1k -* -.probe v(emit) v(vcc) v(1) v(base) v(coll) vcc#branch vin#branch -.model generic npn -* -.end \ No newline at end of file diff --git a/inputs/vdiv.cir b/inputs/vdiv.cir deleted file mode 100644 index db5ae1f..0000000 --- a/inputs/vdiv.cir +++ /dev/null @@ -1,5 +0,0 @@ -voltage divider netlist -V1 in 0 1 -R1 in out 1k -R2 out 0 2k -.end \ No newline at end of file diff --git a/src/API/get_vector.jl b/src/API/get_vector.jl index 3995d8d..ad63169 100644 --- a/src/API/get_vector.jl +++ b/src/API/get_vector.jl @@ -1,12 +1,13 @@ function get_vector_info(vecname, maxlen=Int(maxintfloat())) + GC.enable(false) factor = 1.0 if occursin("*", vecname) factor, vecname = split(vecname, "*") factor = parse(Float64, factor) end - vec = ngGet_Vec_Info(vecname) + vec = ngGet_Vec_Info(vecname) # returns pVectorInfo vec != C_NULL || throw("Vector $(vecname) not found") - vecinfo = unsafe_load(vec) + vecinfo = unsafe_load(vec) # vecinfo should be a VectorInfo vname = unsafe_string(vecinfo.name) len = min(maxlen, vecinfo.length) typelist = Dict(0 => "notype", @@ -43,6 +44,7 @@ function get_vector_info(vecname, maxlen=Int(maxintfloat())) else error("Unknown vector type") end + GC.enable(true) end function curplot() @@ -97,7 +99,7 @@ function getmagnitudevec(name, maxlen=Int(maxintfloat())) abs.(data) end -function getphasevec(name, maxlen=Int(maxintfloat)) +function getphasevec(name, maxlen=Int(maxintfloat())) _, __, data = get_vector_info(name, maxlen) angle.(data) end diff --git a/src/API/graphs.jl b/src/API/graphs.jl deleted file mode 100644 index 49b020f..0000000 --- a/src/API/graphs.jl +++ /dev/null @@ -1,72 +0,0 @@ -using RecipesBase -using Colors -using .Plots - -struct NgSpiceGraphs end - -const graph = NgSpiceGraphs() - -# `fort` is frequency or time vector. It is the `X` axis and should always be real. -@recipe function ng(::NgSpiceGraphs, vectype, fort, veclist, title, xlims=nothing) - ft = getrealvec(fort) - label := permutedims(veclist) - grid := true - title := "$title" - background_color --> Colors.RGB(0.0, 0.0, 0.0) - xguide := fort - guide := length(veclist) > 1 ? "signals" : "signal" - color_palette --> :default - seriestype := :path - overwrite_figure := false - vec = vectype.(veclist) - #isa(xlims, Nothing) || xlims := xlims - ft, vec -end - -# source function for sp files needs to specially process plot commands -function source_sp(netpath) - netlines = readlines(netpath) - circpath = joinpath(pwd(), "net.cir") - for l in range(1, stop=length(netlines)) - if netlines[l] == ".control" - open(circpath, "a") do f - for line in netlines[1:l-1] - write(f, line*"\n") - end - end - try source(circpath) catch; rm(circpath) end - temp = l - while netlines[temp+1] != ".endc" - temp += 1 - try - if occursin("plot", netlines[temp]) - _plotswitch(netlines[temp]) - else - cmd(netlines[temp]) - end - catch - isfile(circpath) && rm(circpath) - end - end - end - end - isfile(circpath) && rm(circpath) -end - -function _plotswitch(pltstr) - params = split(pltstr[6:end], " ") - xlims = nothing - xlim_index = findall(occursin.("xlim", params)) - length(xlim_index) == 0 || (xlim_index = xlim_index[1]; xlims = parse.(Float64, (params[xlim_index+1], params[xlim_index+2])); - deleteat!(params, xlim_index:1:xlim_index+2)) - fort = "frequency" ∈ listcurvecs() ? "frequency" : "time" - pushfirst!(params, fort) - if !occursin("-", params[1]) plt = plot(graph, getrealvec, params[1], params[2:end], "Real plot", xlims) - elseif params[1] ∈ ("--real", "-r") plt = plot(graph, getrealvec, params[2], params[3:end], "Real plot", xlims) - elseif params[1] ∈ ("--imaginary", "-i") plt = plot(graph, getimagvec, params[2], params[3:end], "Imaginary plot", xlims) - elseif params[1] ∈ ("--magnitude", "-m") plt = plot(graph, getmagnitudevec, params[2], params[3:end], "Magnitude plot", xlims) - elseif params[1] ∈ ("--phase", "-p") plt = plot(graph, getphasevec, params[2], params[3:end], "Phase plot", xlims) - else throw("$(params[1]) is not a valid plot type") - end - Base.display(plt) -end diff --git a/src/API/repl.jl b/src/API/repl.jl deleted file mode 100644 index ec310e0..0000000 --- a/src/API/repl.jl +++ /dev/null @@ -1,29 +0,0 @@ -using ReplMaker -using .Plots - -function _ngspice_parser(str) - if str == "init" init() - elseif occursin("plot", str) - _plotswitch(str) - else - cmd(str) - end -end - -function _repl_parser(str) - if occursin(".sp", str) && str[1:7] == "source " - source_sp(str[8:end]) - else - _ngspice_parser(str) - end -end - -interactive() = (init(); - initrepl(_repl_parser, - prompt_text = "NgSpice> ", - prompt_color = :yellow, - start_key = '~', - mode_name = "for NgSpice is", - )) - - \ No newline at end of file diff --git a/src/API/running.jl b/src/API/running.jl index 75237b4..935f556 100644 --- a/src/API/running.jl +++ b/src/API/running.jl @@ -1,34 +1,24 @@ -cmd(command) = ngSpice_Command(command) -function init() - pvoid = convert(Ptr{Nothing}, 0) - ngSpice_Init(gen_psendchar(), gen_psendstat(), - gen_pcontrolledexit(), - gen_psenddata(), - gen_psendinitdata(), - gen_pbgthread(), pvoid) - ngSpice_Init_JLExtensions( - @cfunction(path_resolve, Cstring, (Cstring, Cstring)) - ) - -end -isrunning() = ngSpice_running() # always returns 0 +function cmd(command::String) + global quiet + GC.enable(false) + ngSpice_Command(command) + if !quiet + dumpbuffer() + end +end +precompile(cmd,(String,)) -run() = (println("Running the simulator"); cmd("run")) -bgrun() = (println("Running the simulator in a background thread"); - cmd("bg_run")) -set_breakpoint(bkpt::Float64) = ngSpice_SetBkpt(bkpt) - -stop() = (println("Stopping the simulator"); cmd("stop")) -bghalt() = (println("Halting the simulator in a background thread"); - cmd("bg_halt")) +function init() + GC.enable(false) + ngSpice_Init(gen_psendchar[], gen_psendstat[], + gen_pcontrolledexit[], + gen_psenddata[], + gen_psendinitdata[], + gen_pbgthread[], C_NULL) -reset() = (println("Resetting the simulator"); cmd("reset")) -resume() = (println("Resuming the simulator"); cmd("resume")) +end -alter(command::String) = cmd(string("alter ", command)) -quit() = cmd("quit") -exit() = (println("Quitting immediately"); cmd("unset askquit"); cmd("quit")) diff --git a/src/API/sim_utils.jl b/src/API/sim_utils.jl index 8db6c14..a188188 100644 --- a/src/API/sim_utils.jl +++ b/src/API/sim_utils.jl @@ -1,17 +1,23 @@ -function load_netlist(netlist::AbstractArray{T}) where T <: AbstractString - append!(netlist, ["C_NULL"]) - t = netlist |> ngSpice_Circ -end + function load_netlist(netlist::Vector{String}) + append!(netlist, ["C_NULL"]) + t = netlist |> ngSpice_Circ + end -function load_netlist(netlist::AbstractString) - # The strings in Julia always use \n instead of \r \r\n - # (even if the editor does). - # But if the circuit-string has \r in it, - # uncomment the following line - # occursin("\r", netlist) && replace(netlist, "\r"=>"") - load_netlist(split(netlist, "\n")) +# Opted to use the "circbyline" approach here to reduce +# memory crossover events between Julia and NgSpice. +function load_netlist(netlist::String) + for line in eachsplit(netlist,"\n") + if contains(line,r"\w+") + cmd(string("circbyline ",line)) + end + end + if !contains(lowercase(netlist),r"\.end\s*$") + cmd("circbyline .end") + end end +precompile(load_netlist,(String,)) +precompile(load_netlist,(Vector{String},)) -source(netpath) = cmd("source $netpath") +source(netpath::String) = cmd("source $netpath") display() = cmd("display") diff --git a/src/NgHerb.jl b/src/NgHerb.jl new file mode 100644 index 0000000..5bc2246 --- /dev/null +++ b/src/NgHerb.jl @@ -0,0 +1,139 @@ +__precompile__() +module NgHerb + +using ngspice_jll +export ngspice_jll + +using DataStructures + +include("interface/ngspice_common.jl") +include("interface/callbacks.jl") +include("interface/ngspice_api.jl") +include("API/sim_utils.jl") +include("API/running.jl") +include("API/get_vector.jl") + +#const async_cond = Ref{Base.AsyncCondition}() +string_buffer = CircularBuffer{UInt8}(10000) + +# Callback pointers +const gen_psendchar = Ref{Ptr{Cvoid}}(C_NULL) +const gen_pcontrolledexit = Ref{Ptr{Cvoid}}(C_NULL) + +const gen_psendstat = Ref{Ptr{Cvoid}}(C_NULL) +const gen_pbgthread = Ref{Ptr{Cvoid}}(C_NULL) +const gen_psenddata = Ref{Ptr{Cvoid}}(C_NULL) +const gen_psendinitdata = Ref{Ptr{Cvoid}}(C_NULL) + +pcbvec = Vector{Ref}() +cbvec = Vector{Function}() +quiet = false + +data_pointer = Ptr{VecInfoAll}(0) + +function __init__() + + # async_cond[] = Base.AsyncCondition() + + # We will just need these callbacks: + gen_psendchar[] = @cfunction(sendchar, Cint, (Ptr{Cchar}, Cint, Ptr{Cvoid} )) + gen_pcontrolledexit[] = @cfunction(controlledexit, Cint, (Cint, Cint, Cint, Cint, Ptr{Cvoid})) + + for x in (gen_psendchar, gen_pcontrolledexit) + push!(pcbvec,x) + end + + for x in (sendchar,controlledexit) + push!(cbvec,x) + end + + +# callback_listener() + init() +end + +function be_quiet() + global quiet = true +end + + +function dumpbuffer() + # Dump contents from ring buffer + buf_str = String(collect(string_buffer)) + empty!(string_buffer) + + # Remove "stdout " from start of lines + io=IOBuffer() + for l in eachsplit(buf_str,"\n") + println(io,replace(l,r"^stdout "=>"")) + end + + # Print everything + println(String(take!(seekstart(io)))) +end + + +#= +function callback_listener() + @async begin + try + while isopen(async_cond[]) + wait(async_cond[]) + #dumpbuffer() + GC.enable(true) + end + catch err + @error "Error in AsyncCondition processing loop" exception=(err, catch_backtrace()) + end + end +end +=# + +#================ Special Strings =====================# +# ng"" sends the quoted command to the simulator +macro ng_str(s) + NgHerb.cmd(s) +end + +# real"" retrieves the real-valued part of the indicated vector +macro real_str(s) + NgHerb.getrealvec(s) +end + +# imag"" retrieves the imaginary-valued part of the indicated vector +macro imag_str(s) + NgHerb.getimaginaryvec(s) +end + +# i"" retrieves the current in the indicated voltage source +macro i_str(s) + NgHerb.getrealvec(s*"#branch") +end + +# magnitude"" retrieves the complex magnitude of the indicated vector +macro magnitude_str(s) + NgHerb.getmagnitudevec(s) +end + +# dB"" retrieves a magnitude vector and converts to dB20 +macro dB_str(s) + 20.0 .* log10.(NgHerb.getmagnitudevec(s)) +end + +# phase"" retrieves a phase vector and converts to degrees +macro phase_str(s) + (180/π).*NgHerb.getphasevec(s) +end + +# vec"" returns a vector, possibly complex +macro vec_str(s) + NgHerb.getvec(s) +end + + + + +export @ng_str, @real_str, @imag_str, @i_str, @magnitude_str, @dB_str, @phase_str, @vec_str +export dump_buffer,be_quiet + +end diff --git a/src/NgSpice.jl b/src/NgSpice.jl deleted file mode 100644 index b68b822..0000000 --- a/src/NgSpice.jl +++ /dev/null @@ -1,51 +0,0 @@ -__precompile__() -module NgSpice - -using ngspice_jll -export ngspice_jll - -using Requires - -include("interface/ctypes.jl") -export Ctm, Ctime_t, Cclock_t - -include("interface/ngspice_common.jl") -include("interface/ngspice_api.jl") - -export bgthreadrunning, controlledexit, #getISRCdata, detsyncdata, getVSRCdata, - sendchar, senddata, sendstat, sendinitdata - -export gen_pbgthread, gen_pcontrolledexit, gen_psendchar, gen_psenddata, - gen_psendinitdata, gen_psendstat - -foreach(names(@__MODULE__, all=true)) do s - if startswith(string(s), "ng") - @eval export $s - end -end #should this be replaced with aliases - -include("extensions.jl") - -include("API/get_vector.jl") -include("API/sim_utils.jl") -include("API/running.jl") - -function __init__() - @require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" @eval include("API/repl.jl") - @require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" @eval include("API/graphs.jl") - - # Ensure that NgSpice is initialized, as otherwise it's easy to get segfaults - # because NgSpice expects a printf callback to be provided (as we do in the - # init() method we're calling here) - init() -end - -export get_vector_info, - curplot, listallplots, listallvecs, listcurvecs, getimagvec, - getmagnitudevec, getphasevec, getvec, getrealvec, - NgSpiceGraphs, graph, - load_netlist, source, source_sp, - bghalt, bgrun, cmd, init, - interactive, alter - #isrunning, -end diff --git a/src/extensions.jl b/src/extensions.jl deleted file mode 100644 index f5bfb8f..0000000 --- a/src/extensions.jl +++ /dev/null @@ -1,30 +0,0 @@ -const JLPATH_PREFIX = "jlpkg:" - -function c_strdup(str) - ptr = @ccall libngspice.tmalloc((sizeof(str)+1)::Cint)::Ptr{UInt8} - @GC.preserve str Base.unsafe_copyto!(ptr, pointer(str), sizeof(str)) - unsafe_store!(ptr, UInt8(0), sizeof(str) + 1) - ptr -end - -function path_resolve(name::Cstring, dir::Cstring)::Cstring - name = unsafe_string(name) - dir = unsafe_string(dir) - - if startswith(name, JLPATH_PREFIX) - path = name[sizeof(JLPATH_PREFIX)+1:end] - components = splitpath(path) - - @assert components[1] != "/" - - pkg_path = Base.locate_package(Base.PkgId(components[1])) - if pkg_path !== nothing - pkg_path = realpath(joinpath(dirname(pkg_path), "..")) - file_path = joinpath(pkg_path, components[2:end]...) - return c_strdup(file_path) - end - - return Ptr{Cchar}(-1) - end - return C_NULL -end diff --git a/src/interface/callbacks.jl b/src/interface/callbacks.jl new file mode 100644 index 0000000..9eb635b --- /dev/null +++ b/src/interface/callbacks.jl @@ -0,0 +1,21 @@ +function sendchar(_text::Ptr{Cchar}, id::Cint, userdata::Ptr{Cvoid})::Cint + copy_len = ccall(:strlen, Csize_t, (Ptr{Cchar},), _text) + for c in 1:copy_len + push!(string_buffer,unsafe_load(_text,c)) + end + push!(string_buffer,'\n') + + #ccall(:uv_async_send, Cint, (Ptr{Cvoid},), async_cond[].handle) + return zero(Int32) +end +precompile(sendchar,(Ptr{Cchar},Cint,Ptr{Cvoid})) + + + +function controlledexit(exitstatus::Cint, immediate::Cint, quitexit::Cint, id::Cint, userdata::Ptr{Cvoid})::Cint + quitexit == 1 && println("Returned from quit with exit status") + return exitstatus +end + + + diff --git a/src/interface/ctypes.jl b/src/interface/ctypes.jl deleted file mode 100644 index 436e6ad..0000000 --- a/src/interface/ctypes.jl +++ /dev/null @@ -1,7 +0,0 @@ -## TODO: pending https://github.com/JuliaLang/julia/issues/29420 -# this one is suggested in the issue, but it looks like time_t and tm are two different things? -# const Ctime_t = Base.Libc.TmStruct - -const Ctm = Base.Libc.TmStruct -const Ctime_t = UInt -const Cclock_t = UInt diff --git a/src/interface/ngspice_api.jl b/src/interface/ngspice_api.jl index 8d7be04..c423295 100644 --- a/src/interface/ngspice_api.jl +++ b/src/interface/ngspice_api.jl @@ -2,36 +2,31 @@ function ngSpice_Init(printfcn, statfcn, ngexit, sdata, sinitdata, bgtrun, userD ccall((:ngSpice_Init, libngspice), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}), printfcn, statfcn, ngexit, sdata, sinitdata, bgtrun, userData) end -function ngSpice_Init_JLExtensions(path_resolve) - ret = try; - ccall((:ngSpice_Init_JLExtensions, libngspice), Cint, (Cint, Ptr{Cvoid},), - 1, path_resolve) - catch e; - @warn "Failed to initialize julia extensions. Some features may not work." - return false +#----------------------------------------------------------------- +# This implementation is really worried about thread safety, +# but maybe not altogether necessary? I assume the command +# string will be consumed rapidly by the receiving ccall +# and not needed again after it returns. +function ngSpice_Command(command::String) + # Calculate bytes needed (including the NUL terminator) + byte_count = sizeof(command) + 1 + + # 1. Allocate raw system memory that Julia's GC will completely ignore + c_buffer = Libc.malloc(byte_count) + + # 2. Safely copy Julia's string data into the raw system buffer + GC.@preserve command begin + src_ptr = Base.unsafe_convert(Cstring, command) + # Copy the characters + trailing NUL byte + unsafe_copyto!(convert(Ptr{UInt8}, c_buffer), convert(Ptr{UInt8}, src_ptr), byte_count) + + @ccall libngspice.ngSpice_Command(c_buffer::Ptr{Cchar})::Cint end - if ret != 0 - error("Failed to initialize julia extensions") - end - return true -end - -function ngSpice_Init_Sync(vsrcdat, isrcdat, syncdat, ident, userData) - ccall((:ngSpice_Init_Sync, libngspice), Cint, (Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cvoid}, Ptr{Cint}, Ptr{Cvoid}), vsrcdat, isrcdat, syncdat, ident, userData) -end - -function ngSpice_Command(command) - ccall((:ngSpice_Command, libngspice), Cint, (Cstring,), command) end -function ngGet_Vec_Info(vecname) - ccall((:ngGet_Vec_Info, libngspice), pvector_info, (Cstring,), vecname) -end - -function ngSpice_Circ(circarray) - ccall((:ngSpice_Circ, libngspice), Cint, (Ptr{Ptr{UInt8}},), circarray) -end +#----------------------------------------------------------------- +# These seem safe function ngSpice_CurPlot() ccall((:ngSpice_CurPlot, libngspice), Ptr{UInt8}, ()) end @@ -40,14 +35,22 @@ function ngSpice_AllPlots() ccall((:ngSpice_AllPlots, libngspice), Ptr{Ptr{UInt8}}, ()) end + +#----------------------------------------------------------------- +# These functions are potentially unsafe due to passing String +# to Csting on foreign thread +function ngGet_Vec_Info(vecname) + ccall((:ngGet_Vec_Info, libngspice), pVectorInfo, (Cstring,), vecname) +end + + function ngSpice_AllVecs(plotname) ccall((:ngSpice_AllVecs, libngspice), Ptr{Ptr{UInt8}}, (Cstring,), plotname) end -function ngSpice_running() - ccall((:ngSpice_running, libngspice), Cint, ()) -end -function ngSpice_SetBkpt(bkpt) - ccall((:ngSpice_SetBkpt, libngspice), Cint, (Cdouble,), bkpt) +#----------------------------------------------------------------- +# Is this safe? +function ngSpice_Circ(circarray) + ccall((:ngSpice_Circ, libngspice), Cint, (Ptr{Ptr{UInt8}},), circarray) end diff --git a/src/interface/ngspice_common.jl b/src/interface/ngspice_common.jl index 61e2fc1..b845418 100644 --- a/src/interface/ngspice_common.jl +++ b/src/interface/ngspice_common.jl @@ -1,4 +1,3 @@ -# Skipping MacroDefinition: IMPEXP __declspec ( dllimport ) const ngcomplex_t = Complex{Cdouble} @@ -11,12 +10,14 @@ const VF_MINGIVEN = (1 << 5) const VF_MAXGIVEN = (1 << 6) const VF_PERMANENT = (1 << 7) + + """ Vector info obtained from any vector in ngspice.dll. Allows direct access to the ngspice internal vector structure, as defined in include/ngspice/devc.h . """ -struct vector_info +struct VectorInfo name::Cstring # Same as so_vname type::Cint # Same as so_vtype flags::Int16 # Flags (a combination of VF_*) @@ -25,9 +26,9 @@ struct vector_info length::Cint # Length of the vector end -const pvector_info = Ptr{vector_info} +const pVectorInfo = Ptr{VectorInfo} -struct vecvalues +struct VecValues name::Cstring # name of a specific vector creal::Cdouble # actual data value cimag::Cdouble # actual data value @@ -35,17 +36,17 @@ struct vecvalues is_complex::Cint # if the data are complex numbers end -const pvecvalues = Ptr{vecvalues} +const pVecValues = Ptr{VecValues} -struct vecvaluesall +struct VecValuesAll veccount::Cint # number of vectors in plot vecindex::Cint # index of actual set of vectors. i.e. the number of accepted data point - vecsa::pvecvalues # values of actual set of vectors, indexed from 0 to veccount - 1 - #just pvecvalues? + vecsa::pVecValues # values of actual set of vectors, indexed from 0 to veccount - 1 + #just pVecValues? end -const pvecvaluesall = Ptr{vecvaluesall} -struct vecinfo +const pVecValuesAll = Ptr{VecValuesAll} +struct VecInfo number::Cint # number of vector, as postion in the linked list of vectors, s name::Cstring # name of the actual vector is_real::Cint # 1 if the actual vector has real data @@ -53,96 +54,16 @@ struct vecinfo pdvecscale::Ptr{Cvoid} # a void pointer to struct dvec *ds, the scale vector end +const pVecInfo = Ptr{VecInfo} -const pvecinfo = Ptr{vecinfo} -struct vecinfoall +struct VecInfoAll name::Cstring title::Cstring date::Cstring type::Cstring veccount::Cint - vecs::pvecinfo -end - -#const pvecinfoall = Ptr{vecinfoall} - -ngerrorf, bgrunningf, vecgetnum = 0, 0, 0 -function std_print(text) - occursin("stdout", text) && - (println(text[8:end]); return) - (occursin("stderr", text) && !occursin("viewport", text)) && - (println(text[8:end]); return) - occursin("viewport", text) && - (println("\nPlotting is skipped.\n") - ; return) - println(text) -end - -function sendchar(_text::Ptr{Cchar}, id::Cint, userdata)::Cint - _text != C_NULL || throw("Not a valid text") - text = unsafe_string(_text) - std_print(text) - occursin(r"stderr Error:"i, text) && (ngerrorf = 1) - return 0 -end - -gen_psendchar() = @cfunction(sendchar, Cint, (Ptr{Cchar}, Cint, Ptr{Cvoid})) - -function sendstat(_text::Ptr{Cchar}, id::Cint, userdata)::Cint - _text != C_NULL || throw("Not a valid text") - text = unsafe_string(_text) - std_print(text) - return 0 -end - -gen_psendstat() = @cfunction(sendstat, Cint, (Ptr{Cchar}, Cint, Ptr{Cvoid})) - -function bgthreadrunning(run::Cint, id::Cint, userdata::Ptr{Cvoid})::Cint - bgrunning = run - run ? println("BG thread is not running") : - println("BG thread is running") - return 0 -end - -gen_pbgthread() = @cfunction(bgthreadrunning, Cint, (Cint, Cint, Ptr{Cvoid})) - -function controlledexit(exitstatus::Cint, immediate::Cint, - quitexit::Cint, id::Cint, userdata::Ptr{Cvoid})::Cint - quitexit == 1 && println("Returned from quit with exit status") - immediate == 1 ? (println("Unloading NgSpice"); ngSpice_Command("quit")) : - (println("Prepare an unload"); will_unload = 1) - return exitstatus -end - -gen_pcontrolledexit() = @cfunction(controlledexit, Cint, (Cint, Cint, Cint, Cint, Ptr{Cvoid})) - -function senddata(vecdata::Ptr{vecinfoall}, - id::Cint, userdata::Ptr{Cvoid})::Cint - return 0 -end - -gen_psenddata() = @cfunction(senddata, Cint, (Ptr{vecinfoall}, Cint, Ptr{Cvoid})) - -function sendinitdata(initdata::Ptr{vecinfoall}, id::Cint, userdata::Ptr{Cvoid}) - #= - This bit is problematic because it always returns C_NULLs even before - `data.veccount` number of `vecinfo`s are passed. - Even when that is handled it's o/p is always `nothing` - and array of `nothing`s - - initdata == C_NULL && throw("No initialized data") - data = unsafe_load(initdata) - vec = unsafe_wrap(Array, data.vecs, (data.veccount, )) - for v in vec - v.name == C_NULL && return zero(Int32) - vname = unsafe_string(v.name) - vpdvec = unsafe_wrap(Array, v.pdvec, 10) - vpdscale = unsafe_wrap(Array, v.pdvecscale, 10) - println(vname, vpdscale, vpdvec) - end - =# - return zero(Int32) + vecs::pVecInfo end +const pVecInfoAll = Ptr{VecInfoAll} -gen_psendinitdata() = @cfunction(sendinitdata, Cint, (Ptr{vecinfoall}, Cint, Ptr{Cvoid})) diff --git a/test/ngspice_api.jl b/test/ngspice_api.jl deleted file mode 100644 index eb1bc1f..0000000 --- a/test/ngspice_api.jl +++ /dev/null @@ -1,15 +0,0 @@ -using NgSpice -using Test - -rootdir = joinpath(@__DIR__, "..") -netpath = joinpath(rootdir, "inputs", "mosfet.cir") - -@testset "interface" begin - p = convert(Ptr{Nothing}, 0) - @test ngSpice_Init(p, p, p, p, p, p, p) == 0 - @test ngSpice_Command("source $netpath") == 0 - @test ngSpice_CurPlot() != C_NULL - @test ngSpice_Command("run") == 0 - @test typeof(ngSpice_AllPlots()) == Ptr{Ptr{UInt8}} - @test ngSpice_running() == 0 -end \ No newline at end of file diff --git a/test/runtests.jl b/test/runtests.jl deleted file mode 100644 index 56b8194..0000000 --- a/test/runtests.jl +++ /dev/null @@ -1,15 +0,0 @@ -using NgSpice -using Test -using SafeTestsets - -@safetestset "interface functions" begin - include("ngspice_api.jl") -end - -@testset "friend functions" begin - include("wrapper_api.jl") -end - -@safetestset "wrapper safetests" begin - include("wrapper_safetests.jl") -end diff --git a/test/wrapper_api.jl b/test/wrapper_api.jl deleted file mode 100644 index 0aedb6c..0000000 --- a/test/wrapper_api.jl +++ /dev/null @@ -1,34 +0,0 @@ -using NgSpice -using Test - -rootdir = joinpath(@__DIR__, "..") -netpath = joinpath(rootdir, "inputs", "mosfet.cir") - -@testset "initialize" begin - init() - @test source(netpath) == 0 - @test NgSpice.run() == 0 -end - -@testset "getvectors" begin - # as this simulation runs after the one in `ngspice_api.jl`, - # `tran2` is the current plot - @test curplot() == "tran2" - @test listallplots() == ["tran2", "tran1", "const"] - @test collect(keys(listallvecs())) == collect(sort(listallplots())) - @test listallvecs()[curplot()] == listcurvecs() - @test getvec.(listcurvecs()) == get_vector_info.(listcurvecs()) - #listcurvecs() - for node in split("V(1) emit coll base vcc") - @test getvec(node)[2] == "voltage" - end - for branch in split("vcc#branch vin#branch") - @test getvec(branch)[2] == "current" - end - @test getvec("time")[2] == "time" -end - -@testset "passing circuit as an array" begin - netlist = readlines(netpath) - @test load_netlist(netlist) == 0 -end diff --git a/test/wrapper_safetests.jl b/test/wrapper_safetests.jl deleted file mode 100644 index 8cedacd..0000000 --- a/test/wrapper_safetests.jl +++ /dev/null @@ -1,16 +0,0 @@ -using NgSpice -using Test - -NgSpice.init() - -nl = """ -* Diode test circuit -V1 inp 0 DC=1 AC=1 SIN(1 1 1000) -* Connected in forward bias: -D1 inp 0 dmod -.model dmod d cjo=0 m=1 rs=5000 area=1 pj=0 cjp=0 mj=0 mjsw=0 pb=1 php=1 n=2 bv=0 ibv=0 ik=0 ikr=0 is=1.0e-9 tt=0 -.save all @d1[id] @d1[cd] @d1[charge] @d1[vd] -.END -""" - -@test NgSpice.load_netlist(nl) == 0 diff --git a/tutorials/demo.jl b/tutorials/demo.jl deleted file mode 100644 index 3e7d4d1..0000000 --- a/tutorials/demo.jl +++ /dev/null @@ -1,12 +0,0 @@ -# Check out mosfet.jl for more Julia-like usage - -import NgSpice -n = NgSpice - -netpath = joinpath(@__DIR__, "..", "inputs", "ac_ascii.cir") |> normpath - -n.init() -n.cmd("source $netpath") -n.cmd("run") -n.cmd("display") -#n.cmd("") diff --git a/tutorials/mosfet.jl b/tutorials/mosfet.jl deleted file mode 100644 index d4ec770..0000000 --- a/tutorials/mosfet.jl +++ /dev/null @@ -1,21 +0,0 @@ -using NgSpice -# using Plots -n = NgSpice - -netpath = joinpath(@__DIR__, "..", "inputs", "mosfet.cir") |> normpath - -n.init() -n.source(netpath) -n.run() -n.display() # Returns a dataframe of current vectors -n.listallvecs() # Lists vectors of both active and inactive plots -n.curplot() # Current active plot -n.listcurvecs() # Vectors in current active plot - -# For plotting the signals, pass `n.graph` an object of `NgSpiceGraphs` type. -# And then, specify the get-vector method. -# Pass "time" or "frequency" -# List of signals to plot -# Finally, the title of the plot -# plot(n.graph, n.getimagvec, "time", ["emit", "vcc"], "Simple MOSFET") -# plot(n.graph, n.getrealvec, "time", ["emit", "vcc"], "Simple MOSFET")