From 951f831f63ee277fab8be0062b482b364bea316a Mon Sep 17 00:00:00 2001 From: LSTM-Kirigaya <1193466151@qq.com> Date: Tue, 26 Nov 2024 21:38:23 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=20SSI=20=E8=AE=A1=E7=AE=97?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BF=AE=E5=A4=8D=20|=20=E4=BF=AE=E5=A4=8D?= =?UTF-8?q?=20TCL=20=E5=88=B7=E6=96=B0=20XPR=20=E7=9A=84=E8=AE=BE=E8=AE=A1?= =?UTF-8?q?=E6=BA=90=E6=B7=BB=E5=8A=A0=E9=80=BB=E8=BE=91=E6=BC=8F=E6=B4=9E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- l10n/bundle.l10n.de.json | 4 +- l10n/bundle.l10n.en.json | 4 +- l10n/bundle.l10n.ja.json | 4 +- l10n/bundle.l10n.zh-cn.json | 4 +- l10n/bundle.l10n.zh-tw.json | 4 +- .../dide-lsp/static/xilinx/primitive.bin | Bin 3736879 -> 3736879 bytes snippets/sdc.json | 11 + snippets/svlog.json | 293 ++++-------------- snippets/tcl.json | 18 ++ snippets/vhdl.json | 20 ++ src/function/dide-viewer/index.ts | 4 +- src/function/hdlDoc/markdown.ts | 6 +- src/function/lsp/linter/vivado.ts | 27 +- src/function/netlist/index.ts | 2 + src/function/sim/simulate.ts | 66 ++-- src/function/treeView/index.ts | 8 +- src/function/treeView/tree.ts | 6 +- src/global/outputChannel.ts | 57 +++- src/global/prjInfo.ts | 35 +++ src/hdlFs/file.ts | 21 +- src/hdlParser/common.ts | 18 +- src/hdlParser/core.ts | 143 +++++++-- src/manager/PL/index.ts | 22 +- src/manager/PL/xilinx.ts | 104 +++++-- src/manager/index.ts | 4 +- src/monitor/event.ts | 34 +- 26 files changed, 526 insertions(+), 393 deletions(-) diff --git a/l10n/bundle.l10n.de.json b/l10n/bundle.l10n.de.json index cef3074..19c82ec 100644 --- a/l10n/bundle.l10n.de.json +++ b/l10n/bundle.l10n.de.json @@ -69,5 +69,7 @@ "info.pl.xilinx.update-addfiles": "Datei zu Xilinx-Projekt hinzufügen", "info.pl.xilinx.update-delfiles": "Löschen Sie die folgenden Dateien aus dem Xilinx-Projekt.", "info.pl.xilinx.no-need-add-files": "Keine Dateien zum Hinzufügen zum Xilinx-Projekt", - "info.pl.xilinx.no-need-del-files": "Es müssen keine Dateien aus Xilinx gelöscht werden." + "info.pl.xilinx.no-need-del-files": "Es müssen keine Dateien aus Xilinx gelöscht werden.", + "error.pl.launch.not-valid-vivado-path": "Fehler beim Starten des Vivado TCL-Skriptinterpreters: {0}. Bitte überprüfen Sie, ob der Startpfad für Vivado korrekt ist. Derzeit eingestellter Startordnerpfad für Vivado: {1}", + "info.pl.launch.set-vivado-path": "Zur Einstellung des Vivado-Installationspfads gehen" } \ No newline at end of file diff --git a/l10n/bundle.l10n.en.json b/l10n/bundle.l10n.en.json index 1632f95..ac91e50 100644 --- a/l10n/bundle.l10n.en.json +++ b/l10n/bundle.l10n.en.json @@ -69,5 +69,7 @@ "info.pl.xilinx.update-addfiles": "Add file to Xilinx project", "info.pl.xilinx.update-delfiles": "Delete the following files from the Xilinx project.", "info.pl.xilinx.no-need-add-files": "No files need to be added to the Xilinx project", - "info.pl.xilinx.no-need-del-files": "There are no files to be deleted from Xilinx." + "info.pl.xilinx.no-need-del-files": "There are no files to be deleted from Xilinx.", + "error.pl.launch.not-valid-vivado-path": "Error encountered while starting the Vivado TCL script interpreter: {0}. Please check if your Vivado startup path is correct. Currently set Vivado startup folder path: {1}", + "info.pl.launch.set-vivado-path": "Go to set the Vivado installation path" } \ No newline at end of file diff --git a/l10n/bundle.l10n.ja.json b/l10n/bundle.l10n.ja.json index 4c4ad8d..a30cc52 100644 --- a/l10n/bundle.l10n.ja.json +++ b/l10n/bundle.l10n.ja.json @@ -69,5 +69,7 @@ "info.pl.xilinx.update-addfiles": "ファイルを Xilinx プロジェクトに追加", "info.pl.xilinx.update-delfiles": "以下のファイルをXilinxプロジェクトから削除してください。", "info.pl.xilinx.no-need-add-files": "Xilinx プロジェクトに追加するファイルはありません", - "info.pl.xilinx.no-need-del-files": "Xilinx から削除するファイルはありません。" + "info.pl.xilinx.no-need-del-files": "Xilinx から削除するファイルはありません。", + "error.pl.launch.not-valid-vivado-path": "Vivado TCL スクリプトインタプリタの起動中にエラーが発生しました:{0}。Vivado の起動パスが正しいか確認してください。現在設定されている Vivado 起動フォルダパス:{1}", + "info.pl.launch.set-vivado-path": "Vivado インストールパスの設定に移動" } \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-cn.json b/l10n/bundle.l10n.zh-cn.json index 48a6b93..02418ba 100644 --- a/l10n/bundle.l10n.zh-cn.json +++ b/l10n/bundle.l10n.zh-cn.json @@ -69,5 +69,7 @@ "info.pl.xilinx.update-addfiles": "添加文件到 Xilinx 工程", "info.pl.xilinx.update-delfiles": "将下方文件从 Xilinx 工程中删除", "info.pl.xilinx.no-need-add-files": "没有需要添加到 Xilinx 工程的文件", - "info.pl.xilinx.no-need-del-files": "没有需要从 Xilinx 中删除的文件" + "info.pl.xilinx.no-need-del-files": "没有需要从 Xilinx 中删除的文件", + "error.pl.launch.not-valid-vivado-path": "启动 Vivado TCL 脚本解释器遇到错误:{0} 。请检查你的 Vivado 启动路径是否正确,当前设置的 Vivado 启动文件夹路径:{1}", + "info.pl.launch.set-vivado-path": "前往设置 Vivado 安装路径" } \ No newline at end of file diff --git a/l10n/bundle.l10n.zh-tw.json b/l10n/bundle.l10n.zh-tw.json index 40f6f5b..1783f64 100644 --- a/l10n/bundle.l10n.zh-tw.json +++ b/l10n/bundle.l10n.zh-tw.json @@ -69,5 +69,7 @@ "info.pl.xilinx.update-addfiles": "將檔案新增到 Xilinx 專案", "info.pl.xilinx.update-delfiles": "從 Xilinx 專案中刪除以下檔案。", "info.pl.xilinx.no-need-add-files": "沒有需要添加到 Xilinx 工程的文件", - "info.pl.xilinx.no-need-del-files": "沒有需要從 Xilinx 中刪除的檔案。" + "info.pl.xilinx.no-need-del-files": "沒有需要從 Xilinx 中刪除的檔案。", + "error.pl.launch.not-valid-vivado-path": "啟動 Vivado TCL 腳本解釋器遇到錯誤:{0} 。請檢查你的 Vivado 啟動路徑是否正確,目前設定的 Vivado 啟動資料夾路徑:{1}", + "info.pl.launch.set-vivado-path": "前往設定 Vivado 安裝路徑" } \ No newline at end of file diff --git a/resources/dide-lsp/static/xilinx/primitive.bin b/resources/dide-lsp/static/xilinx/primitive.bin index 53f05f265ce5eded2b515e763f325182da8d8afd..4bd7e11b4c61551dd61d4b55ff9203c942c78340 100644 GIT binary patch delta 4287 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 NU*t?NfG3gB^uMI&cryS1 delta 4354 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 PBMV$Vi>N*>O(OpX6g9&~ diff --git a/snippets/sdc.json b/snippets/sdc.json index 497a4f1..55b8f50 100644 --- a/snippets/sdc.json +++ b/snippets/sdc.json @@ -1,4 +1,13 @@ { + "clock": { + "prefix": "create_pll", + "body": [ + "create_clock -period 20.000 [get_ports clock]", + "set_input_jitter [get_clocks -of_objects [get_ports clock]] 0.200", + "set_property PHASESHIFT_MODE WAVEFORM [get_cells -hierarchical *adv*]" + ] + }, + "ILA_CORE": { "prefix": "create_ILA_CORE", "body": [ @@ -8,6 +17,7 @@ "connect_debug_port dbg_hub/clk [get_nets [list CLK_Global_u/clk_out${2:3}]]" ] }, + "Debug_CORE": { "prefix": "create_Debug_CORE", "body": [ @@ -24,6 +34,7 @@ "connect_debug_port u_ila_$1/clk [get_nets [list CLK_Global_u/clk_out${3:3}]]" ] }, + "Debug_add_port": { "prefix": "add_port", "body": [ diff --git a/snippets/svlog.json b/snippets/svlog.json index 04947e9..18f2510 100644 --- a/snippets/svlog.json +++ b/snippets/svlog.json @@ -1,210 +1,18 @@ -{ - "IDDR": { - "prefix": "iddr", - "body" : [ - "IDDR #(", - " // \"OPPOSITE_EDGE\", \"SAME_EDGE\" or \"SAME_EDGE_PIPELINED\" ", - " .DDR_CLK_EDGE(\"SAME_EDGE\"), ", - " .INIT_Q1(1'b0), // Initial value of Q1: 1'b0 or 1'b1", - " .INIT_Q2(1'b0), // Initial value of Q2: 1'b0 or 1'b1", - " .SRTYPE(\"SYNC\")) // Set/Reset type: \"SYNC\" or \"ASYNC\" ", - "IDDR_inst (", - "IDDR #(", - " .Q1(rx_data_pos), // 1-bit output for positive edge of clock ", - " .Q2(rx_data_neg), // 1-bit output for negative edge of clock", - " .C(data_clk), // 1-bit clock input", - " .CE(1'b1), // 1-bit clock enable input", - " .D(rx_data_dly), // 1-bit DDR data input", - " .R(1'b0), // 1-bit reset", - " .S(1'b0) // 1-bit set", - ");" - ] - }, - - "ODDR": { - "prefix": "oddr", - "body" : [ - "ODDR #(", - " .DDR_CLK_EDGE(\"SAME_EDGE\"), // \"OPPOSITE_EDGE\" or \"SAME_EDGE\" ", - " .INIT(1'b0), // Initial value of Q: 1'b0 or 1'b1", - " .SRTYPE(\"SYNC\")) // Set/Reset type: \"SYNC\" or \"ASYNC\" ", - "ODDR_inst (", - " .Q(odata), // 1-bit DDR output", - " .C(data_clk), // 1-bit clock input", - " .CE(1'b1), // 1-bit clock enable input", - " .D1(data_p), // 1-bit data input (positive edge)", - " .D2(data_n), // 1-bit data input (negative edge)", - " .R(1'b0), // 1-bit reset", - " .S(1'b0) // 1-bit set", - ");" - ] - }, - - "OBUFDS": { - "prefix": "obuf", - "body" : [ - "OBUFDS #(", - " .IOSTANDARD(\"LVDS18\"), // Specify the output I/O standard", - " .SLEW(\"SLOW\")) // Specify the output slew rate", - "OBUFDS_inst (", - " .O(tx_frame_p), // Diff_p output (connect directly to top-level port)", - " .OB(tx_frame_n), // Diff_n output (connect directly to top-level port)", - " .I(tx_frame) // Buffer input ", - ");" - ] - }, - - "IBUFDS": { - "prefix": "ibuf", - "body" : [ - "IBUFDS #(", - " .DIFF_TERM(\"FALSE\"), // Differential Termination", - " .IBUF_LOW_PWR(\"TRUE\"), // Low power=\"TRUE\", Highest performance=\"FALSE\" ", - " .IOSTANDARD(\"DEFAULT\")) // Specify the input I/O standard", - "IBUFDS_inst (", - " .O(data_clk_tmp), // Buffer output", - " .I(data_clk_p), // Diff_p buffer input (connect directly to top-level port)", - " .IB(data_clk_n) // Diff_n buffer input (connect directly to top-level port)", - ");" - ] - }, - - "OSERDESE2": { - "prefix": "oserd", - "body" : [ - "OSERDESE2 #(", - " .DATA_RATE_OQ(\"DDR\"), // DDR, SDR", - " .DATA_RATE_TQ(\"DDR\"), // DDR, BUF, SDR", - " .DATA_WIDTH(4), // Parallel data width (2-8,10,14)", - " .INIT_OQ(1'b0), // Initial value of OQ output (1'b0,1'b1)", - " .INIT_TQ(1'b0), // Initial value of TQ output (1'b0,1'b1)", - " .SERDES_MODE(\"MASTER\"), // MASTER, SLAVE", - " .SRVAL_OQ(1'b0), // OQ output value when SR is used (1'b0,1'b1)", - " .SRVAL_TQ(1'b0), // TQ output value when SR is used (1'b0,1'b1)", - " .TBYTE_CTL(\"FALSE\"), // Enable tristate byte operation (FALSE, TRUE)", - " .TBYTE_SRC(\"FALSE\"), // Tristate byte source (FALSE, TRUE)", - " .TRISTATE_WIDTH(4) // 3-state converter width (1,4)", - ")", - "OSERDESE2_inst (", - " .OFB(OFB), // 1-bit output: Feedback path for data", - " .OQ(OQ), // 1-bit output: Data path output", - " // SHIFTOUT1 / SHIFTOUT2: 1-bit (each) output: Data output expansion (1-bit each)", - " .SHIFTOUT1(SHIFTOUT1),", - " .SHIFTOUT2(SHIFTOUT2),", - " .TBYTEOUT(TBYTEOUT), // 1-bit output: Byte group tristate", - " .TFB(TFB), // 1-bit output: 3-state control", - " .TQ(TQ), // 1-bit output: 3-state control", - " .CLK(CLK), // 1-bit input: High speed clock", - " .CLKDIV(CLKDIV), // 1-bit input: Divided clock", - " // D1 - D8: 1-bit (each) input: Parallel data inputs (1-bit each)", - " .D1(D1),", - " .D2(D2),", - " .D3(D3),", - " .D4(D4),", - " .D5(D5),", - " .D6(D6),", - " .D7(D7),", - " .D8(D8),", - " .OCE(OCE), // 1-bit input: Output data clock enable", - " .RST(RST), // 1-bit input: Reset", - " // SHIFTIN1 / SHIFTIN2: 1-bit (each) input: Data input expansion (1-bit each)", - " .SHIFTIN1(SHIFTIN1),", - " .SHIFTIN2(SHIFTIN2),", - " // T1 - T4: 1-bit (each) input: Parallel 3-state inputs", - " .T1(T1),", - " .T2(T2),", - " .T3(T3),", - " .T4(T4),", - " .TBYTEIN(TBYTEIN), // 1-bit input: Byte group tristate", - " .TCE(TCE) // 1-bit input: 3-state clock enable", - ");" - ] - }, - - "ISERDESE2": { - "prefix": "iserd", - "body" : [ - "ISERDESE2 #(", - " .DATA_RATE(\"DDR\"), // DDR, SDR", - " .DATA_WIDTH(4), // Parallel data width (2-8,10,14)", - " .DYN_CLKDIV_INV_EN(\"FALSE\"), // Enable DYNCLKDIVINVSEL inversion (FALSE, TRUE)", - " .DYN_CLK_INV_EN(\"FALSE\"), // Enable DYNCLKINVSEL inversion (FALSE, TRUE)", - " // INIT_Q1 - INIT_Q4: Initial value on the Q outputs (0/1)", - " .INIT_Q1(1'b0),", - " .INIT_Q2(1'b0),", - " .INIT_Q3(1'b0),", - " .INIT_Q4(1'b0),", - " .INTERFACE_TYPE(\"MEMORY\"), // MEMORY, MEMORY_DDR3, MEMORY_QDR, NETWORKING, OVERSAMPLE", - " .IOBDELAY(\"NONE\"), // NONE, BOTH, IBUF, IFD", - " .NUM_CE(2), // Number of clock enables (1,2)", - " .OFB_USED(\"FALSE\"), // Select OFB path (FALSE, TRUE)", - " .SERDES_MODE(\"MASTER\"), // MASTER, SLAVE", - " // SRVAL_Q1 - SRVAL_Q4: Q output values when SR is used (0/1)", - " .SRVAL_Q1(1'b0),", - " .SRVAL_Q2(1'b0),", - " .SRVAL_Q3(1'b0),", - " .SRVAL_Q4(1'b0))", - "ISERDESE2_inst (", - " .O(O), // 1-bit output: Combinatorial output", - " // Q1 - Q8: 1-bit (each) output: Registered data outputs", - " .Q1(Q1),", - " .Q2(Q2),", - " .Q3(Q3),", - " .Q4(Q4),", - " .Q5(Q5),", - " .Q6(Q6),", - " .Q7(Q7),", - " .Q8(Q8),", - " // SHIFTOUT1, SHIFTOUT2: 1-bit (each) output: Data width expansion output ports", - " .SHIFTOUT1(SHIFTOUT1),", - " .SHIFTOUT2(SHIFTOUT2),", - "\n", - " // 1-bit input: The BITSLIP pin performs a Bitslip operation synchronous to", - " // CLKDIV when asserted (active High). Subsequently, the data seen on the Q1", - " // to Q8 output ports will shift, as in a barrel-shifter operation, one", - " // position every time Bitslip is invoked (DDR operation is different from", - " // SDR).", - " .BITSLIP(BITSLIP), ", - "\n", - " // CE1, CE2: 1-bit (each) input: Data register clock enable inputs", - " .CE1(CE1),", - " .CE2(CE2),", - " .CLKDIVP(CLKDIVP), // 1-bit input: TBD", - " // Clocks: 1-bit (each) input: ISERDESE2 clock input ports", - " .CLK(CLK), // 1-bit input: High-speed clock", - " .CLKB(CLKB), // 1-bit input: High-speed secondary clock", - " .CLKDIV(CLKDIV), // 1-bit input: Divided clock", - " .OCLK(OCLK), // 1-bit input: High speed output clock used when INTERFACE_TYPE=\"MEMORY\" ", - " // Dynamic Clock Inversions: 1-bit (each) input: Dynamic clock inversion pins to switch clock polarity", - " .DYNCLKDIVSEL(DYNCLKDIVSEL), // 1-bit input: Dynamic CLKDIV inversion", - " .DYNCLKSEL(DYNCLKSEL), // 1-bit input: Dynamic CLK/CLKB inversion", - " // Input Data: 1-bit (each) input: ISERDESE2 data input ports", - " .D(D), // 1-bit input: Data input", - " .DDLY(DDLY), // 1-bit input: Serial data from IDELAYE2", - " .OFB(OFB), // 1-bit input: Data feedback from OSERDESE2", - " .OCLKB(OCLKB), // 1-bit input: High speed negative edge output clock", - " .RST(RST), // 1-bit input: Active high asynchronous reset", - " // SHIFTIN1, SHIFTIN2: 1-bit (each) input: Data width expansion input ports", - " .SHIFTIN1(SHIFTIN1),", - " .SHIFTIN2(SHIFTIN2)", - ");" - ] - }, - - "count": { - "prefix": "count", +{ + "counter": { + "prefix": "counter", "body": [ "//define the time counter", - "reg [${1:32}:0] cnt$2 = 0;", - "reg ${3:impulse};", "parameter SET_TIME = $1'd$4;", - "always@(posedge clk) begin", - " if (cnt$2 == SET_TIME) begin", - " cnt$2 <= $1'd0;", + "reg [${1:32}:0] count$2;", + "reg ${3:impulse};", + "always@(posedge clock) begin", + " if (count$2 == SET_TIME) begin", + " count$2 <= $1'd0;", " $3 <= 1'd1;", " end", " else begin", - " cnt$2 <= cnt$2 + 1'd1;", + " count$2 <= count$2 + 1'd1;", " $3 <= 1'd0;", " end", "end" @@ -214,15 +22,15 @@ "divclk": { "prefix": "div", "body": [ - "reg [${1:3}:0] cnt$2 = 0;", - "reg clk_div$2;", - "always@(posedge ${3:clk}) begin", - " if (cnt$2 == ${4:3}) begin", - " cnt$2 <= $1'd0;", + "reg [${1:3}:0] count$2;", + "reg clk_div$2;", + "always@(posedge ${3:clock}) begin", + " if (count$2 == ${4:3}) begin", + " count$2 <= $1'd0;", " clk_div$2 <= ~clk_div$2;", " end", " else begin", - " cnt$2 <= cnt$2 + 1'd1;", + " count$2 <= count$2 + 1'd1;", " end", "end" ] @@ -234,10 +42,10 @@ "reg gate$2;", "reg gate$2_buf;", - "wire gate$2_pose = gate$2 & ~gate$2_buf;", - "wire gate$2_nege = ~gate$2 & gate$2_buf;", + "wire gate$2_pos = gate$2 & ~gate$2_buf;", + "wire gate$2_neg = ~gate$2 & gate$2_buf;", - "always@(posedge clk) begin", + "always@(posedge clock) begin", " gate$2 <= ${1:signal};", " gate$2_buf <= gate$2;", "end" @@ -262,9 +70,9 @@ "prefix": "resetn", "body": [ "reg rst_n_s1, rst_n_s2;", - "wire rst_n", - "always @ (posedge clk or negedge sys_rst_n) begin", - " if (sys_rst_n) begin", + "wire sys_rstn", + "always @ (posedge clock or negedge rstn) begin", + " if (rstn) begin", " rst_n_s2 <= 1'b0;", " rst_n_s1 <= 1'b0;", " end", @@ -272,18 +80,18 @@ " rst_n_s2 <= rst_n_s1;", " end", "end", - "assign rst_n = rst_n_s2;" + "assign sys_rstn = rst_n_s2;" ], - "description" : "Asynchronous sys_rst_n synchronous release (intel device)" + "description" : "Asynchronous sys_rstn synchronous release (intel device)" }, "reset": { "prefix": "reset", "body": [ "reg rst_s1, rst_s2;", - "wire rst", - "always @ (posedge clk or posedge sys_rst) begin", - " if (sys_rst) begin", + "wire sys_rst", + "always @ (posedge clock or posedge reset) begin", + " if (reset) begin", " rst_s2 <= 1'b0;", " rst_s1 <= 1'b0;", " end", @@ -291,9 +99,9 @@ " rst_s2 <= rst_s1;", " end", "end", - "assign rst = rst_s2;" + "assign sys_rst = rst_s2;" ], - "description" : "Asynchronous sys_rst synchronous release (xilinx device)" + "description" : "Asynchronous reset synchronous release (xilinx device)" }, "initial sim": { @@ -369,18 +177,18 @@ "alwaysposclk": { "prefix": "alclk", "body": [ - "always @(posedge clk) begin", + "always @(posedge clock) begin", " $1;", "end" ], - "description": "always @(posedge clk) directly" + "description": "always @(posedge clock) directly" }, "alwayssyncrst": { "prefix": "alsync", "body": [ - "always @(posedge clk) begin", - " if(rst) begin", + "always @(posedge clock) begin", + " if(reset) begin", " $1 <= 0;", " end", " else begin", @@ -394,8 +202,8 @@ "alwaysasyncrst": { "prefix": "alasync", "body": [ - "always @(posedge clk or posedge rst) begin", - " if(rst) begin", + "always @(posedge clock or posedge reset) begin", + " if(reset) begin", " $1 <= 0;", " end", " else begin", @@ -409,8 +217,8 @@ "alwayssyncrstn": { "prefix": "alsyncn", "body": [ - "always @(posedge clk) begin", - " if(!rst_n) begin", + "always @(posedge clock) begin", + " if(!rstn) begin", " $1 <= 0;", " end", " else begin", @@ -418,14 +226,14 @@ " end", "end" ], - "description": "synchronous rst_n (intel device)" + "description": "synchronous rstn (intel device)" }, "alwaysasyncrstn": { "prefix": "alasyncn", "body": [ - "always @(posedge clk or negedge rst_n) begin", - " if(!rst_n) begin", + "always @(posedge clock or negedge rstn) begin", + " if(!rstn) begin", " $1 <= 0;", " end", " else begin", @@ -433,7 +241,7 @@ " end", "end" ], - "description": "asynchronous rst_n (intel device)" + "description": "asynchronous rstn (intel device)" }, "beginend": { @@ -461,13 +269,13 @@ "prefix": "modp", "body": [ "module ${1:name} #(", - " parameter INPUT_WIDTH = ${2:12},", - " parameter OUTPUT_WIDTH = $2", + " parameter IWIDTH = ${2:12},", + " parameter OWIDTH = $2", ") (", - " input clk,", - " input RST,", - " input [INPUT_WIDTH - 1 : 0] ${3:data_i},", - " output [OUTPUT_WIDTH - 1 : 0] ${4:data_o}", + " input clock,", + " input reset,", + " input [IWIDTH - 1 : 0] ${3:data_i},", + " output [OWIDTH - 1 : 0] ${4:data_o}", ");", " $5", "endmodule //$1\n" @@ -479,8 +287,8 @@ "prefix": "mod", "body": [ "module ${1:moduleName} (", - " input clk,", - " input rst,", + " input clock,", + " input reset,", " $2", ");", " $3", @@ -488,6 +296,7 @@ ], "description": "Insert a module without parameter" }, + "simple module": { "prefix": "module", "body": [ @@ -497,6 +306,7 @@ ], "description": "Insert a common module" }, + "generate_for": { "prefix": "genfor", "body": [ @@ -903,18 +713,21 @@ "*/" ] }, + "dumpfile": { "prefix": "$dumpfile", "body": [ "\\$dumpfile(\"$1\");" ] }, + "dumpvars": { "prefix": "$dumpvars", "body": [ "\\$dumpvars;" ] }, + "finish": { "prefix": "$finish", "body": [ diff --git a/snippets/tcl.json b/snippets/tcl.json index d9ff82f..673c8f0 100644 --- a/snippets/tcl.json +++ b/snippets/tcl.json @@ -8,6 +8,7 @@ ], "description": "For Loop" }, + "foreach": { "prefix": "foreach", "body": [ @@ -17,6 +18,7 @@ ], "description": "Foreach Loop" }, + "if": { "prefix": "if", "body": [ @@ -26,6 +28,7 @@ ], "description": "If Condition" }, + "elseif": { "prefix": "elseif", "body": [ @@ -35,6 +38,7 @@ ], "description": "ElseIf Condition" }, + "else": { "prefix": "else", "body": [ @@ -44,6 +48,7 @@ ], "description": "Else Block" }, + "proc": { "prefix": "proc", "body": [ @@ -53,6 +58,7 @@ ], "description": "Proc Block" }, + "while": { "prefix": "while", "body": [ @@ -62,6 +68,7 @@ ], "description": "While Loop" }, + "catch": { "prefix": "catch", "body": [ @@ -69,6 +76,7 @@ ], "description": "Catch Block" }, + "try": { "prefix": "try", "body": [ @@ -80,6 +88,7 @@ ], "description": "Try Block" }, + "switch": { "prefix": "switch", "body": [ @@ -90,6 +99,7 @@ ], "description": "Switch Block" }, + "oo::class create": { "prefix": "oo::class create", "body": [ @@ -105,6 +115,7 @@ ], "description": "Class Create" }, + "tk_chooseDirectory": { "prefix": "tk_chooseDirectory", "body": [ @@ -112,6 +123,7 @@ ], "description": "Choose Directory" }, + "tk_getOpenFile": { "prefix": "tk_getOpenFile", "body": [ @@ -122,6 +134,7 @@ ], "description": "Open File Dialog" }, + "tk_getSaveFile": { "prefix": "tk_getSaveFile", "body": [ @@ -132,6 +145,7 @@ ], "description": "Save File Dialog" }, + "tk_messageBox": { "prefix": "tk_messageBox", "body": [ @@ -139,6 +153,7 @@ ], "description": "Message Box" }, + "set_property": { "prefix": "set_property", "body": [ @@ -146,18 +161,21 @@ ], "description": "set property" }, + "create_clock": { "prefix": "create_clock", "body": [ "create_clock ${1:signal_name} ${2:clock_name} ${3:frequency} ${4:uncertainty}" ] }, + "set_initial_state": { "prefix": "set_initial_state", "body": [ "set_initial_5state ${1:initial_state}" ] }, + "connect_port": { "prefix": "connect_port", "body": [ diff --git a/snippets/vhdl.json b/snippets/vhdl.json index 4bc6f96..1fe2c03 100644 --- a/snippets/vhdl.json +++ b/snippets/vhdl.json @@ -5,120 +5,140 @@ "description": "asynchronous process", "scope": "source.vhdl" }, + "arch": { "prefix": "arch", "body": "architecture ${1:arch} of ${2:ent} is\n\n\tsignal $0\n\nbegin\n\nend ${1:arch} ; -- ${1:arch}", "description": "architecture", "scope": "source.vhdl" }, + "case": { "prefix": "case", "body": "case( ${1:signal_name} ) is\n\n\twhen ${2:IDLE} =>\n\t\t$0\n\n\twhen others =>\n\nend case ;", "description": "case", "scope": "source.vhdl" }, + "else": { "prefix": "else", "body": "else\n\t$0", "description": "else", "scope": "source.vhdl" }, + "elsif": { "prefix": "elsif", "body": "elsif ${1:expression} then\n\t$0", "description": "elsif", "scope": "source.vhdl" }, + "ent": { "prefix": "ent", "body": "entity ${1:ent} is\n port (\n\t${0:clock}\n ) ;\nend ${1:ent};", "description": "entity", "scope": "source.vhdl" }, + "entarch": { "prefix": "entarch", "body": "entity ${1:ent} is\n port (\n\t${0:clock}\n ) ;\nend ${1:ent} ;\n\narchitecture ${2:arch} of ${1:ent} is\n\n\n\nbegin\n\n\n\nend architecture ; -- ${2:arch}", "description": "entity architecture", "scope": "source.vhdl" }, + "for": { "prefix": "for", "body": "${1:identifier} : for ${2:i} in ${3:0} to ${4:10} loop\n\t$0\nend loop ; -- ${1:identifier}", "description": "for loop", "scope": "source.vhdl" }, + "forg": { "prefix": "forg", "body": "${1:identifier} : for ${2:i} in ${3:x} to ${4:y} generate\n\t$0\nend generate ; -- ${1:identifier}", "description": "for generate", "scope": "source.vhdl" }, + "if": { "prefix": "if", "body": "if ${1:expression} then\n\t$0\nend if ;", "description": "if", "scope": "source.vhdl" }, + "pack": { "prefix": "pack", "body": "package ${1:pkg} is\n\t$0\nend package ;", "description": "package", "scope": "source.vhdl" }, + "pro": { "prefix": "pro", "body": "${1:identifier} : process( ${2:sensitivity_list} )\nbegin\n\t$0\nend process ; -- ${1:identifier}", "description": "process", "scope": "source.vhdl" }, + "s": { "prefix": "s", "body": "signed(${1:x} downto ${2:0}) ;$0", "description": "signed downto", "scope": "source.vhdl" }, + "sr": { "prefix": "sr", "body": "signed(${1:signal}'range) ;$0", "description": "signed range", "scope": "source.vhdl" }, + "spro": { "prefix": "spro", "body": "${1:identifier} : process( ${2:clock} )\nbegin\n\tif( rising_edge(${2:clock}) ) then\n\t\t$0\n\tend if ;\nend process ; -- ${1:identifier}", "description": "synchronous process", "scope": "source.vhdl" }, + "slv": { "prefix": "slv", "body": "std_logic_vector(${1:x} downto ${2:0}) ;$0", "description": "std_logic_vector downto", "scope": "source.vhdl" }, + "slvr": { "prefix": "slvr", "body": "std_logic_vector(${1:signal}'range) ;$0", "description": "std_logic_vector range", "scope": "source.vhdl" }, + "u": { "prefix": "u", "body": "unsigned(${1:x} downto ${2:0}) ;$0", "description": "unsigned downto", "scope": "source.vhdl" }, + "ur": { "prefix": "ur", "body": "unsigned(${1:signal}'range) ;$0", "description": "unsigned range", "scope": "source.vhdl" }, + "vhdl": { "prefix": "vhdl", "body": "library ieee ;\n\tuse ieee.std_logic_1164.all ;\n\tuse ieee.numeric_std.all ;\n\nentity ${1:ent} is\n port (\n\t${0:clock}\n ) ;\nend ${1:ent} ; \n\narchitecture ${2:arch} of ${1:ent} is\n\nbegin\n\nend architecture ;", "description": "vhdl template", "scope": "source.vhdl" }, + "while": { "prefix": "while", "body": "${1:identifier} : while ${2:expression} loop\n\t$0\nend loop ; -- ${1:identifier}", diff --git a/src/function/dide-viewer/index.ts b/src/function/dide-viewer/index.ts index 183216e..8f0cee0 100644 --- a/src/function/dide-viewer/index.ts +++ b/src/function/dide-viewer/index.ts @@ -71,7 +71,7 @@ class WaveViewer { this.panel.iconPath = getIconConfig('view'); registerMessageEvent(this.panel, uri); } else { - WaveViewOutput.report('preview html in is empty', ReportType.Warn); + WaveViewOutput.report('preview html in is empty', { level: ReportType.Warn }); } } @@ -138,7 +138,7 @@ class VcdViewerProvider implements vscode.CustomEditorProvider { webviewPanel.webview.html = preprocessHtml; webviewPanel.iconPath = getIconConfig('view'); } else { - WaveViewOutput.report('preview html in is empty', ReportType.Warn); + WaveViewOutput.report('preview html in is empty', { level: ReportType.Warn }); } } diff --git a/src/function/hdlDoc/markdown.ts b/src/function/hdlDoc/markdown.ts index 1dd1010..2696ee1 100644 --- a/src/function/hdlDoc/markdown.ts +++ b/src/function/hdlDoc/markdown.ts @@ -4,7 +4,7 @@ import * as fspath from 'path'; import { AbsPath, opeParam, MainOutput, ReportType } from '../../global'; import { hdlParam, HdlModule, HdlFile, HdlInstance } from '../../hdlParser/core'; -import { HdlModulePort, HdlModuleParam, InstModPathStatus } from '../../hdlParser/common'; +import { HdlModulePort, HdlModuleParam, InstModPathStatus, HdlFileProjectType } from '../../hdlParser/common'; import { MarkdownString, RenderString, RenderType, mergeSortByLine, getWavedromsFromFile, Count, WavedromString } from './common'; @@ -43,7 +43,7 @@ function selectFieldValue(obj: any, subName: string, ws: string, name: string, i if (fs.existsSync(value)) { // 判断 类型 const hdlFile = hdlParam.getHdlFile(value); - if (hdlFile && hdlFile.type === 'remote_lib') { + if (hdlFile && hdlFile.projectType === HdlFileProjectType.RemoteLib) { // 如果是 库 文件,做出更加自定义的字面量 const libRelPath = value.replace(`${opeParam.extensionPath}/library/`, ''); value = `library [${libRelPath}](file://${value})`; @@ -277,10 +277,12 @@ async function getDocsFromFile(path: AbsPath): Promise line: ${errorLine}, info: ${syntaxInfo}`, ReportType.Run); + LspOutput.report(` line: ${errorLine}, info: ${syntaxInfo}`, { + level: ReportType.Run + }); const range = this.makeCorrectRange(document, errorLine, syntaxInfo); const diag = new vscode.Diagnostic(range, syntaxInfo, vscode.DiagnosticSeverity.Error); @@ -136,8 +141,13 @@ class VivadoLinter implements BaseLinter { const fullExecutorName = opeParam.os === 'win32' ? executorName + '.bat' : executorName; if (vivadoInstallPath.trim() === '' || !fs.existsSync(vivadoInstallPath)) { - LspOutput.report(`User's Vivado Install Path "${vivadoInstallPath}", which is invalid. Use ${executorName} in default.`, ReportType.Warn); - LspOutput.report('If you have doubts, check prj.vivado.install.path in setting', ReportType.Warn); + LspOutput.report(`User's Vivado Install Path "${vivadoInstallPath}", which is invalid. Use ${executorName} in default.`, { + level: ReportType.Warn + }); + LspOutput.report('If you have doubts, check prj.vivado.install.path in setting', { + level: ReportType.Warn + }); + return executorName; } else { LspOutput.report(`User's Vivado Install Path "${vivadoInstallPath}", which is invalid`); @@ -161,11 +171,16 @@ class VivadoLinter implements BaseLinter { const { stderr } = await easyExec(executorPath, []); if (stderr.length === 0) { this.executableInvokeNameMap.set(langID, executorPath); - LspOutput.report(`success to verify ${executorPath}, linter from vivado is ready to go!`, ReportType.Launch); + LspOutput.report(`success to verify ${executorPath}, linter from vivado is ready to go!`, { + level: ReportType.Launch + }); return true; } else { this.executableInvokeNameMap.set(langID, undefined); - LspOutput.report(`Fail to execute ${executorPath}! Reason: ${stderr}`, ReportType.Error, true); + LspOutput.report(`Fail to execute ${executorPath}! Reason: ${stderr}`, { + level: ReportType.Error, + notify: true + }); return false; } } diff --git a/src/function/netlist/index.ts b/src/function/netlist/index.ts index 546d30e..acb4a2e 100644 --- a/src/function/netlist/index.ts +++ b/src/function/netlist/index.ts @@ -31,10 +31,12 @@ class Netlist { const standardPath = hdlPath.toSlash(path); const response = await doFastApi(standardPath, 'common'); const langID = hdlFile.getLanguageId(standardPath); + const projectType = hdlParam.getHdlFileProjectType(standardPath, 'common'); moduleFile = new HdlFile( standardPath, langID, response?.macro || defaultMacro, response?.content || [], + projectType, 'common' ); // 从 hdlParam 中去除,避免干扰全局 diff --git a/src/function/sim/simulate.ts b/src/function/sim/simulate.ts index 855da58..4c4e511 100644 --- a/src/function/sim/simulate.ts +++ b/src/function/sim/simulate.ts @@ -73,7 +73,10 @@ class Simulate { }; let code = hdlFile.readFile(path); if (!code) { - MainOutput.report('error when read ' + path, ReportType.Error, true); + MainOutput.report('error when read ' + path, { + level: ReportType.Error, + notify: true + }); return; } @@ -95,7 +98,9 @@ class Simulate { if (!hdlFile.isDir(simConfig.simulationHome)) { - MainOutput.report('create dir ' + simConfig.simulationHome, ReportType.Info); + MainOutput.report('create dir ' + simConfig.simulationHome, { + level: ReportType.Info + }); hdlDir.mkdir(simConfig.simulationHome); } @@ -113,7 +118,10 @@ class Simulate { simConfig.installPath = setting.get('digital-ide.function.simulate.icarus.installPath', ''); if (simConfig.installPath !== '' && !hdlFile.isDir(simConfig.installPath)) { - MainOutput.report(`install path ${simConfig.installPath} is illegal`, ReportType.Error, true); + MainOutput.report(`install path ${simConfig.installPath} is illegal`, { + level: ReportType.Error, + notify: true + }); return; } @@ -252,7 +260,9 @@ class IcarusSimulate extends Simulate { // console.log(thirdLibraryFileArgs); const cmd = `${iverilogPath} ${argu} -o ${outVvpPath} -s ${name} ${macroIncludeArgs} ${thirdLibraryDirArgs} ${mainPath} ${dependenceArgs} ${thirdLibraryFileArgs}`; - MainOutput.report(cmd, ReportType.Run); + MainOutput.report(cmd, { + level: ReportType.Run + }); return cmd; } @@ -287,26 +297,42 @@ class IcarusSimulate extends Simulate { } child_process.exec(command, { cwd }, (error, stdout, stderr) => { if (error) { - MainOutput.report('Error took place when run ' + command, ReportType.Error); - MainOutput.report('Reason: ' + stderr, ReportType.Error); + MainOutput.report('Error took place when run ' + command, { + level: ReportType.Error + }); + MainOutput.report('Reason: ' + stderr, { + level: ReportType.Error + }); } else { - MainOutput.report(stdout, ReportType.Info); + MainOutput.report(stdout, { + level: ReportType.Info + }); const vvpOutFile = hdlPath.join(simConfig.simulationHome, 'out.vvp'); - MainOutput.report("Create vvp to " + vvpOutFile, ReportType.Run); + MainOutput.report("Create vvp to " + vvpOutFile, { + level: ReportType.Run + }); const outVvpPath = hdlPath.join(simConfig.simulationHome, 'out.vvp'); const vvpPath = simConfig.vvpPath; // run vvp to interrupt script const vvpCommand = `${vvpPath} ${outVvpPath}`; - MainOutput.report(vvpCommand, ReportType.Run); + MainOutput.report(vvpCommand, { + level: ReportType.Run + }); child_process.exec(vvpCommand, { cwd }, (error, stdout, stderr) => { if (error) { - MainOutput.report('Error took place when run ' + vvpCommand, ReportType.Error); - MainOutput.report('Reason: ' + stderr, ReportType.Error); + MainOutput.report('Error took place when run ' + vvpCommand, { + level: ReportType.Error + }); + MainOutput.report('Reason: ' + stderr, { + level: ReportType.Error + }); } else { - MainOutput.report(stdout, ReportType.Info); + MainOutput.report(stdout, { + level: ReportType.Info + }); } }); } @@ -355,7 +381,10 @@ class IcarusSimulate extends Simulate { this.exec(simulationCommand, cwd); } else { const errorMsg = 'Fail to generate command'; - MainOutput.report(errorMsg, ReportType.Error, true); + MainOutput.report(errorMsg, { + level: ReportType.Error, + notify: true + }); return; } } @@ -386,15 +415,13 @@ class IcarusSimulate extends Simulate { } const standardPath = hdlPath.toSlash(path); - console.log('enter [doFastApi]'); const response = await doFastApi(standardPath, 'common'); - console.log('response result: '); - console.log(response); - + const projectType = hdlParam.getHdlFileProjectType(standardPath, 'common'); const moduleFile = new HdlFile( standardPath, langID, response?.macro || defaultMacro, response?.content || [], + projectType, 'common' ); // 从 hdlParam 中去除,避免干扰全局 @@ -418,7 +445,10 @@ class IcarusSimulate extends Simulate { if (targetModule !== undefined) { this.simulateByHdlModule(targetModule); } else { - MainOutput.report('There is no module named ' + view.name + ' in ' + view.path, ReportType.Error, true); + MainOutput.report('There is no module named ' + view.name + ' in ' + view.path, { + level: ReportType.Error, + notify: true + }); return; } } diff --git a/src/function/treeView/index.ts b/src/function/treeView/index.ts index 50b472d..5dac4de 100644 --- a/src/function/treeView/index.ts +++ b/src/function/treeView/index.ts @@ -49,7 +49,9 @@ function openFileByUri(path: string, range: Range, element: ModuleDataItem) { } } } - MainOutput.report("invalid jump uri triggered in treeview, el: " + JSON.stringify(element, null, ' '), ReportType.Error); + MainOutput.report("invalid jump uri triggered in treeview, el: " + JSON.stringify(element, null, ' '), { + level: ReportType.Error + }); } function gotoXilinxIPDefinition(element: ModuleDataItem) { @@ -63,7 +65,9 @@ function gotoXilinxIPDefinition(element: ModuleDataItem) { vscode.window.showInformationMessage(t('info.treeview.ip-no-active.message')); } } else { - MainOutput.report("[gotoXilinxIPDefinition] path is undefined", ReportType.Error); + MainOutput.report("[gotoXilinxIPDefinition] path is undefined", { + level: ReportType.Error + }); } } diff --git a/src/function/treeView/tree.ts b/src/function/treeView/tree.ts index e0f9ee6..40e8ed6 100644 --- a/src/function/treeView/tree.ts +++ b/src/function/treeView/tree.ts @@ -3,7 +3,7 @@ import * as vscode from 'vscode'; import { AbsPath, MainOutput, opeParam, ReportType } from '../../global'; import { SimPath, SrcPath } from '../../global/prjInfo'; import { HdlInstance, hdlParam } from '../../hdlParser/core'; -import { HdlFileType, Range } from '../../hdlParser/common'; +import { HdlFileProjectType, Range } from '../../hdlParser/common'; import { hdlFile, hdlPath } from '../../hdlFs'; import { xilinx, itemModes, otherModes } from './common'; import { getIconConfig } from '../../hdlFs/icons'; @@ -71,7 +71,7 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { this.srcRootItem = { icon: 'src', - type: HdlFileType.Src, + type: HdlFileProjectType.Src, doFastFileType: undefined, name: 'src', range: undefined, @@ -81,7 +81,7 @@ class ModuleTreeProvider implements vscode.TreeDataProvider { this.simRootItem = { icon: 'sim', - type: HdlFileType.Sim, + type: HdlFileProjectType.Sim, doFastFileType: undefined, name: 'sim', range: undefined, diff --git a/src/global/outputChannel.ts b/src/global/outputChannel.ts index c3d018b..93cd4d2 100644 --- a/src/global/outputChannel.ts +++ b/src/global/outputChannel.ts @@ -2,16 +2,53 @@ import * as vscode from 'vscode'; enum ReportType { + /** + * debug + */ Debug = 'Debug', + /** + * 某些模块或者子进程启动函数中的输出,用来判断子模块是否正常启动 + */ Launch = 'Launch', + /** + * 测量性能相关的输出 + */ Performance = 'Performance', + /** + * debug 查看路径有效性相关的输出 + */ PathCheck = 'Path Check', + /** + * 普通消息的信息 + */ Info = 'Info', + /** + * warn 等级的信息 + */ Warn = 'Warn', + /** + * error 等级的信息 + */ Error = 'Error', + /** + * 某些功能或者子进程在运行中产出的信息 + */ Run = 'Run' }; +interface ReportOption { + /** + * 汇报的等级,类似于日志系统中的 level,详见 + * [ReportType](https://github.com/Digital-EDA/Digital-IDE/blob/main/src/global/outputChannel.ts#L4) + */ + level?: ReportType, + /** + * 用于控制是否同时也在窗口右下角展示信息。如果为 true,则同时会 + * 调用 vscode.window.showInformationMessage 在右下角展示信息。默认为 false + */ + notify?: boolean +} + class Output { private _output: vscode.OutputChannel; private _ignoreTypes: ReportType[]; @@ -51,19 +88,21 @@ class Output { } /** - * + * @description 信息汇报函数,用于将字符串显示在 Output 窗口中,也可可以同时显示右下角的窗口中 * @param message message - * @param type report type - * @param reportInWindows whether use vscode.windows. to show info + * @param option 汇报的选项 */ - public report(message: string | unknown, type: ReportType = ReportType.Info, reportInWindows: boolean = false) { - if (!this.skipMessage(type) && message) { - // this._output.show(true); + public report(message: string | unknown, option?: ReportOption) { + option = option || { level: ReportType.Info, notify: false } as ReportOption; + const level = option.level || ReportType.Info; + const notify = option.notify || false; + + if (!this.skipMessage(level) && message) { const currentTime = this.getCurrentTime(); - this._output.appendLine('[' + type + ' - ' + currentTime + '] ' + message); + this._output.appendLine('[' + level + ' - ' + currentTime + '] ' + message); - if (reportInWindows) { - this.showInWindows('' + message, type); + if (notify) { + this.showInWindows('' + message, level); } } } diff --git a/src/global/prjInfo.ts b/src/global/prjInfo.ts index 0cefc3a..f19bbec 100644 --- a/src/global/prjInfo.ts +++ b/src/global/prjInfo.ts @@ -233,6 +233,7 @@ class PrjInfo implements PrjInfoMeta { const psname = this.prjName.PS; // TODO : packaging the replacer + // TODO : 支持路径的正则表达式 return path.replace(/\$\{workspace\}/g, workspacePath) .replace(/\$\{plname\}/g, plname) .replace(/\$\{psname\}/g, psname); @@ -593,6 +594,11 @@ class PrjInfo implements PrjInfoMeta { return libPath; } + /** + * @description 代表当前的 arch.hardware.sim 的值 + * 标准结构下应为 user/sim 的绝对路径 + * 空则返回默认值 workspace path + */ public get hardwareSimPath(): AbsPath { const simPath = this._arch.hardware.sim; const workspace = this._workspacePath; @@ -604,6 +610,11 @@ class PrjInfo implements PrjInfoMeta { return hdlPath.join(workspace, simPath); } + /** + * @description 代表当前的 arch.hardware.src 的值 + * 标准结构下应为 user/src 的绝对路径 + * 空则返回默认值 workspace path + */ public get hardwareSrcPath(): AbsPath { const srcPath = this._arch.hardware.src; const workspace = this._workspacePath; @@ -617,6 +628,30 @@ class PrjInfo implements PrjInfoMeta { return hdlPath.join(workspace, srcPath); } + /** + * @description user/ip 的绝对路径 + */ + public get ipPath(): AbsPath { + const workspace = this._workspacePath; + return hdlPath.join(workspace, 'user', 'ip'); + } + + /** + * @description user/src/lib 绝对路径 + */ + public get localLibPath(): AbsPath { + const workspace = this._workspacePath; + return hdlPath.join(workspace, 'user', 'src', 'lib'); + } + + /** + * @description ${extensionPath}/library 绝对路径 + */ + public get remoteLibPath(): AbsPath { + const extensionPath = this._extensionPath; + return hdlPath.join(extensionPath, 'library'); + } + public json(): RawPrjInfo { return { toolChain: this._toolChain, diff --git a/src/hdlFs/file.ts b/src/hdlFs/file.ts index fe116c7..75b3523 100644 --- a/src/hdlFs/file.ts +++ b/src/hdlFs/file.ts @@ -5,7 +5,7 @@ import { AbsPath, RelPath } from '../global'; import { HdlLangID } from '../global/enum'; import { verilogExts, vhdlExts, systemVerilogExts, hdlExts } from '../global/lang'; import * as hdlPath from './path'; -import { HdlFileType } from '../hdlParser/common'; +import { HdlFileProjectType } from '../hdlParser/common'; import { opeParam } from '../global'; /** @@ -139,24 +139,6 @@ function getLanguageId(path: AbsPath | RelPath): HdlLangID { } -function getHdlFileType(path: AbsPath) : HdlFileType { - const uniformPath = hdlPath.toSlash(path); - const arch = opeParam.prjInfo.arch; - const srcPath: AbsPath = arch.hardware.src; - const simPath: AbsPath = arch.hardware.sim; - const wsPath: AbsPath = opeParam.workspacePath; - if (uniformPath.includes(srcPath)) { - return HdlFileType.Src; - } else if (uniformPath.includes(simPath)) { - return HdlFileType.Sim; - } else if (uniformPath.includes(wsPath)) { - return HdlFileType.LocalLib; - } else { - return HdlFileType.RemoteLib; - } -} - - function readFile(path: AbsPath): string | undefined { try { const content = fs.readFileSync(path, 'utf-8'); @@ -376,7 +358,6 @@ export { readJSON, writeJSON, rmSync, - getHdlFileType, pickFileRecursive, isHasAttr, isHasValue, diff --git a/src/hdlParser/common.ts b/src/hdlParser/common.ts index 8ff47ac..f1a48d2 100644 --- a/src/hdlParser/common.ts +++ b/src/hdlParser/common.ts @@ -32,11 +32,23 @@ enum HdlModulePortType { enum HdlModuleParamType {LocalParam, Parameter, Unknown}; -enum HdlFileType { +/** + * @description 用于描述当前的这个 HDL 文件是会被系统视为哪一种进行处理 + * - Src: src 目录文件 + * - Sim: sim 目录文件 + * - LocalLib: 局部库文件 + * - RemoteLib: 全局库文件 + * - IP: IP 核 + * - Primitive: 原语 + */ +enum HdlFileProjectType { Src = 'src', Sim = 'sim', LocalLib = 'local_lib', - RemoteLib = 'remote_lib' + RemoteLib = 'remote_lib', + IP = 'ip', + Primitive = 'primitive', + Unknown = 'unknown' }; enum InstModPathStatus {Current, Include, Others, Unknown}; @@ -214,7 +226,7 @@ export { InstRange, HdlModulePortType, HdlModuleParamType, - HdlFileType, + HdlFileProjectType, InstModPathStatus, Error, Define, diff --git a/src/hdlParser/core.ts b/src/hdlParser/core.ts index f1c1b05..0c46a77 100644 --- a/src/hdlParser/core.ts +++ b/src/hdlParser/core.ts @@ -58,7 +58,9 @@ class HdlParam { await this.doHdlFast(path, 'common'); const hdlFile = this.getHdlFile(path); if (!hdlFile) { - MainOutput.report('error happen when we attempt to add file by path: ' + path, ReportType.Error); + MainOutput.report('error happen when we attempt to add file by path: ' + path, { + level: ReportType.Error + }); } else { hdlFile.makeInstance(); // when a new file is added, retry the solution of dependency @@ -134,11 +136,11 @@ class HdlParam { } public selectTopModuleSourceByFileType(hdlModule: HdlModule): Set { - switch (hdlModule.file.type) { - case common.HdlFileType.Src: return this.srcTopModules; - case common.HdlFileType.Sim: return this.simTopModules; - case common.HdlFileType.LocalLib: return this.srcTopModules; - case common.HdlFileType.RemoteLib: return this.srcTopModules; + switch (hdlModule.file.projectType) { + case common.HdlFileProjectType.Src: return this.srcTopModules; + case common.HdlFileProjectType.Sim: return this.simTopModules; + case common.HdlFileProjectType.LocalLib: return this.srcTopModules; + case common.HdlFileProjectType.RemoteLib: return this.srcTopModules; default: return this.srcTopModules; } } @@ -152,6 +154,10 @@ class HdlParam { topModuleSource.add(hdlModule); } + /** + * @description 根据输入的 module 把它从所属的 src 或者 sim 的 topmodules 中去除 + * @param hdlModule + */ public deleteTopModuleToSource(hdlModule: HdlModule) { const topModuleSource = this.selectTopModuleSourceByFileType(hdlModule); topModuleSource.delete(hdlModule); @@ -238,15 +244,21 @@ class HdlParam { const fast = await HdlSymbol.fast(path, fileType); if (fast) { const languageId = this.getRealLanguageId(path, fast.fileType); + const fileProjectType = this.getHdlFileProjectType(path, fast.fileType); new HdlFile(path, languageId, fast.macro, fast.content, + fileProjectType, fast.fileType); } } catch (error) { - MainOutput.report('Error happen when parse ' + path, ReportType.Error); - MainOutput.report('Reason: ' + error, ReportType.Error); + MainOutput.report('Error happen when parse ' + path, { + level: ReportType.Error + }); + MainOutput.report('Reason: ' + error, { + level: ReportType.Error + }); } } @@ -257,6 +269,32 @@ class HdlParam { return hdlFile.getLanguageId(path); } + public getHdlFileProjectType(path: string, fileType: DoFastFileType): common.HdlFileProjectType { + switch (fileType) { + case 'common': + // 根据前缀来判断对应的类型 + path = hdlPath.toSlash(path); + const prjInfo = opeParam.prjInfo; + + if (path.startsWith(prjInfo.hardwareSrcPath)) { + return common.HdlFileProjectType.Src; + } else if (path.startsWith(prjInfo.hardwareSimPath)) { + return common.HdlFileProjectType.Sim; + } else if (path.startsWith(prjInfo.ipPath)) { + return common.HdlFileProjectType.IP; + } else if (path.startsWith(prjInfo.localLibPath)) { + return common.HdlFileProjectType.LocalLib; + } else if (path.startsWith(prjInfo.remoteLibPath)) { + return common.HdlFileProjectType.RemoteLib; + } else { + return common.HdlFileProjectType.Unknown; + } + case 'ip': + return common.HdlFileProjectType.IP; + case 'primitives': + return common.HdlFileProjectType.Primitive; + } + } public async initializeHdlFiles(hdlFiles: AbsPath[], progress: vscode.Progress) { let count: number = 0; @@ -343,8 +381,8 @@ class HdlParam { } switch (type) { - case common.HdlFileType.Src: return this.getSrcTopModules(); - case common.HdlFileType.Sim: return this.getSimTopModules(); + case common.HdlFileProjectType.Src: return this.getSrcTopModules(); + case common.HdlFileProjectType.Sim: return this.getSimTopModules(); default: return []; } } @@ -399,7 +437,9 @@ class HdlParam { // 初始化 const moduleFile = this.getHdlFile(path); if (!moduleFile) { - MainOutput.report('error happen when create moduleFile ' + path, ReportType.Warn); + MainOutput.report('error happen when create moduleFile ' + path, { + level: ReportType.Warn + }); } else { moduleFile.makeInstance(); for (const module of moduleFile.getAllHdlModules()) { @@ -481,19 +521,25 @@ class HdlInstance { this.locateHdlModule(); } + /** + * @description 定位出当前 instance 的模块是什么,并将模块对应的 HdlModule (普通 HDL、IP、原语) 赋值到 this.module 上 + * 对于存在于结构树中的 HdlModule (普通 HDL & IP),改变这些 HdlModule 的 ref 并修改顶层模块相关的属性 + */ public locateHdlModule() { const instModPath = this.instModPath; const instModName = this.type; if (instModPath) { - this.module = hdlParam.getHdlModule(instModPath, instModName); - - // add refer for module - this.module?.addGlobalReferedInstance(this); - // if module and parent module share the same source (e.g both in src folder) - if (this.isSameSourceInstantiation()) { - // 增加当前 instance 的引用,并从对应类型的顶层模块中剔除 - this.module?.addLocalReferedInstance(this); + const module = hdlParam.getHdlModule(instModPath, instModName); + if (module) { + this.module = module; + // 增加当前模块的 global ref + this.module.addGlobalReferedInstance(this); + // 如果当前 instance 对应的例化是同源例化,则 + // 增加当前 instance 的 local ref,并从对应类型的顶层模块中剔除 + if (this.isSameSourceInstantiation()) { + this.module?.addLocalReferedInstance(this); + } } } else { doPrimitivesJudgeApi(instModName).then(isPrimitive => { @@ -503,6 +549,9 @@ class HdlInstance { const fakeModule = new HdlModule( XilinxPrimitivesHdlFile, instModName, defaultRange, [], [], []); this.module = fakeModule; + // 原语在任何情况下都不是顶层模块 + hdlParam.deleteTopModule(fakeModule); + hdlParam.deleteTopModuleToSource(fakeModule); } } }); @@ -513,24 +562,37 @@ class HdlInstance { /** * @description 判断当前的 `instance` 对应的例化行为是否为一个同源例化 (SSI, same source instantiation) * - * 对于标准项目结构,也就是 src + sim ,如果在 moduleA 中完成了 moduleB 的例化,且 moduleA 和 moduleB 都是 src 文件夹下的, + * - 对于标准项目结构,也就是 src + sim ,如果在 moduleA 中完成了 moduleB 的例化,且 moduleA 和 moduleB 都是 src 文件夹下的, * 那么这个例化就是一个同源例化;如果 moduleB 在 sim 下, moduleA 在 src 下,那么当前的例化就是一个非同源例化。 - * - * 同源例化造成的引用为 local ref,非同源例化 + 同源例化造成的引用为 global ref。在模块树下, src 文件夹下的只有 local ref 为空的 module 才是顶层模块 + * - 对于 library 和 IP 这两种类型的 module,对于它们的例化一律视为同源引用。 + * - 同源例化造成的引用为 local ref,非同源例化 + 同源例化造成的引用为 global ref。在模块树下, src 文件夹下的只有 local ref 为空的 module 才是顶层模块 * 换句话说,非同源例化一定不会造成顶层模块的变化,但是同源例化有可能会。 * @returns */ public isSameSourceInstantiation(): boolean { - const parentMod = this.parentMod; - const instMod = this.module; - if (instMod) { - return parentMod.file.type === instMod.file.type; + const parentModule = this.parentMod; + const belongModule = this.module; + + // 当前 instance 仍然是 unsolved 状态,返回 false 不参与后续的 ref 计算 + if (!belongModule) { + return false; } - return false; + + // instance 模块本身是 library / IP / 原语,一律视为 SSI + if (belongModule.file.projectType === common.HdlFileProjectType.IP || + belongModule.file.projectType === common.HdlFileProjectType.Primitive || + belongModule.file.projectType === common.HdlFileProjectType.LocalLib || + belongModule.file.projectType === common.HdlFileProjectType.RemoteLib + ) { + return true; + } + + // 剩余情况下,一律根据 type 判断 + return parentModule.file.projectType === belongModule.file.projectType; } /** - * @description update Instance of each time + * @description 更新当前的 instance * @param newInstance */ public update(newInstance: common.RawHdlInstance) { @@ -685,8 +747,9 @@ class HdlModule { } // this.rawInstances = undefined; } else { - MainOutput.report('call makeNameToInstances but this.rawInstances is undefined', - ReportType.Warn); + MainOutput.report('call makeNameToInstances but this.rawInstances is undefined', { + level: ReportType.Warn + }); } } @@ -885,23 +948,30 @@ class HdlModule { }; export class HdlFile { + // 标准化的文件绝对路径 public path: string; + // 对应的 HDL 语言 ID public languageId: HdlLangID; - public type: common.HdlFileType; + // 文件的项目类型 + public projectType: common.HdlFileProjectType; + // 文件的解析模式 public doFastType: DoFastFileType; + // 当前文件的宏 public macro: common.Macro; + // 维护当前文件内部 module 的 map private readonly nameToModule: Map; constructor(path: string, languageId: HdlLangID, macro: common.Macro, modules: common.RawHdlModule[], + projectType: common.HdlFileProjectType, doFastType: DoFastFileType) { this.path = path; this.languageId = languageId; this.macro = macro; - this.type = hdlFile.getHdlFileType(path); + this.projectType = projectType; this.doFastType = doFastType; // add to global hdlParam @@ -987,8 +1057,13 @@ export class HdlFile { } } -export const XilinxPrimitivesHdlFile = new HdlFile('xilinx-primitives', HdlLangID.Verilog, defaultMacro, [], 'primitives'); - +export const XilinxPrimitivesHdlFile = new HdlFile( + 'xilinx-primitives', + HdlLangID.Verilog, + defaultMacro, + [], + common.HdlFileProjectType.Primitive, + 'primitives'); export { diff --git a/src/manager/PL/index.ts b/src/manager/PL/index.ts index 5379993..d4215a7 100644 --- a/src/manager/PL/index.ts +++ b/src/manager/PL/index.ts @@ -10,7 +10,7 @@ import { opeParam } from '../../global'; import { ToolChainType } from '../../global/enum'; import { hdlFile, hdlPath } from '../../hdlFs'; import { moduleTreeProvider, ModuleDataItem } from '../../function/treeView/tree'; -import { HdlFileType } from '../../hdlParser/common'; +import { HdlFileProjectType } from '../../hdlParser/common'; import { PropertySchema } from '../../global/propertySchema'; import { HardwareOutput, ReportType } from '../../global/outputChannel'; import { t } from '../../i18n'; @@ -31,15 +31,7 @@ class PlManage extends BaseManage { const curToolChain = this.context.tool; if (curToolChain === ToolChainType.Xilinx) { - const vivadoPath = vscode.workspace.getConfiguration('digital-ide.prj.vivado.install').get('path', ''); - if (hdlFile.isDir(vivadoPath)) { - this.context.path = hdlPath.join(hdlPath.toSlash(vivadoPath), 'vivado'); - if (opeParam.os === 'win32') { - this.context.path += '.bat'; - } - } else { - this.context.path = 'vivado'; - } + this.context.path = this.context.ope.updateVivadoPath(); } } @@ -104,7 +96,7 @@ class PlManage extends BaseManage { HardwareOutput.show(); this.context.process.stdin.write('exit\n'); - HardwareOutput.report(t('info.pl.exit.title'), ReportType.Info); + HardwareOutput.report(t('info.pl.exit.title')); this.context.process = undefined; } @@ -112,8 +104,8 @@ class PlManage extends BaseManage { public setSrcTop(item: ModuleDataItem) { this.context.ope.setSrcTop(item.name, this.context); const type = moduleTreeProvider.getItemType(item); - if (type === HdlFileType.Src) { - moduleTreeProvider.setFirstTop(HdlFileType.Src, item.name, item.path); + if (type === HdlFileProjectType.Src) { + moduleTreeProvider.setFirstTop(HdlFileProjectType.Src, item.name, item.path); moduleTreeProvider.refreshSrc(); } } @@ -121,8 +113,8 @@ class PlManage extends BaseManage { public setSimTop(item: ModuleDataItem) { this.context.ope.setSimTop(item.name, this.context); const type = moduleTreeProvider.getItemType(item); - if (type === HdlFileType.Sim) { - moduleTreeProvider.setFirstTop(HdlFileType.Sim, item.name, item.path); + if (type === HdlFileProjectType.Sim) { + moduleTreeProvider.setFirstTop(HdlFileProjectType.Sim, item.name, item.path); moduleTreeProvider.refreshSim(); } } diff --git a/src/manager/PL/xilinx.ts b/src/manager/PL/xilinx.ts index 5863610..a842ae1 100644 --- a/src/manager/PL/xilinx.ts +++ b/src/manager/PL/xilinx.ts @@ -13,6 +13,7 @@ import { XilinxIP } from '../../global/enum'; import { HardwareOutput, MainOutput, ReportType } from '../../global/outputChannel'; import { debounce } from '../../global/util'; import { t } from '../../i18n'; +import { HdlFileProjectType } from '../../hdlParser/common'; interface XilinxCustom { ipRepo: AbsPath, @@ -172,14 +173,14 @@ class XilinxOperation { } const tclPath = hdlPath.join(this.xilinxPath, 'launch.tcl'); - scripts.push(this.getRefreshCmd()); + scripts.push(this.getRefreshXprDesignSourceCommand()); scripts.push(`file delete ${tclPath} -force`); const tclCommands = scripts.join('\n') + '\n'; hdlFile.writeFile(tclPath, tclCommands); const argu = `-notrace -nolog -nojournal`; + context.path = this.updateVivadoPath(); const cmd = `${context.path} -mode tcl -s ${tclPath} ${argu}`; - const _this = this; @@ -193,6 +194,7 @@ class XilinxOperation { } // 执行 cmd 启动 const vivadoProcess = spawn(cmd, [], { shell: true, stdio: 'pipe', cwd: opeParam.workspacePath }); + let status: 'pending' | 'fulfilled' = 'pending'; vivadoProcess.on('close', () => { onVivadoClose(); @@ -204,13 +206,6 @@ class XilinxOperation { onVivadoClose(); }); - vivadoProcess.stderr.on('data', data => { - HardwareOutput.report(data.toString(), ReportType.Error); - HardwareOutput.show(); - }); - - let status: 'pending' | 'fulfilled' = 'pending'; - return new Promise(resolve => { vivadoProcess.stdout.on('data', data => { const message: string = _this.handleMessage(data.toString(), status); @@ -219,15 +214,42 @@ class XilinxOperation { HardwareOutput.show(); resolve(vivadoProcess); } - HardwareOutput.report(message, ReportType.Info); + HardwareOutput.report(message, { + level: ReportType.Info + }); status = 'fulfilled'; }); + + vivadoProcess.stderr.on('data', async data => { + HardwareOutput.report(data.toString(), { + level: ReportType.Error + }); + HardwareOutput.show(); + if (status === 'pending') { + // pending 阶段就出现 stderr 说明启动失败 + resolve(undefined); + + const vivadoInstallPath = vscode.workspace.getConfiguration('digital-ide').get('prj.vivado.install.path') || ''; + + const res = await vscode.window.showErrorMessage( + t('error.pl.launch.not-valid-vivado-path', data.toString(), vivadoInstallPath.toString()), + { + title: t('info.pl.launch.set-vivado-path'), + value: true + } + ); + if (res?.value) { + await vscode.commands.executeCommand('workbench.action.openSettings', 'digital-ide.prj.vivado.install.path'); + } + } + }); }); } const process = await vscode.window.withProgress({ title: t('info.pl.launch.progress.launch-tcl.title'), - location: vscode.ProgressLocation.Notification + location: vscode.ProgressLocation.Notification, + cancellable: true }, async () => { return await launchScript(); }); @@ -280,7 +302,11 @@ class XilinxOperation { scripts.push(`open_project ${path} -quiet`); } - private getRefreshCmd(): string { + /** + * @description 更新 xpr 设计源的命令 + * @returns + */ + private getRefreshXprDesignSourceCommand(): string { const scripts: string[] = []; // 清除所有源文件 scripts.push(`remove_files -quiet [get_files]`); @@ -358,13 +384,25 @@ class XilinxOperation { }); // 导入非本地的设计源文件 - const HDLFiles = hdlParam.getAllHdlFiles(); - for (const file of HDLFiles) { - // TODO: 新增library的add_files - if (file.type === "src") { - scripts.push(`add_files ${file.path} -quiet`); + for (const hdlFile of hdlParam.getAllHdlFiles()) { + switch (hdlFile.projectType) { + case HdlFileProjectType.Src: + case HdlFileProjectType.LocalLib: + case HdlFileProjectType.RemoteLib: + // src 和 library 加入 source_1 设计源 + scripts.push(`add_file ${hdlFile.path} -quiet`); + break; + case HdlFileProjectType.Sim: + // sim 加入 sim_1 设计源 + scripts.push(`add_file -fileset sim_1 ${hdlFile.path} -quiet`); + break; + case HdlFileProjectType.IP: + case HdlFileProjectType.Primitive: + // IP 和 原语不用管 + break; + default: + break; } - scripts.push(`add_files -fileset sim_1 ${file.path} -quiet`); } scripts.push(`add_files -fileset constrs_1 ${this.datPath} -quiet`); @@ -389,8 +427,12 @@ class XilinxOperation { return cmd; } + /** + * @description 【Xilinx Vivado 操作】更新 xpr 文件 + * @param context + */ public refresh(context: PLContext) { - const cmd = this.getRefreshCmd(); + const cmd = this.getRefreshXprDesignSourceCommand(); context.process?.stdin.write(cmd + '\n'); } @@ -590,7 +632,9 @@ file delete ${scriptPath} -force\n`; if (context.process) { context.process.stdin.write('start_gui -quiet\n'); - HardwareOutput.report(t('info.pl.gui.report-title'), ReportType.Info); + HardwareOutput.report(t('info.pl.gui.report-title'), { + level: ReportType.Info + }); HardwareOutput.show(); this.guiLaunched = true; } @@ -600,7 +644,7 @@ file delete ${scriptPath} -force\n`; if (!this.guiLaunched && files.length > 0) { const filesString = files.join("\n"); HardwareOutput.report(t('info.pl.add-files.title') + '\n' + filesString); - this.processFileInPrj(files, context, "add_file"); + this.execCommandToFilesInTclInterpreter(files, context, "add_file"); } } @@ -608,7 +652,7 @@ file delete ${scriptPath} -force\n`; if (!this.guiLaunched && files.length > 0) { const filesString = files.join("\n"); HardwareOutput.report(t('info.pl.del-files.title') + '\n' + filesString); - this.processFileInPrj(files, context, "remove_files"); + this.execCommandToFilesInTclInterpreter(files, context, "remove_files"); } } @@ -638,7 +682,7 @@ file delete ${scriptPath} -force\n`; * @param context * @param command */ - public processFileInPrj(files: string[], context: PLContext, command: string) { + public execCommandToFilesInTclInterpreter(files: string[], context: PLContext, command: string) { if (context.process === undefined) { return; } @@ -681,6 +725,20 @@ file delete ${scriptPath} -force\n`; MainOutput.report(log); } + + public updateVivadoPath(): string { + const vivadoBinFolder = vscode.workspace.getConfiguration('digital-ide.prj.vivado.install').get('path') || ''; + if (hdlFile.isDir(vivadoBinFolder)) { + let vivadoPath = hdlPath.join(hdlPath.toSlash(vivadoBinFolder), 'vivado'); + if (opeParam.os === 'win32') { + vivadoPath += '.bat'; + } + return vivadoPath; + } else { + // 没有设置 vivado bin 文件夹,就认为用户已经把对应的路径加入环境变量了 + return 'vivado'; + } + } } class XilinxBd { diff --git a/src/manager/index.ts b/src/manager/index.ts index 36f7208..19e7fba 100644 --- a/src/manager/index.ts +++ b/src/manager/index.ts @@ -13,7 +13,9 @@ function registerManagerCommands(context: vscode.ExtensionContext) { // const psManage = prjManage.ps; vscode.commands.registerCommand('digital-ide.property-json.generate', prjManage.generatePropertyJson); - vscode.commands.registerCommand('digital-ide.property-json.overwrite', prjManage.overwritePropertyJson); + + // 丢弃原因:插件更新后,用户修改的部分会被覆盖,没有存在必要了 + // vscode.commands.registerCommand('digital-ide.property-json.overwrite', prjManage.overwritePropertyJson); // libpick vscode.commands.registerCommand('digital-ide.pickLibrary', pickLibrary); diff --git a/src/monitor/event.ts b/src/monitor/event.ts index 2f53416..0de6e24 100644 --- a/src/monitor/event.ts +++ b/src/monitor/event.ts @@ -33,7 +33,9 @@ abstract class BaseAction { public listenChange(m: HdlMonitor) { const fSWatcher = this.selectFSWatcher(m); if (!fSWatcher) { - MainOutput.report("FSWatcher hasn't been made!", ReportType.Error); + MainOutput.report("FSWatcher hasn't been made!", { + level: ReportType.Error + }); return; } fSWatcher.on(Event.Change, path => this.change(path, m)); @@ -42,7 +44,9 @@ abstract class BaseAction { public listenAdd(m: HdlMonitor) { const fSWatcher = this.selectFSWatcher(m); if (!fSWatcher) { - MainOutput.report("FSWatcher hasn't been made!", ReportType.Error); + MainOutput.report("FSWatcher hasn't been made!", { + level: ReportType.Error + }); return; } fSWatcher.on(Event.Add, path => this.add(path, m)); @@ -51,7 +55,9 @@ abstract class BaseAction { public listenUnlink(m: HdlMonitor) { const fSWatcher = this.selectFSWatcher(m); if (!fSWatcher) { - MainOutput.report("FSWatcher hasn't been made!", ReportType.Error); + MainOutput.report("FSWatcher hasn't been made!", { + level: ReportType.Error + }); return; } fSWatcher.on(Event.Unlink, path => this.unlink(path, m)); @@ -75,7 +81,9 @@ class HdlAction extends BaseAction { // check if it has been created if (hdlParam.hasHdlFile(path)) { - MainOutput.report(' HdlFile ' + path + ' has been created', ReportType.Warn); + MainOutput.report(' HdlFile ' + path + ' has been created', { + level: ReportType.Warn + }); return; } @@ -247,7 +255,9 @@ class PpyAction extends BaseAction { // skip hdl remake if (originalLibState !== currentLibState) { const fileChange = await libManage.processLibFiles(opeParam.prjInfo.library); - MainOutput.report(`libManage finish process, add ${fileChange.add.length} files, del ${fileChange.del.length} files`, ReportType.Info); + MainOutput.report(`libManage finish process, add ${fileChange.add.length} files, del ${fileChange.del.length} files`, { + level: ReportType.Info + }); } } else { // update hdl monitor @@ -308,8 +318,6 @@ class PpyAction extends BaseAction { for (const path of delFiles) { hdlParam.deleteHdlFile(path); } - - // 判断新加入的 module 是否还是顶层模块 } @@ -320,7 +328,9 @@ class PpyAction extends BaseAction { const delfileActionTag = '(del files) '; if (addFiles.length > 0) { const reportMsg = ['', ...addFiles].join('\n\t'); - MainOutput.report(addfileActionTag + t('info.pl.xilinx.update-addfiles') + reportMsg, ReportType.Run); + MainOutput.report(addfileActionTag + t('info.pl.xilinx.update-addfiles') + reportMsg, { + level: ReportType.Run + }); await prjManage.pl.addFiles(addFiles); } else { MainOutput.report(addfileActionTag + t('info.pl.xilinx.no-need-add-files')); @@ -328,14 +338,18 @@ class PpyAction extends BaseAction { if (delFiles.length > 0) { const reportMsg = ['', ...delFiles].join('\n\t'); - MainOutput.report(delfileActionTag + t('info.pl.xilinx.update-delfiles') + reportMsg, ReportType.Run); + MainOutput.report(delfileActionTag + t('info.pl.xilinx.update-delfiles') + reportMsg, { + level: ReportType.Run + }); await prjManage.pl.delFiles(delFiles); } else { MainOutput.report(delfileActionTag + t('info.pl.xilinx.no-need-del-files')); } } else { - MainOutput.report('PL is not registered', ReportType.Warn); + MainOutput.report('PL is not registered', { + level: ReportType.Warn + }); } } }