FPGA 第6組
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Write
        • Owners
        • Signed-in users
        • Everyone
        Owners Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Help
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Write
Owners
  • Owners
  • Signed-in users
  • Everyone
Owners Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # FPGA 第六組 Lab3 結報 [文章網址](https://hackmd.io/jy8ZP-5BTEitzMMWkC-8Ow) ## 組員 | 姓名 | 學號 | |:------:|:---------:| | 劉永勝 | F94089032 | | 蔡宗瑾 | E14083137 | | 李宇洋 | E24099025 | ## Problem 1 - RGB LED [[影片連結]](https://www.youtube.com/shorts/wLFn9Q1GFNA) ### Block Design ![](https://i.imgur.com/z3zSR60.png) 不同於上次實驗,這次是要以c code控制led燈的亮燈順序。不像verilog有平行處理的概念,c code是序項執行。因此分成以下3個步驟,依序執行,完成這此實作。 1. Set LED color 設定三個參數,R、G、B,分別代表該顏色的16進為數值。例如紫色的16進制為`0x7f_1f_ff`,則分別指定參數 R = `0x7f`、G = `0x1f`、B = `0xff`。 2. Bright - 根據PWM的觀念,以256個clk cycle作為1個週期,控制R、G、B各別亮燈時間。則步驟一set color的參數就能作為亮燈時間的最大值。見下方程式說明,第一圈for loop表示一個顏色停留的時間,第二圈則表示PWM以256個cycle為一周期。 - 其中較特別的是第3、6、9行,rgb_data會透過XGpio函數,寫到實體LED的port上。由於線寬為 3-bit,由高位元到低位元各別代表B、G、R的開關,紅燈表示 `3'b001`、綠燈表示 `3'b010`、藍燈表示 `3'b100`。藉由不斷開關R、G、B三個燈的,欺騙人眼的方式實現PWM效果。 (但之後發現用c code的arithmetic operator `&`、`|` 會更好) ``` c= for (int Delay = 0; Delay < LED_DELAY; Delay++){ for (int count = 0; count < 256; count ++) { rgb_data = (count < R)? 1 : 0; XGpio_DiscreteWrite(&RGB_Gpio, 1, rgb_data); rgb_data = (count < G)? 2 : 0; XGpio_DiscreteWrite(&RGB_Gpio, 1, rgb_data); rgb_data = (count < B)? 4 : 0; XGpio_DiscreteWrite(&RGB_Gpio, 1, rgb_data); } } ``` 3. Change color 題目要求6個顏色的燈要依序閃爍,則使用的個counter,每閃完一個燈號則加一,對此參數取 `mod6`,則可再步驟一set color時控制顏色。 ## Problem 2 - Sorting ### Algorithm 此專案為單純讓c code跑在processing system上,並沒有使用到AXI介面資料傳輸,因此沒有考慮sorting電路的寫法。我們採用quick sort演算法,quicksort是一種遞迴式的排序演算法,其pseudo code如下所示: ![](https://i.imgur.com/Kzn9CPk.png) ![](https://i.imgur.com/Eswj4XL.png) PARTITION的功能即是將array最右端的值A[r]與array其他值做比較,並且將array分成兩部分,左半部比A[r]小,右半部比A[r]大。 ![](https://i.imgur.com/uP0FMab.png) ### 實作結果 需先輸入要排序的數字總數(key numbers),再依序輸入每一筆數字(key)。 - switch為0: acsending order ![](https://i.imgur.com/mGwZjK8.png) - switch為1: descending order ![](https://i.imgur.com/B3uBnhE.png) ## Problem 3 ### Block Design ![](https://i.imgur.com/HdWOq3u.png) ### 電路設計說明 #### Problem3-1 ##### AXI interface ![](https://i.imgur.com/zBis0d1.png) >slv_reg0 -> operand1 slv_reg1 -> operand2 slv_reg2 -> operator slv_reg3 -> inValid slv_reg4 -> dataResponse slv_reg5 -> outData slv_reg6 -> outValid slv_reg7 -> overflow ![](https://i.imgur.com/5NM5QsW.png) | state | 說明 | |:------:|:----------:| |NOP |閒置狀態,不進行任何操作,並等待inValid訊號。| |ADD |進行加法運算,並且在處理完成後拉高calcDone。| |SUB |進行減法運算,並且在處理完成後拉高calcDone。| |MUL |進行乘法運算,並且在處理完成後拉高calcDone。| |DONE |將outValid設為1,並等待PS發回dataResponse訊號 **(確認已收到Output data)** 後,回到NOP state等待下一次操作。| ##### 設計邏輯 - **PS端(main.c)**: ```cpp= /*--------------------------INPUT--------------------------*/ printf("Please choose calculation mode(1: add, 2: sub, 3: mul):\n\r"); scanf("%d", &opeartor); while(opeartor > 3 || opeartor < 1){ ... } printf("%d\r\n", opeartor); ARITHMETIC_mWriteReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 8, opeartor); // operand1 printf("Please input operand1 (Which is smaller than 127, and bigger -128):\n\r"); scanf("%d", &operand1); while(operand1 > 127 || operand1 < -128){ ... } printf("%d\r\n", operand1); ARITHMETIC_mWriteReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 0, operand1); // operand2 printf("Please input operand2 (Which is smaller than 127, and bigger -128):\n\r"); scanf("%d", &operand2); while(operand2 > 127 || operand2 < -128){ ... } printf("%d\r\n", operand2); ARITHMETIC_mWriteReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 4, operand2); ``` 上方程式碼用於確認使用者的input是否在允許範圍內,並且將value寫入對應的AXI slave register存取的位置。 ```cpp= // inValid high ARITHMETIC_mWriteReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 12, 1); // Wait until the calculation is done while(ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 24) == 0){ ... if(ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 24) == 1){ // inValid low ARITHMETIC_mWriteReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 12, 0); } } if(ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 24) == 1){ // inValid low ARITHMETIC_mWriteReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 12, 0); } printf("Calculation is done!\r\n"); ``` 上方程式碼會將Processor hang在while迴圈直到確認Arithmetic module已經做完運算(如果已經完成會發回outValid訊號)。 ```cpp= // ! Output switch (opeartor) { case 1: printf("Result of %d + %d: %d\n",operand1, operand2, (int8_t)ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 20)); printf("Overflow: %d\n", ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 28)); break; case 2: printf("Result of %d - %d: %d\n",operand1, operand2, (int8_t)ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 20)); printf("Overflow: %d\n", ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 28)); break; case 3: printf("Result of %d * %d: %d\n",operand1, operand2, (int8_t)ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 20)); printf("Overflow: %d\n", ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 28)); break; default: break; } // Told PL the data is received ARITHMETIC_mWriteReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 16, 1); printf("====================================\n"); // Reset for(int i=0;i<9;i++){ printf("Reset slave register %d: %d\n",i,ARITHMETIC_mReadReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 4*i)); ARITHMETIC_mWriteReg(XPAR_ARITHMETIC_0_S00_AXI_BASEADDR, 4*i, 0); } printf("====================================\n"); ``` 最後會將從PL得到的Output結果print出來,告知PL已經收到data(將dataResponse對應的slave register拉高),並且將AXI slave register的data進行重置,進行下一次操作。 - **PL端(Arithmetic.v)**: ```verilog= // Registers reg calcDone, overflow_reg; reg signed [7:0] operand1_reg, operand2_reg; reg signed [15:0] outData_reg; // The redudant bits are for overflow detection // Wires assign outData = outData_reg[7:0]; ... // --------------------- // // outData // // --------------------- // always @(posedge clk) begin case (state) `ADD: begin outData_reg <= operand1_reg + operand2_reg; calcDone <= 1'b1; end `SUB: begin outData_reg <= operand1_reg - operand2_reg; calcDone <= 1'b1; end `MUL: begin outData_reg <= operand1_reg * operand2_reg; calcDone <= 1'b1; end `DONE: begin outData_reg <= outData_reg; calcDone <= 1'b1; end default: begin outData_reg <= 32'd0; calcDone <= 1'b0; end endcase end ``` `outData_reg`會在運算的state將已經儲存好的operand進行對應的運算,並且在`DONE`時將output值維持住,直到PS回傳dataResponse的訊號後回到`NOP`。 ```verilog= // Registers reg calcDone, overflow_reg; reg signed [15:0] outData_reg; // The redudant bits are for overflow detection // Wires assign overflow = overflow_reg; ... // --------------------- // // overflow // // --------------------- // always @(posedge clk) begin if(state == `DONE) begin if(outData_reg > 127 || outData_reg < -128) overflow_reg <= 1'b1; else overflow_reg <= 1'b0; end else overflow_reg <= 1'b0; end ``` `outData_reg`因為有預留好多餘的8-bit空間,所以可以透過其在`DONE`時的value來判斷是否為overflow。 #### Problem3-2 ##### Algorithm 本問題採用insertion sort的演算法來進行電路撰寫,insertion sort的pseudo code如下所示: ![](https://i.imgur.com/5lUa2gH.png) ##### AXI interface ![](https://i.imgur.com/T6ONtu5.png) >slv_reg0 -> inData slv_reg1 -> inEN slv_reg2 -> outData ##### State Diagram ![](https://i.imgur.com/vBqGeS7.png) | state | 說明 | |:------:|:----------:| |INIT |等待PL端接收到PS傳來的input enable訊號,收到後即跳至LOAD| |LOAD |將slv_reg0的輸入資料一筆一筆讀進sorting array A中| |COMPARE|判斷while_condition,確認 j>=0 and A[j]>key此條件| |SWAP |執行上方pseudo code的第6以及第7行| |LAST |執行上方pseudo code的第8行| ##### 設計邏輯 - **PS端(main.c)**: ```cpp= /*--------------------------INPUT--------------------------*/ printf("Please input 8 numbers:\n\r"); for(i = 0; i < 8; i++) { printf("Input No.%d key: \r\n", i+1); scanf("%d", &key); while(key > 15 || key < 0){ printf("%d\r\n", key); printf("Your input is out of range!\n\r"); printf("Input No.%d key: \r\n", i+1); scanf("%d", &key); } printf("%d\r\n", key); inData = inData + ((key & 0xf) << (4*i)); } SORTING_mWriteReg(XPAR_SORTING_0_S00_AXI_BASEADDR, 0, inData); SORTING_mWriteReg(XPAR_SORTING_0_S00_AXI_BASEADDR, 4, 1); outData = SORTING_mReadReg(XPAR_SORTING_0_S00_AXI_BASEADDR, 8); /*--------------------------OUTPUT--------------------------*/ printf("Sorted numbers are: \r\n"); for(i = 0; i < 8; i++) { output = ((outData >> (4*i)) & 0xf); printf("%d\r\n", output); } ``` 上方程式碼的第13行透過for loop將所有輸入的8筆4-bit資料全部存入inData,並將其透過第15行寫入slave_register_0,再透過第16行將input enable的訊號寫入slave_register_1。 第20行則是去讀取PL端輸出的資料,從slave_register_2讀取。 - **PL端(sort.v)**: 在LOAD狀態,將從PS端傳來的slv_reg0內的inData給一筆一筆存入至array中。 等待電路經過i=1至n-1次COMPARE,SWAP以及LAST的循環後,array將會被排序完成,而outData會一直將array的每一個元素給串接起來,直到FSM跑至DONE,outData結果才是正確的,PS屆時讀取slv_reg2的值才會是正確的輸出。 ```verilog= // --------------------- // // array // // --------------------- // always@(posedge clk) begin if(rstn == 1'b0) begin array[0] <= 4'd0; ... end else begin if(curState == `LOAD) begin case(index) 5'd0: array[index] <= inData[3:0]; 5'd1: array[index] <= inData[7:4]; ... endcase end else if(curState == `SWAP) array[j+5'd1] <= array[j]; else if(curState == `LAST) array[j+5'd1] <= key; else begin array[0] <= array[0]; ... end end end // --------------------- // // outData // // --------------------- // assign outData = {array[7], array[6], array[5], array[4], array[3], array[2], array[1], array[0]}; ``` ##### 運行流程 ![](https://i.imgur.com/CAqkXXg.png) 上方圖中輸入8筆資料先後由左到右依序為<3,15,1,4,14,6,0,9>,可以看到input顯示906e41f3,為將8筆資料存入同一個32-bit的u32暫存空間的結果,從LSB至MSB以16進制方式表示與輸入序列相吻合,代表輸入成功寫入slv_reg0。 #### Problem3-3 ##### AXI interface ![](https://i.imgur.com/xdiPxzF.png) >slv_reg0 -> type slv_reg1 -> inValid slv_reg2 -> inData slv_reg3 -> dataResponse slv_reg4 -> result slv_reg5 -> outValid ##### State Diagram ![](https://i.imgur.com/DOz6AT4.png) | state | 說明 | |:------:|:----------:| |NOP |閒置狀態,不進行任何操作,並等待inValid訊號。| |HANDLE|正在處理parity運算,並且在處理完成後拉高calcDone。| |DONE |將outValid設為1,並等待PS發回dataResponse訊號 **(確認已收到Output data)** 後,回到NOP state等待下一次操作。| ##### 設計邏輯 - **PS端(main.c)**: ```cpp= // pairty mode printf("Please choose pairty mode(1: odd, 2: even):\n\r"); scanf("%d", &type); while(type < 1 || type > 2){ ... } printf("%d\r\n", type); PARITYGENERATOR_mWriteReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 0, type); // input data printf("Please input data (Support number to 2147483647(2^31) at most):\n\r"); scanf("%d", &inData); printf("%d\r\n", inData); printf("Also equal to 0x%x\r\n", inData); PARITYGENERATOR_mWriteReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 4, inData); ``` 上方程式碼用於確認使用者的input是否在允許範圍內,並且將value寫入對應的AXI slave register存取的位置。 ```cpp= // inValid high PARITYGENERATOR_mWriteReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 8, 1); // Wait until the calculation is done while(PARITYGENERATOR_mReadReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 20) == 0){ ... if(PARITYGENERATOR_mReadReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 20) == 1){ // inValid low PARITYGENERATOR_mWriteReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 8, 0); } } if(PARITYGENERATOR_mReadReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 20) == 1){ // inValid low PARITYGENERATOR_mWriteReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 8, 0); } printf("Calculation is done!\r\n"); ``` 上方程式碼會將Processor hang在while迴圈直到確認ParityGenerator module已經做完運算(如果已經完成會發回outValid訊號)。 ```cpp= // ! Output switch (type) { case 1: printf("Odd pairty of 0x%x: %d\n", inData, PARITYGENERATOR_mReadReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 16)); break; case 2: printf("Even pairty of 0x%x: %d\n", inData, PARITYGENERATOR_mReadReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 16)); break; default: break; } // Told PL the data is received PARITYGENERATOR_mWriteReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 12, 1); printf("====================================\n"); // Reset for(int i=0;i<7;i++){ printf("Reset slave register %d: %d\n",i,PARITYGENERATOR_mReadReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 4*i)); PARITYGENERATOR_mWriteReg(XPAR_PARITYGENERATOR_0_S00_AXI_BASEADDR, 4*i, 0); } printf("====================================\n"); ``` 最後會將從PL得到的Output結果print出來,告知PL已經收到data(將dataResponse對應的slave register拉高),並且將AXI slave register的data進行重置,進行下一次操作。 - **PL端(ParityGenerator.v)**: ``` verilog= // Registers reg calcDone; reg calc_reg, result_reg; // Wires assign result = result_reg; assign outValid = (state == `DONE) ? 1'b1 : 1'b0; integer counter; ... // --------------------- // // outData // // --------------------- // always @(posedge clk) begin case (state) `NOP: begin calc_reg <= 32'd0; result_reg <= 32'd0; calcDone <= 1'b0; inData_part_reg <= 0; end `HANDLE: begin if(counter >= 31) begin calc_reg <= calc_reg; calcDone <= 1'b1; end else begin calc_reg <= calc_reg ^ inData[counter]; inData_part_reg <= inData[counter]; end end `DONE: begin if(type == 1) begin result_reg <= ~calc_reg; end else begin result_reg <= calc_reg; end calcDone <= 1'b1; end default: begin calc_reg <= 32'd0; result_reg <= 32'd0; calcDone <= 1'b0; end endcase end // --------------------- // // counter // // --------------------- // always @(posedge clk) begin if(state == `HANDLE) begin counter <= counter + 1; end else counter <= 0; end ``` `counter`和`calc_reg`為在`HANDLE`時主要作為運算的兩個register: - `counter`會在每個cycle遞增直到大於31。 - `calc_reg`在`NOP`會重置為0,並且在`HANDLE`時和input data對應counter的bit進行XOR運算,最後在`DONE`根據不同的parity type將值傳給`result_reg `進行output。 ### 完整運行結果 1. **透過ZYNQ Processor上運行的main.c選擇進行哪種運算** *(1: Arithmetic, 2: Sorting, 3: Parity Generator)* ![](https://i.imgur.com/mIKSBEe.png) 2. **Arithmetic**: - Check if mode is valid ![](https://i.imgur.com/Y8d3QUV.png) - Add result ![](https://i.imgur.com/VUE7b0k.png) - Sub result ![](https://i.imgur.com/xK8eHhK.png) - Mul result ![](https://i.imgur.com/Lrj0uzm.png) 3. **Sorting**: - Check if mode is valid ![](https://i.imgur.com/aeD74So.png) - result ![](https://i.imgur.com/UZhokJH.png) 4. **Parity Generator**: - Check if mode is valid ![](https://i.imgur.com/Abc5pnN.png) - result ![](https://i.imgur.com/GxGmsCH.png)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully